Merge tag 'mac80211-next-for-davem-2015-10-05' of git://git.kernel.org/pub/scm/linux...
authorDavid S. Miller <davem@davemloft.net>
Wed, 7 Oct 2015 11:29:18 +0000 (04:29 -0700)
committerDavid S. Miller <davem@davemloft.net>
Wed, 7 Oct 2015 11:29:18 +0000 (04:29 -0700)
Johannes Berg says:

====================
For the current cycle, we have the following right now:
 * many internal fixes, API improvements, cleanups, etc.
 * full AP client state tracking in cfg80211/mac80211 from Ayala
 * VHT support (in mac80211) for mesh
 * some A-MSDU in A-MPDU support from Emmanuel
 * show current TX power to userspace (from RafaƂ)
 * support for netlink dump in vendor commands (myself)
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
53 files changed:
drivers/net/wireless/ath/ath10k/mac.c
drivers/net/wireless/ath/ath9k/htc_drv_main.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/carl9170/main.c
drivers/net/wireless/ath/wcn36xx/main.c
drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
drivers/net/wireless/cw1200/sta.c
drivers/net/wireless/cw1200/sta.h
drivers/net/wireless/ipw2x00/libipw_rx.c
drivers/net/wireless/iwlegacy/4965-mac.c
drivers/net/wireless/iwlegacy/4965.h
drivers/net/wireless/iwlwifi/dvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/mediatek/mt7601u/main.c
drivers/net/wireless/mwl8k.c
drivers/net/wireless/rsi/rsi_91x_mac80211.c
drivers/net/wireless/rt2x00/rt2800lib.c
drivers/net/wireless/rt2x00/rt2800lib.h
drivers/net/wireless/rtlwifi/core.c
drivers/net/wireless/ti/wlcore/main.c
include/linux/ieee80211.h
include/net/cfg80211.h
include/net/mac80211.h
net/mac80211/agg-rx.c
net/mac80211/agg-tx.c
net/mac80211/cfg.c
net/mac80211/debugfs.c
net/mac80211/debugfs_key.c
net/mac80211/debugfs_netdev.c
net/mac80211/driver-ops.c
net/mac80211/driver-ops.h
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/main.c
net/mac80211/mesh.c
net/mac80211/mesh.h
net/mac80211/mesh_plink.c
net/mac80211/mlme.c
net/mac80211/offchannel.c
net/mac80211/pm.c
net/mac80211/rate.c
net/mac80211/rc80211_minstrel_debugfs.c
net/mac80211/rc80211_minstrel_ht_debugfs.c
net/mac80211/sta_info.h
net/mac80211/status.c
net/mac80211/tdls.c
net/mac80211/trace.h
net/mac80211/tx.c
net/mac80211/util.c
net/wireless/core.c
net/wireless/nl80211.c
net/wireless/reg.c

index 64674c9..b04e769 100644 (file)
@@ -6144,7 +6144,7 @@ static int ath10k_ampdu_action(struct ieee80211_hw *hw,
                               struct ieee80211_vif *vif,
                               enum ieee80211_ampdu_mlme_action action,
                               struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-                              u8 buf_size)
+                              u8 buf_size, bool amsdu)
 {
        struct ath10k *ar = hw->priv;
        struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
index 172a9ff..a680a97 100644 (file)
@@ -1659,7 +1659,7 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
                                  struct ieee80211_vif *vif,
                                  enum ieee80211_ampdu_mlme_action action,
                                  struct ieee80211_sta *sta,
-                                 u16 tid, u16 *ssn, u8 buf_size)
+                                 u16 tid, u16 *ssn, u8 buf_size, bool amsdu)
 {
        struct ath9k_htc_priv *priv = hw->priv;
        struct ath9k_htc_sta *ista;
index c27143b..323eb33 100644 (file)
@@ -1856,7 +1856,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
                              struct ieee80211_vif *vif,
                              enum ieee80211_ampdu_mlme_action action,
                              struct ieee80211_sta *sta,
-                             u16 tid, u16 *ssn, u8 buf_size)
+                             u16 tid, u16 *ssn, u8 buf_size, bool amsdu)
 {
        struct ath_softc *sc = hw->priv;
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
index 170c209..19d3d64 100644 (file)
@@ -1415,7 +1415,7 @@ static int carl9170_op_ampdu_action(struct ieee80211_hw *hw,
                                    struct ieee80211_vif *vif,
                                    enum ieee80211_ampdu_mlme_action action,
                                    struct ieee80211_sta *sta,
-                                   u16 tid, u16 *ssn, u8 buf_size)
+                                   u16 tid, u16 *ssn, u8 buf_size, bool amsdu)
 {
        struct ar9170 *ar = hw->priv;
        struct carl9170_sta_info *sta_info = (void *) sta->drv_priv;
index 900e72a..7c169ab 100644 (file)
@@ -859,7 +859,7 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw,
                    struct ieee80211_vif *vif,
                    enum ieee80211_ampdu_mlme_action action,
                    struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-                   u8 buf_size)
+                   u8 buf_size, bool amsdu)
 {
        struct wcn36xx *wcn = hw->priv;
        struct wcn36xx_sta *sta_priv = NULL;
index d2c5747..bec2dc1 100644 (file)
@@ -820,7 +820,7 @@ brcms_ops_ampdu_action(struct ieee80211_hw *hw,
                    struct ieee80211_vif *vif,
                    enum ieee80211_ampdu_mlme_action action,
                    struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-                   u8 buf_size)
+                   u8 buf_size, bool amsdu)
 {
        struct brcms_info *wl = hw->priv;
        struct scb *scb = &wl->wlc->pri_scb;
index b86500b..95a7fdb 100644 (file)
@@ -2137,7 +2137,7 @@ int cw1200_ampdu_action(struct ieee80211_hw *hw,
                        struct ieee80211_vif *vif,
                        enum ieee80211_ampdu_mlme_action action,
                        struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-                       u8 buf_size)
+                       u8 buf_size, bool amsdu)
 {
        /* Aggregation is implemented fully in firmware,
         * including block ack negotiation. Do not allow
index b7e386b..bebb337 100644 (file)
@@ -111,7 +111,7 @@ int cw1200_ampdu_action(struct ieee80211_hw *hw,
                        struct ieee80211_vif *vif,
                        enum ieee80211_ampdu_mlme_action action,
                        struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-                       u8 buf_size);
+                       u8 buf_size, bool amsdu);
 
 void cw1200_suspend_resume(struct cw1200_common *priv,
                          struct wsm_suspend_resume *arg);
index a6877dd..cef7f7d 100644 (file)
@@ -1091,8 +1091,6 @@ static const char *get_info_element_string(u16 id)
                MFIE_STRING(TIM);
                MFIE_STRING(IBSS_PARAMS);
                MFIE_STRING(COUNTRY);
-               MFIE_STRING(HP_PARAMS);
-               MFIE_STRING(HP_TABLE);
                MFIE_STRING(REQUEST);
                MFIE_STRING(CHALLENGE);
                MFIE_STRING(PWR_CONSTRAINT);
index 44fa422..6656215 100644 (file)
@@ -5984,7 +5984,7 @@ int
 il4965_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                        enum ieee80211_ampdu_mlme_action action,
                        struct ieee80211_sta *sta, u16 tid, u16 * ssn,
-                       u8 buf_size)
+                       u8 buf_size, bool amsdu)
 {
        struct il_priv *il = hw->priv;
        int ret = -EINVAL;
index 3a57f71..8ab8706 100644 (file)
@@ -184,7 +184,7 @@ void il4965_mac_update_tkip_key(struct ieee80211_hw *hw,
 int il4965_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                            enum ieee80211_ampdu_mlme_action action,
                            struct ieee80211_sta *sta, u16 tid, u16 * ssn,
-                           u8 buf_size);
+                           u8 buf_size, bool amsdu);
 int il4965_mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                       struct ieee80211_sta *sta);
 void
index 453f7c3..b3ad34e 100644 (file)
@@ -731,7 +731,7 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
                                   struct ieee80211_vif *vif,
                                   enum ieee80211_ampdu_mlme_action action,
                                   struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-                                  u8 buf_size)
+                                  u8 buf_size, bool amsdu)
 {
        struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
        int ret = -EINVAL;
index aa8c2b7..f70452c 100644 (file)
@@ -820,7 +820,7 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
                                    struct ieee80211_vif *vif,
                                    enum ieee80211_ampdu_mlme_action action,
                                    struct ieee80211_sta *sta, u16 tid,
-                                   u16 *ssn, u8 buf_size)
+                                   u16 *ssn, u8 buf_size, bool amsdu)
 {
        struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
        int ret;
index 66c963d..ee46f46 100644 (file)
@@ -1819,7 +1819,7 @@ static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw,
                                       struct ieee80211_vif *vif,
                                       enum ieee80211_ampdu_mlme_action action,
                                       struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-                                      u8 buf_size)
+                                      u8 buf_size, bool amsdu)
 {
        switch (action) {
        case IEEE80211_AMPDU_TX_START:
index 169384b..f715eee 100644 (file)
@@ -335,7 +335,8 @@ static int mt7601u_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
 static int
 mt76_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                  enum ieee80211_ampdu_mlme_action action,
-                 struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size)
+                 struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size,
+                 bool amsdu)
 {
        struct mt7601u_dev *dev = hw->priv;
        struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv;
index 9420fc6..30e3aaa 100644 (file)
@@ -5423,7 +5423,7 @@ static int
 mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                   enum ieee80211_ampdu_mlme_action action,
                   struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-                  u8 buf_size)
+                  u8 buf_size, bool amsdu)
 {
 
        int i, rc = 0;
index 7e80432..b5bcc93 100644 (file)
@@ -664,6 +664,7 @@ static int rsi_mac80211_set_key(struct ieee80211_hw *hw,
  * @tid: Traffic identifier.
  * @ssn: Pointer to ssn value.
  * @buf_size: Buffer size (for kernel version > 2.6.38).
+ * @amsdu: is AMSDU in AMPDU allowed
  *
  * Return: status: 0 on success, negative error code on failure.
  */
@@ -673,7 +674,8 @@ static int rsi_mac80211_ampdu_action(struct ieee80211_hw *hw,
                                     struct ieee80211_sta *sta,
                                     unsigned short tid,
                                     unsigned short *ssn,
-                                    unsigned char buf_size)
+                                    unsigned char buf_size,
+                                    bool amsdu)
 {
        int status = -EOPNOTSUPP;
        struct rsi_hw *adapter = hw->priv;
index 9524564..9733b31 100644 (file)
@@ -7937,7 +7937,7 @@ EXPORT_SYMBOL_GPL(rt2800_get_tsf);
 int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                        enum ieee80211_ampdu_mlme_action action,
                        struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-                       u8 buf_size)
+                       u8 buf_size, bool amsdu)
 {
        struct rt2x00_sta *sta_priv = (struct rt2x00_sta *)sta->drv_priv;
        int ret = 0;
index 1609b8a..440790b 100644 (file)
@@ -220,7 +220,7 @@ u64 rt2800_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
 int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                        enum ieee80211_ampdu_mlme_action action,
                        struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-                       u8 buf_size);
+                       u8 buf_size, bool amsdu);
 int rt2800_get_survey(struct ieee80211_hw *hw, int idx,
                      struct survey_info *survey);
 void rt2800_disable_wpdma(struct rt2x00_dev *rt2x00dev);
index 585d088..c925a4d 100644 (file)
@@ -1373,7 +1373,7 @@ static int rtl_op_ampdu_action(struct ieee80211_hw *hw,
                               struct ieee80211_vif *vif,
                               enum ieee80211_ampdu_mlme_action action,
                               struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-                              u8 buf_size)
+                              u8 buf_size, bool amsdu)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
 
index e819369..ec7f6af 100644 (file)
@@ -5263,7 +5263,7 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
                                  struct ieee80211_vif *vif,
                                  enum ieee80211_ampdu_mlme_action action,
                                  struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-                                 u8 buf_size)
+                                 u8 buf_size, bool amsdu)
 {
        struct wl1271 *wl = hw->priv;
        struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
index cfa906f..f79a02a 100644 (file)
@@ -1379,6 +1379,7 @@ struct ieee80211_ht_operation {
 
 
 /* block-ack parameters */
+#define IEEE80211_ADDBA_PARAM_AMSDU_MASK 0x0001
 #define IEEE80211_ADDBA_PARAM_POLICY_MASK 0x0002
 #define IEEE80211_ADDBA_PARAM_TID_MASK 0x003C
 #define IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK 0xFFC0
@@ -1745,8 +1746,7 @@ enum ieee80211_eid {
        WLAN_EID_TIM = 5,
        WLAN_EID_IBSS_PARAMS = 6,
        WLAN_EID_COUNTRY = 7,
-       WLAN_EID_HP_PARAMS = 8,
-       WLAN_EID_HP_TABLE = 9,
+       /* 8, 9 reserved */
        WLAN_EID_REQUEST = 10,
        WLAN_EID_QBSS_LOAD = 11,
        WLAN_EID_EDCA_PARAM_SET = 12,
index f0889a2..90332a1 100644 (file)
@@ -858,6 +858,8 @@ struct station_del_parameters {
 /**
  * enum cfg80211_station_type - the type of station being modified
  * @CFG80211_STA_AP_CLIENT: client of an AP interface
+ * @CFG80211_STA_AP_CLIENT_UNASSOC: client of an AP interface that is still
+ *     unassociated (update properties for this type of client is permitted)
  * @CFG80211_STA_AP_MLME_CLIENT: client of an AP interface that has
  *     the AP MLME in the device
  * @CFG80211_STA_AP_STA: AP station on managed interface
@@ -873,6 +875,7 @@ struct station_del_parameters {
  */
 enum cfg80211_station_type {
        CFG80211_STA_AP_CLIENT,
+       CFG80211_STA_AP_CLIENT_UNASSOC,
        CFG80211_STA_AP_MLME_CLIENT,
        CFG80211_STA_AP_STA,
        CFG80211_STA_IBSS,
@@ -2971,12 +2974,21 @@ enum wiphy_vendor_command_flags {
  * @doit: callback for the operation, note that wdev is %NULL if the
  *     flags didn't ask for a wdev and non-%NULL otherwise; the data
  *     pointer may be %NULL if userspace provided no data at all
+ * @dumpit: dump callback, for transferring bigger/multiple items. The
+ *     @storage points to cb->args[5], ie. is preserved over the multiple
+ *     dumpit calls.
+ * It's recommended to not have the same sub command with both @doit and
+ * @dumpit, so that userspace can assume certain ones are get and others
+ * are used with dump requests.
  */
 struct wiphy_vendor_command {
        struct nl80211_vendor_cmd_info info;
        u32 flags;
        int (*doit)(struct wiphy *wiphy, struct wireless_dev *wdev,
                    const void *data, int data_len);
+       int (*dumpit)(struct wiphy *wiphy, struct wireless_dev *wdev,
+                     struct sk_buff *skb, const void *data, int data_len,
+                     unsigned long *storage);
 };
 
 /**
index bfc5694..4ec6fed 100644 (file)
@@ -5,6 +5,7 @@
  * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
  * Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2013-2014  Intel Mobile Communications GmbH
+ * Copyright (C) 2015 Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -1360,6 +1361,8 @@ enum ieee80211_vif_flags {
  * @debugfs_dir: debugfs dentry, can be used by drivers to create own per
  *     interface debug files. Note that it will be NULL for the virtual
  *     monitor interface (if that is requested.)
+ * @probe_req_reg: probe requests should be reported to mac80211 for this
+ *     interface.
  * @drv_priv: data area for driver use, will always be aligned to
  *     sizeof(void *).
  * @txq: the multicast data TX queue (if driver uses the TXQ abstraction)
@@ -1384,6 +1387,8 @@ struct ieee80211_vif {
        struct dentry *debugfs_dir;
 #endif
 
+       unsigned int probe_req_reg;
+
        /* must be last */
        u8 drv_priv[0] __aligned(sizeof(void *));
 };
@@ -1494,10 +1499,8 @@ enum ieee80211_key_flags {
  *     - Temporal Authenticator Rx MIC Key (64 bits)
  * @icv_len: The ICV length for this key type
  * @iv_len: The IV length for this key type
- * @drv_priv: pointer for driver use
  */
 struct ieee80211_key_conf {
-       void *drv_priv;
        atomic64_t tx_pn;
        u32 cipher;
        u8 icv_len;
@@ -1894,6 +1897,12 @@ struct ieee80211_txq {
  * @IEEE80211_HW_TDLS_WIDER_BW: The device/driver supports wider bandwidth
  *     than then BSS bandwidth for a TDLS link on the base channel.
  *
+ * @IEEE80211_HW_SUPPORTS_AMSDU_IN_AMPDU: The driver supports receiving A-MSDUs
+ *     within A-MPDU.
+ *
+ * @IEEE80211_HW_BEACON_TX_STATUS: The device/driver provides TX status
+ *     for sent beacons.
+ *
  * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
  */
 enum ieee80211_hw_flags {
@@ -1927,6 +1936,8 @@ enum ieee80211_hw_flags {
        IEEE80211_HW_SUPPORTS_CLONED_SKBS,
        IEEE80211_HW_SINGLE_SCAN_ON_ALL_BANDS,
        IEEE80211_HW_TDLS_WIDER_BW,
+       IEEE80211_HW_SUPPORTS_AMSDU_IN_AMPDU,
+       IEEE80211_HW_BEACON_TX_STATUS,
 
        /* keep last, obviously */
        NUM_IEEE80211_HW_FLAGS
@@ -2827,6 +2838,13 @@ enum ieee80211_reconfig_type {
  *     See the section "Frame filtering" for more information.
  *     This callback must be implemented and can sleep.
  *
+ * @config_iface_filter: Configure the interface's RX filter.
+ *     This callback is optional and is used to configure which frames
+ *     should be passed to mac80211. The filter_flags is the combination
+ *     of FIF_* flags. The changed_flags is a bit mask that indicates
+ *     which flags are changed.
+ *     This callback can sleep.
+ *
  * @set_tim: Set TIM bit. mac80211 calls this function when a TIM bit
  *     must be set or cleared for a given STA. Must be atomic.
  *
@@ -3016,6 +3034,9 @@ enum ieee80211_reconfig_type {
  *     buffer size of 8. Correct ways to retransmit #1 would be:
  *      - TX:       1 or 18 or 81
  *     Even "189" would be wrong since 1 could be lost again.
+ *     The @amsdu parameter is valid when the action is set to
+ *     %IEEE80211_AMPDU_TX_OPERATIONAL and indicates the peer's ability
+ *     to receive A-MSDU within A-MPDU.
  *
  *     Returns a negative error code on failure.
  *     The callback can sleep.
@@ -3266,6 +3287,10 @@ struct ieee80211_ops {
                                 unsigned int changed_flags,
                                 unsigned int *total_flags,
                                 u64 multicast);
+       void (*config_iface_filter)(struct ieee80211_hw *hw,
+                                   struct ieee80211_vif *vif,
+                                   unsigned int filter_flags,
+                                   unsigned int changed_flags);
        int (*set_tim)(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
                       bool set);
        int (*set_key)(struct ieee80211_hw *hw, enum set_key_cmd cmd,
@@ -3349,7 +3374,7 @@ struct ieee80211_ops {
                            struct ieee80211_vif *vif,
                            enum ieee80211_ampdu_mlme_action action,
                            struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-                           u8 buf_size);
+                           u8 buf_size, bool amsdu);
        int (*get_survey)(struct ieee80211_hw *hw, int idx,
                struct survey_info *survey);
        void (*rfkill_poll)(struct ieee80211_hw *hw);
index 5c564a6..10ad4ac 100644 (file)
@@ -79,7 +79,7 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
               (int)reason);
 
        if (drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_STOP,
-                            &sta->sta, tid, NULL, 0))
+                            &sta->sta, tid, NULL, 0, false))
                sdata_info(sta->sdata,
                           "HW problem - can not stop rx aggregation for %pM tid %d\n",
                           sta->sta.addr, tid);
@@ -189,6 +189,7 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d
        struct ieee80211_local *local = sdata->local;
        struct sk_buff *skb;
        struct ieee80211_mgmt *mgmt;
+       bool amsdu = ieee80211_hw_check(&local->hw, SUPPORTS_AMSDU_IN_AMPDU);
        u16 capab;
 
        skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
@@ -217,7 +218,8 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d
        mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP;
        mgmt->u.action.u.addba_resp.dialog_token = dialog_token;
 
-       capab = (u16)(policy << 1);     /* bit 1 aggregation policy */
+       capab = (u16)(amsdu << 0);      /* bit 0 A-MSDU support */
+       capab |= (u16)(policy << 1);    /* bit 1 aggregation policy */
        capab |= (u16)(tid << 2);       /* bit 5:2 TID number */
        capab |= (u16)(buf_size << 6);  /* bit 15:6 max size of aggregation */
 
@@ -321,7 +323,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
                __skb_queue_head_init(&tid_agg_rx->reorder_buf[i]);
 
        ret = drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_START,
-                              &sta->sta, tid, &start_seq_num, 0);
+                              &sta->sta, tid, &start_seq_num, 0, false);
        ht_dbg(sta->sdata, "Rx A-MPDU request on %pM tid %d result %d\n",
               sta->sta.addr, tid, ret);
        if (ret) {
index c8ba2e7..a758eb8 100644 (file)
@@ -97,7 +97,8 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
        mgmt->u.action.u.addba_req.action_code = WLAN_ACTION_ADDBA_REQ;
 
        mgmt->u.action.u.addba_req.dialog_token = dialog_token;
-       capab = (u16)(1 << 1);          /* bit 1 aggregation policy */
+       capab = (u16)(1 << 0);          /* bit 0 A-MSDU support */
+       capab |= (u16)(1 << 1);         /* bit 1 aggregation policy */
        capab |= (u16)(tid << 2);       /* bit 5:2 TID number */
        capab |= (u16)(agg_size << 6);  /* bit 15:6 max size of aggergation */
 
@@ -331,7 +332,7 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
                        return -EALREADY;
                ret = drv_ampdu_action(local, sta->sdata,
                                       IEEE80211_AMPDU_TX_STOP_FLUSH_CONT,
-                                      &sta->sta, tid, NULL, 0);
+                                      &sta->sta, tid, NULL, 0, false);
                WARN_ON_ONCE(ret);
                return 0;
        }
@@ -381,7 +382,7 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
        tid_tx->tx_stop = reason == AGG_STOP_LOCAL_REQUEST;
 
        ret = drv_ampdu_action(local, sta->sdata, action,
-                              &sta->sta, tid, NULL, 0);
+                              &sta->sta, tid, NULL, 0, false);
 
        /* HW shall not deny going back to legacy */
        if (WARN_ON(ret)) {
@@ -469,7 +470,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
        start_seq_num = sta->tid_seq[tid] >> 4;
 
        ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START,
-                              &sta->sta, tid, &start_seq_num, 0);
+                              &sta->sta, tid, &start_seq_num, 0, false);
        if (ret) {
                ht_dbg(sdata,
                       "BA request denied - HW unavailable for %pM tid %d\n",
@@ -693,7 +694,8 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
 
        drv_ampdu_action(local, sta->sdata,
                         IEEE80211_AMPDU_TX_OPERATIONAL,
-                        &sta->sta, tid, NULL, tid_tx->buf_size);
+                        &sta->sta, tid, NULL, tid_tx->buf_size,
+                        tid_tx->amsdu);
 
        /*
         * synchronize with TX path, while splicing the TX path
@@ -918,8 +920,10 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
        struct tid_ampdu_tx *tid_tx;
        u16 capab, tid;
        u8 buf_size;
+       bool amsdu;
 
        capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
+       amsdu = capab & IEEE80211_ADDBA_PARAM_AMSDU_MASK;
        tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
        buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6;
 
@@ -968,6 +972,7 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
                }
 
                tid_tx->buf_size = buf_size;
+               tid_tx->amsdu = amsdu;
 
                if (test_bit(HT_AGG_STATE_DRV_READY, &tid_tx->state))
                        ieee80211_agg_tx_operational(local, sta, tid);
index 7a77a14..68e551e 100644 (file)
@@ -981,7 +981,7 @@ static int sta_apply_auth_flags(struct ieee80211_local *local,
                 * well. Some drivers require rate control initialized
                 * before drv_sta_state() is called.
                 */
-               if (test_sta_flag(sta, WLAN_STA_TDLS_PEER))
+               if (!test_sta_flag(sta, WLAN_STA_RATE_CONTROL))
                        rate_control_rate_init(sta);
 
                ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
@@ -1120,8 +1120,11 @@ static int sta_apply_parameters(struct ieee80211_local *local,
            local->hw.queues >= IEEE80211_NUM_ACS)
                sta->sta.wme = set & BIT(NL80211_STA_FLAG_WME);
 
-       /* auth flags will be set later for TDLS stations */
-       if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER)) {
+       /* auth flags will be set later for TDLS,
+        * and for unassociated stations that move to assocaited */
+       if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER) &&
+           !((mask & BIT(NL80211_STA_FLAG_ASSOCIATED)) &&
+             (set & BIT(NL80211_STA_FLAG_ASSOCIATED)))) {
                ret = sta_apply_auth_flags(local, sta, mask, set);
                if (ret)
                        return ret;
@@ -1156,6 +1159,7 @@ static int sta_apply_parameters(struct ieee80211_local *local,
                set_sta_flag(sta, WLAN_STA_TDLS_CHAN_SWITCH);
 
        if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) &&
+           !sdata->u.mgd.tdls_wider_bw_prohibited &&
            ieee80211_hw_check(&local->hw, TDLS_WIDER_BW) &&
            params->ext_capab_len >= 8 &&
            params->ext_capab[7] & WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED)
@@ -1212,7 +1216,8 @@ static int sta_apply_parameters(struct ieee80211_local *local,
                sta_apply_mesh_params(local, sta, params);
 
        /* set the STA state after all sta info from usermode has been set */
-       if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) {
+       if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) ||
+           set & BIT(NL80211_STA_FLAG_ASSOCIATED)) {
                ret = sta_apply_auth_flags(local, sta, mask, set);
                if (ret)
                        return ret;
@@ -1254,12 +1259,14 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
         * defaults -- if userspace wants something else we'll
         * change it accordingly in sta_apply_parameters()
         */
-       if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) {
+       if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) &&
+           !(params->sta_flags_set & (BIT(NL80211_STA_FLAG_AUTHENTICATED) |
+                                       BIT(NL80211_STA_FLAG_ASSOCIATED)))) {
                sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
                sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
-       } else {
-               sta->sta.tdls = true;
        }
+       if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))
+               sta->sta.tdls = true;
 
        err = sta_apply_parameters(local, sta, params);
        if (err) {
@@ -1268,10 +1275,12 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
        }
 
        /*
-        * for TDLS, rate control should be initialized only when
-        * rates are known and station is marked authorized
+        * for TDLS and for unassociated station, rate control should be
+        * initialized only when rates are known and station is marked
+        * authorized/associated
         */
-       if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER))
+       if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER) &&
+           test_sta_flag(sta, WLAN_STA_ASSOC))
                rate_control_rate_init(sta);
 
        layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
@@ -1346,7 +1355,10 @@ static int ieee80211_change_station(struct wiphy *wiphy,
                break;
        case NL80211_IFTYPE_AP:
        case NL80211_IFTYPE_AP_VLAN:
-               statype = CFG80211_STA_AP_CLIENT;
+               if (test_sta_flag(sta, WLAN_STA_ASSOC))
+                       statype = CFG80211_STA_AP_CLIENT;
+               else
+                       statype = CFG80211_STA_AP_CLIENT_UNASSOC;
                break;
        default:
                err = -EOPNOTSUPP;
@@ -3522,18 +3534,32 @@ static void ieee80211_mgmt_frame_register(struct wiphy *wiphy,
                                          u16 frame_type, bool reg)
 {
        struct ieee80211_local *local = wiphy_priv(wiphy);
+       struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
 
        switch (frame_type) {
        case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ:
-               if (reg)
+               if (reg) {
                        local->probe_req_reg++;
-               else
-                       local->probe_req_reg--;
+                       sdata->vif.probe_req_reg++;
+               } else {
+                       if (local->probe_req_reg)
+                               local->probe_req_reg--;
+
+                       if (sdata->vif.probe_req_reg)
+                               sdata->vif.probe_req_reg--;
+               }
 
                if (!local->open_count)
                        break;
 
-               ieee80211_queue_work(&local->hw, &local->reconfig_filter);
+               if (sdata->vif.probe_req_reg == 1)
+                       drv_config_iface_filter(local, sdata, FIF_PROBE_REQ,
+                                               FIF_PROBE_REQ);
+               else if (sdata->vif.probe_req_reg == 0)
+                       drv_config_iface_filter(local, sdata, 0,
+                                               FIF_PROBE_REQ);
+
+               ieee80211_configure_filter(local);
                break;
        default:
                break;
index ced6bf3..3636b45 100644 (file)
@@ -123,6 +123,8 @@ static const char *hw_flag_names[NUM_IEEE80211_HW_FLAGS + 1] = {
        FLAG(SUPPORTS_CLONED_SKBS),
        FLAG(SINGLE_SCAN_ON_ALL_BANDS),
        FLAG(TDLS_WIDER_BW),
+       FLAG(SUPPORTS_AMSDU_IN_AMPDU),
+       FLAG(BEACON_TX_STATUS),
 
        /* keep last for the build bug below */
        (void *)0x1
index 702ca12..7961e7d 100644 (file)
@@ -2,6 +2,7 @@
  * Copyright 2003-2005 Devicescape Software, Inc.
  * Copyright (c) 2006  Jiri Benc <jbenc@suse.cz>
  * Copyright 2007      Johannes Berg <johannes@sipsolutions.net>
+ * Copyright (C) 2015  Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -34,6 +35,14 @@ static const struct file_operations key_ ##name## _ops = {           \
        .llseek = generic_file_llseek,                                  \
 }
 
+#define KEY_OPS_W(name)                                                        \
+static const struct file_operations key_ ##name## _ops = {             \
+       .read = key_##name##_read,                                      \
+       .write = key_##name##_write,                                    \
+       .open = simple_open,                                            \
+       .llseek = generic_file_llseek,                                  \
+}
+
 #define KEY_FILE(name, format)                                         \
                 KEY_READ_##format(name)                                \
                 KEY_OPS(name)
@@ -74,6 +83,41 @@ static ssize_t key_algorithm_read(struct file *file,
 }
 KEY_OPS(algorithm);
 
+static ssize_t key_tx_spec_write(struct file *file, const char __user *userbuf,
+                                size_t count, loff_t *ppos)
+{
+       struct ieee80211_key *key = file->private_data;
+       u64 pn;
+       int ret;
+
+       switch (key->conf.cipher) {
+       case WLAN_CIPHER_SUITE_WEP40:
+       case WLAN_CIPHER_SUITE_WEP104:
+               return -EINVAL;
+       case WLAN_CIPHER_SUITE_TKIP:
+               /* not supported yet */
+               return -EOPNOTSUPP;
+       case WLAN_CIPHER_SUITE_CCMP:
+       case WLAN_CIPHER_SUITE_CCMP_256:
+       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:
+       case WLAN_CIPHER_SUITE_GCMP:
+       case WLAN_CIPHER_SUITE_GCMP_256:
+               ret = kstrtou64_from_user(userbuf, count, 16, &pn);
+               if (ret)
+                       return ret;
+               /* PN is a 48-bit counter */
+               if (pn >= (1ULL << 48))
+                       return -ERANGE;
+               atomic64_set(&key->conf.tx_pn, pn);
+               return count;
+       default:
+               return 0;
+       }
+}
+
 static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf,
                                size_t count, loff_t *ppos)
 {
@@ -110,7 +154,7 @@ static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf,
        }
        return simple_read_from_buffer(userbuf, count, ppos, buf, len);
 }
-KEY_OPS(tx_spec);
+KEY_OPS_W(tx_spec);
 
 static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf,
                                size_t count, loff_t *ppos)
@@ -278,6 +322,9 @@ KEY_OPS(key);
 #define DEBUGFS_ADD(name) \
        debugfs_create_file(#name, 0400, key->debugfs.dir, \
                            key, &key_##name##_ops);
+#define DEBUGFS_ADD_W(name) \
+       debugfs_create_file(#name, 0600, key->debugfs.dir, \
+                           key, &key_##name##_ops);
 
 void ieee80211_debugfs_key_add(struct ieee80211_key *key)
 {
@@ -310,7 +357,7 @@ void ieee80211_debugfs_key_add(struct ieee80211_key *key)
        DEBUGFS_ADD(keyidx);
        DEBUGFS_ADD(hw_key_idx);
        DEBUGFS_ADD(algorithm);
-       DEBUGFS_ADD(tx_spec);
+       DEBUGFS_ADD_W(tx_spec);
        DEBUGFS_ADD(rx_spec);
        DEBUGFS_ADD(replays);
        DEBUGFS_ADD(icverrors);
index 1021e87..37ea30e 100644 (file)
@@ -114,14 +114,6 @@ static ssize_t ieee80211_if_fmt_##name(                                    \
        return scnprintf(buf, buflen, "%pM\n", sdata->field);           \
 }
 
-#define IEEE80211_IF_FMT_DEC_DIV_16(name, field)                       \
-static ssize_t ieee80211_if_fmt_##name(                                        \
-       const struct ieee80211_sub_if_data *sdata,                      \
-       char *buf, int buflen)                                          \
-{                                                                      \
-       return scnprintf(buf, buflen, "%d\n", sdata->field / 16);       \
-}
-
 #define IEEE80211_IF_FMT_JIFFIES_TO_MS(name, field)                    \
 static ssize_t ieee80211_if_fmt_##name(                                        \
        const struct ieee80211_sub_if_data *sdata,                      \
@@ -247,8 +239,6 @@ IEEE80211_IF_FILE_R(hw_queues);
 /* STA attributes */
 IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC);
 IEEE80211_IF_FILE(aid, u.mgd.aid, DEC);
-IEEE80211_IF_FILE(last_beacon, u.mgd.last_beacon_signal, DEC);
-IEEE80211_IF_FILE(ave_beacon, u.mgd.ave_beacon_signal, DEC_DIV_16);
 IEEE80211_IF_FILE(beacon_timeout, u.mgd.beacon_timeout, JIFFIES_TO_MS);
 
 static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata,
@@ -455,6 +445,34 @@ static ssize_t ieee80211_if_parse_uapsd_max_sp_len(
 }
 IEEE80211_IF_FILE_RW(uapsd_max_sp_len);
 
+static ssize_t ieee80211_if_fmt_tdls_wider_bw(
+       const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
+{
+       const struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+       bool tdls_wider_bw;
+
+       tdls_wider_bw = ieee80211_hw_check(&sdata->local->hw, TDLS_WIDER_BW) &&
+                       !ifmgd->tdls_wider_bw_prohibited;
+
+       return snprintf(buf, buflen, "%d\n", tdls_wider_bw);
+}
+
+static ssize_t ieee80211_if_parse_tdls_wider_bw(
+       struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
+{
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+       u8 val;
+       int ret;
+
+       ret = kstrtou8(buf, 0, &val);
+       if (ret)
+               return ret;
+
+       ifmgd->tdls_wider_bw_prohibited = !val;
+       return buflen;
+}
+IEEE80211_IF_FILE_RW(tdls_wider_bw);
+
 /* AP attributes */
 IEEE80211_IF_FILE(num_mcast_sta, u.ap.num_mcast_sta, ATOMIC);
 IEEE80211_IF_FILE(num_sta_ps, u.ap.ps.num_sta_ps, ATOMIC);
@@ -606,14 +624,13 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
 {
        DEBUGFS_ADD(bssid);
        DEBUGFS_ADD(aid);
-       DEBUGFS_ADD(last_beacon);
-       DEBUGFS_ADD(ave_beacon);
        DEBUGFS_ADD(beacon_timeout);
        DEBUGFS_ADD_MODE(smps, 0600);
        DEBUGFS_ADD_MODE(tkip_mic_test, 0200);
        DEBUGFS_ADD_MODE(beacon_loss, 0200);
        DEBUGFS_ADD_MODE(uapsd_queues, 0600);
        DEBUGFS_ADD_MODE(uapsd_max_sp_len, 0600);
+       DEBUGFS_ADD_MODE(tdls_wider_bw, 0600);
 }
 
 static void add_ap_files(struct ieee80211_sub_if_data *sdata)
index 267c3b1..a1d5431 100644 (file)
@@ -8,6 +8,60 @@
 #include "trace.h"
 #include "driver-ops.h"
 
+int drv_add_interface(struct ieee80211_local *local,
+                     struct ieee80211_sub_if_data *sdata)
+{
+       int ret;
+
+       might_sleep();
+
+       if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
+                   (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
+                    !ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF) &&
+                    !(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))))
+               return -EINVAL;
+
+       trace_drv_add_interface(local, sdata);
+       ret = local->ops->add_interface(&local->hw, &sdata->vif);
+       trace_drv_return_int(local, ret);
+
+       if (ret == 0)
+               sdata->flags |= IEEE80211_SDATA_IN_DRIVER;
+
+       return ret;
+}
+
+int drv_change_interface(struct ieee80211_local *local,
+                        struct ieee80211_sub_if_data *sdata,
+                        enum nl80211_iftype type, bool p2p)
+{
+       int ret;
+
+       might_sleep();
+
+       if (!check_sdata_in_driver(sdata))
+               return -EIO;
+
+       trace_drv_change_interface(local, sdata, type, p2p);
+       ret = local->ops->change_interface(&local->hw, &sdata->vif, type, p2p);
+       trace_drv_return_int(local, ret);
+       return ret;
+}
+
+void drv_remove_interface(struct ieee80211_local *local,
+                         struct ieee80211_sub_if_data *sdata)
+{
+       might_sleep();
+
+       if (!check_sdata_in_driver(sdata))
+               return;
+
+       trace_drv_remove_interface(local, sdata);
+       local->ops->remove_interface(&local->hw, &sdata->vif);
+       sdata->flags &= ~IEEE80211_SDATA_IN_DRIVER;
+       trace_drv_return_void(local);
+}
+
 __must_check
 int drv_sta_state(struct ieee80211_local *local,
                  struct ieee80211_sub_if_data *sdata,
@@ -39,3 +93,171 @@ int drv_sta_state(struct ieee80211_local *local,
        trace_drv_return_int(local, ret);
        return ret;
 }
+
+void drv_sta_rc_update(struct ieee80211_local *local,
+                      struct ieee80211_sub_if_data *sdata,
+                      struct ieee80211_sta *sta, u32 changed)
+{
+       sdata = get_bss_sdata(sdata);
+       if (!check_sdata_in_driver(sdata))
+               return;
+
+       WARN_ON(changed & IEEE80211_RC_SUPP_RATES_CHANGED &&
+               (sdata->vif.type != NL80211_IFTYPE_ADHOC &&
+                sdata->vif.type != NL80211_IFTYPE_MESH_POINT));
+
+       trace_drv_sta_rc_update(local, sdata, sta, changed);
+       if (local->ops->sta_rc_update)
+               local->ops->sta_rc_update(&local->hw, &sdata->vif,
+                                         sta, changed);
+
+       trace_drv_return_void(local);
+}
+
+int drv_conf_tx(struct ieee80211_local *local,
+               struct ieee80211_sub_if_data *sdata, u16 ac,
+               const struct ieee80211_tx_queue_params *params)
+{
+       int ret = -EOPNOTSUPP;
+
+       might_sleep();
+
+       if (!check_sdata_in_driver(sdata))
+               return -EIO;
+
+       if (WARN_ONCE(params->cw_min == 0 ||
+                     params->cw_min > params->cw_max,
+                     "%s: invalid CW_min/CW_max: %d/%d\n",
+                     sdata->name, params->cw_min, params->cw_max))
+               return -EINVAL;
+
+       trace_drv_conf_tx(local, sdata, ac, params);
+       if (local->ops->conf_tx)
+               ret = local->ops->conf_tx(&local->hw, &sdata->vif,
+                                         ac, params);
+       trace_drv_return_int(local, ret);
+       return ret;
+}
+
+u64 drv_get_tsf(struct ieee80211_local *local,
+               struct ieee80211_sub_if_data *sdata)
+{
+       u64 ret = -1ULL;
+
+       might_sleep();
+
+       if (!check_sdata_in_driver(sdata))
+               return ret;
+
+       trace_drv_get_tsf(local, sdata);
+       if (local->ops->get_tsf)
+               ret = local->ops->get_tsf(&local->hw, &sdata->vif);
+       trace_drv_return_u64(local, ret);
+       return ret;
+}
+
+void drv_set_tsf(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
+                u64 tsf)
+{
+       might_sleep();
+
+       if (!check_sdata_in_driver(sdata))
+               return;
+
+       trace_drv_set_tsf(local, sdata, tsf);
+       if (local->ops->set_tsf)
+               local->ops->set_tsf(&local->hw, &sdata->vif, tsf);
+       trace_drv_return_void(local);
+}
+
+void drv_reset_tsf(struct ieee80211_local *local,
+                  struct ieee80211_sub_if_data *sdata)
+{
+       might_sleep();
+
+       if (!check_sdata_in_driver(sdata))
+               return;
+
+       trace_drv_reset_tsf(local, sdata);
+       if (local->ops->reset_tsf)
+               local->ops->reset_tsf(&local->hw, &sdata->vif);
+       trace_drv_return_void(local);
+}
+
+int drv_switch_vif_chanctx(struct ieee80211_local *local,
+                          struct ieee80211_vif_chanctx_switch *vifs,
+                          int n_vifs, enum ieee80211_chanctx_switch_mode mode)
+{
+       int ret = 0;
+       int i;
+
+       if (!local->ops->switch_vif_chanctx)
+               return -EOPNOTSUPP;
+
+       for (i = 0; i < n_vifs; i++) {
+               struct ieee80211_chanctx *new_ctx =
+                       container_of(vifs[i].new_ctx,
+                                    struct ieee80211_chanctx,
+                                    conf);
+               struct ieee80211_chanctx *old_ctx =
+                       container_of(vifs[i].old_ctx,
+                                    struct ieee80211_chanctx,
+                                    conf);
+
+               WARN_ON_ONCE(!old_ctx->driver_present);
+               WARN_ON_ONCE((mode == CHANCTX_SWMODE_SWAP_CONTEXTS &&
+                             new_ctx->driver_present) ||
+                            (mode == CHANCTX_SWMODE_REASSIGN_VIF &&
+                             !new_ctx->driver_present));
+       }
+
+       trace_drv_switch_vif_chanctx(local, vifs, n_vifs, mode);
+       ret = local->ops->switch_vif_chanctx(&local->hw,
+                                            vifs, n_vifs, mode);
+       trace_drv_return_int(local, ret);
+
+       if (!ret && mode == CHANCTX_SWMODE_SWAP_CONTEXTS) {
+               for (i = 0; i < n_vifs; i++) {
+                       struct ieee80211_chanctx *new_ctx =
+                               container_of(vifs[i].new_ctx,
+                                            struct ieee80211_chanctx,
+                                            conf);
+                       struct ieee80211_chanctx *old_ctx =
+                               container_of(vifs[i].old_ctx,
+                                            struct ieee80211_chanctx,
+                                            conf);
+
+                       new_ctx->driver_present = true;
+                       old_ctx->driver_present = false;
+               }
+       }
+
+       return ret;
+}
+
+int drv_ampdu_action(struct ieee80211_local *local,
+                    struct ieee80211_sub_if_data *sdata,
+                    enum ieee80211_ampdu_mlme_action action,
+                    struct ieee80211_sta *sta, u16 tid,
+                    u16 *ssn, u8 buf_size, bool amsdu)
+{
+       int ret = -EOPNOTSUPP;
+
+       might_sleep();
+
+       sdata = get_bss_sdata(sdata);
+       if (!check_sdata_in_driver(sdata))
+               return -EIO;
+
+       trace_drv_ampdu_action(local, sdata, action, sta, tid,
+                              ssn, buf_size, amsdu);
+
+       if (local->ops->ampdu_action)
+               ret = local->ops->ampdu_action(&local->hw, &sdata->vif, action,
+                                              sta, tid, ssn, buf_size, amsdu);
+
+       trace_drv_return_int(local, ret);
+
+       return ret;
+}
index 02d9133..3098709 100644 (file)
@@ -137,59 +137,15 @@ static inline void drv_set_wakeup(struct ieee80211_local *local,
 }
 #endif
 
-static inline int drv_add_interface(struct ieee80211_local *local,
-                                   struct ieee80211_sub_if_data *sdata)
-{
-       int ret;
-
-       might_sleep();
-
-       if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
-                   (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
-                    !ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF) &&
-                    !(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))))
-               return -EINVAL;
-
-       trace_drv_add_interface(local, sdata);
-       ret = local->ops->add_interface(&local->hw, &sdata->vif);
-       trace_drv_return_int(local, ret);
-
-       if (ret == 0)
-               sdata->flags |= IEEE80211_SDATA_IN_DRIVER;
-
-       return ret;
-}
-
-static inline int drv_change_interface(struct ieee80211_local *local,
-                                      struct ieee80211_sub_if_data *sdata,
-                                      enum nl80211_iftype type, bool p2p)
-{
-       int ret;
+int drv_add_interface(struct ieee80211_local *local,
+                     struct ieee80211_sub_if_data *sdata);
 
-       might_sleep();
-
-       if (!check_sdata_in_driver(sdata))
-               return -EIO;
-
-       trace_drv_change_interface(local, sdata, type, p2p);
-       ret = local->ops->change_interface(&local->hw, &sdata->vif, type, p2p);
-       trace_drv_return_int(local, ret);
-       return ret;
-}
-
-static inline void drv_remove_interface(struct ieee80211_local *local,
-                                       struct ieee80211_sub_if_data *sdata)
-{
-       might_sleep();
-
-       if (!check_sdata_in_driver(sdata))
-               return;
+int drv_change_interface(struct ieee80211_local *local,
+                        struct ieee80211_sub_if_data *sdata,
+                        enum nl80211_iftype type, bool p2p);
 
-       trace_drv_remove_interface(local, sdata);
-       local->ops->remove_interface(&local->hw, &sdata->vif);
-       sdata->flags &= ~IEEE80211_SDATA_IN_DRIVER;
-       trace_drv_return_void(local);
-}
+void drv_remove_interface(struct ieee80211_local *local,
+                         struct ieee80211_sub_if_data *sdata);
 
 static inline int drv_config(struct ieee80211_local *local, u32 changed)
 {
@@ -260,6 +216,22 @@ static inline void drv_configure_filter(struct ieee80211_local *local,
        trace_drv_return_void(local);
 }
 
+static inline void drv_config_iface_filter(struct ieee80211_local *local,
+                                          struct ieee80211_sub_if_data *sdata,
+                                          unsigned int filter_flags,
+                                          unsigned int changed_flags)
+{
+       might_sleep();
+
+       trace_drv_config_iface_filter(local, sdata, filter_flags,
+                                     changed_flags);
+       if (local->ops->config_iface_filter)
+               local->ops->config_iface_filter(&local->hw, &sdata->vif,
+                                               filter_flags,
+                                               changed_flags);
+       trace_drv_return_void(local);
+}
+
 static inline int drv_set_tim(struct ieee80211_local *local,
                              struct ieee80211_sta *sta, bool set)
 {
@@ -580,25 +552,9 @@ int drv_sta_state(struct ieee80211_local *local,
                  enum ieee80211_sta_state old_state,
                  enum ieee80211_sta_state new_state);
 
-static inline void drv_sta_rc_update(struct ieee80211_local *local,
-                                    struct ieee80211_sub_if_data *sdata,
-                                    struct ieee80211_sta *sta, u32 changed)
-{
-       sdata = get_bss_sdata(sdata);
-       if (!check_sdata_in_driver(sdata))
-               return;
-
-       WARN_ON(changed & IEEE80211_RC_SUPP_RATES_CHANGED &&
-               (sdata->vif.type != NL80211_IFTYPE_ADHOC &&
-                sdata->vif.type != NL80211_IFTYPE_MESH_POINT));
-
-       trace_drv_sta_rc_update(local, sdata, sta, changed);
-       if (local->ops->sta_rc_update)
-               local->ops->sta_rc_update(&local->hw, &sdata->vif,
-                                         sta, changed);
-
-       trace_drv_return_void(local);
-}
+void drv_sta_rc_update(struct ieee80211_local *local,
+                      struct ieee80211_sub_if_data *sdata,
+                      struct ieee80211_sta *sta, u32 changed);
 
 static inline void drv_sta_rate_tbl_update(struct ieee80211_local *local,
                                           struct ieee80211_sub_if_data *sdata,
@@ -630,76 +586,17 @@ static inline void drv_sta_statistics(struct ieee80211_local *local,
        trace_drv_return_void(local);
 }
 
-static inline int drv_conf_tx(struct ieee80211_local *local,
-                             struct ieee80211_sub_if_data *sdata, u16 ac,
-                             const struct ieee80211_tx_queue_params *params)
-{
-       int ret = -EOPNOTSUPP;
-
-       might_sleep();
-
-       if (!check_sdata_in_driver(sdata))
-               return -EIO;
-
-       if (WARN_ONCE(params->cw_min == 0 ||
-                     params->cw_min > params->cw_max,
-                     "%s: invalid CW_min/CW_max: %d/%d\n",
-                     sdata->name, params->cw_min, params->cw_max))
-               return -EINVAL;
-
-       trace_drv_conf_tx(local, sdata, ac, params);
-       if (local->ops->conf_tx)
-               ret = local->ops->conf_tx(&local->hw, &sdata->vif,
-                                         ac, params);
-       trace_drv_return_int(local, ret);
-       return ret;
-}
-
-static inline u64 drv_get_tsf(struct ieee80211_local *local,
-                             struct ieee80211_sub_if_data *sdata)
-{
-       u64 ret = -1ULL;
-
-       might_sleep();
-
-       if (!check_sdata_in_driver(sdata))
-               return ret;
-
-       trace_drv_get_tsf(local, sdata);
-       if (local->ops->get_tsf)
-               ret = local->ops->get_tsf(&local->hw, &sdata->vif);
-       trace_drv_return_u64(local, ret);
-       return ret;
-}
-
-static inline void drv_set_tsf(struct ieee80211_local *local,
-                              struct ieee80211_sub_if_data *sdata,
-                              u64 tsf)
-{
-       might_sleep();
-
-       if (!check_sdata_in_driver(sdata))
-               return;
-
-       trace_drv_set_tsf(local, sdata, tsf);
-       if (local->ops->set_tsf)
-               local->ops->set_tsf(&local->hw, &sdata->vif, tsf);
-       trace_drv_return_void(local);
-}
-
-static inline void drv_reset_tsf(struct ieee80211_local *local,
-                                struct ieee80211_sub_if_data *sdata)
-{
-       might_sleep();
+int drv_conf_tx(struct ieee80211_local *local,
+               struct ieee80211_sub_if_data *sdata, u16 ac,
+               const struct ieee80211_tx_queue_params *params);
 
-       if (!check_sdata_in_driver(sdata))
-               return;
-
-       trace_drv_reset_tsf(local, sdata);
-       if (local->ops->reset_tsf)
-               local->ops->reset_tsf(&local->hw, &sdata->vif);
-       trace_drv_return_void(local);
-}
+u64 drv_get_tsf(struct ieee80211_local *local,
+               struct ieee80211_sub_if_data *sdata);
+void drv_set_tsf(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
+                u64 tsf);
+void drv_reset_tsf(struct ieee80211_local *local,
+                  struct ieee80211_sub_if_data *sdata);
 
 static inline int drv_tx_last_beacon(struct ieee80211_local *local)
 {
@@ -714,30 +611,11 @@ static inline int drv_tx_last_beacon(struct ieee80211_local *local)
        return ret;
 }
 
-static inline int drv_ampdu_action(struct ieee80211_local *local,
-                                  struct ieee80211_sub_if_data *sdata,
-                                  enum ieee80211_ampdu_mlme_action action,
-                                  struct ieee80211_sta *sta, u16 tid,
-                                  u16 *ssn, u8 buf_size)
-{
-       int ret = -EOPNOTSUPP;
-
-       might_sleep();
-
-       sdata = get_bss_sdata(sdata);
-       if (!check_sdata_in_driver(sdata))
-               return -EIO;
-
-       trace_drv_ampdu_action(local, sdata, action, sta, tid, ssn, buf_size);
-
-       if (local->ops->ampdu_action)
-               ret = local->ops->ampdu_action(&local->hw, &sdata->vif, action,
-                                              sta, tid, ssn, buf_size);
-
-       trace_drv_return_int(local, ret);
-
-       return ret;
-}
+int drv_ampdu_action(struct ieee80211_local *local,
+                    struct ieee80211_sub_if_data *sdata,
+                    enum ieee80211_ampdu_mlme_action action,
+                    struct ieee80211_sta *sta, u16 tid,
+                    u16 *ssn, u8 buf_size, bool amsdu);
 
 static inline int drv_get_survey(struct ieee80211_local *local, int idx,
                                struct survey_info *survey)
@@ -1066,58 +944,9 @@ static inline void drv_unassign_vif_chanctx(struct ieee80211_local *local,
        trace_drv_return_void(local);
 }
 
-static inline int
-drv_switch_vif_chanctx(struct ieee80211_local *local,
-                      struct ieee80211_vif_chanctx_switch *vifs,
-                      int n_vifs,
-                      enum ieee80211_chanctx_switch_mode mode)
-{
-       int ret = 0;
-       int i;
-
-       if (!local->ops->switch_vif_chanctx)
-               return -EOPNOTSUPP;
-
-       for (i = 0; i < n_vifs; i++) {
-               struct ieee80211_chanctx *new_ctx =
-                       container_of(vifs[i].new_ctx,
-                                    struct ieee80211_chanctx,
-                                    conf);
-               struct ieee80211_chanctx *old_ctx =
-                       container_of(vifs[i].old_ctx,
-                                    struct ieee80211_chanctx,
-                                    conf);
-
-               WARN_ON_ONCE(!old_ctx->driver_present);
-               WARN_ON_ONCE((mode == CHANCTX_SWMODE_SWAP_CONTEXTS &&
-                             new_ctx->driver_present) ||
-                            (mode == CHANCTX_SWMODE_REASSIGN_VIF &&
-                             !new_ctx->driver_present));
-       }
-
-       trace_drv_switch_vif_chanctx(local, vifs, n_vifs, mode);
-       ret = local->ops->switch_vif_chanctx(&local->hw,
-                                            vifs, n_vifs, mode);
-       trace_drv_return_int(local, ret);
-
-       if (!ret && mode == CHANCTX_SWMODE_SWAP_CONTEXTS) {
-               for (i = 0; i < n_vifs; i++) {
-                       struct ieee80211_chanctx *new_ctx =
-                               container_of(vifs[i].new_ctx,
-                                            struct ieee80211_chanctx,
-                                            conf);
-                       struct ieee80211_chanctx *old_ctx =
-                               container_of(vifs[i].old_ctx,
-                                            struct ieee80211_chanctx,
-                                            conf);
-
-                       new_ctx->driver_present = true;
-                       old_ctx->driver_present = false;
-               }
-       }
-
-       return ret;
-}
+int drv_switch_vif_chanctx(struct ieee80211_local *local,
+                          struct ieee80211_vif_chanctx_switch *vifs,
+                          int n_vifs, enum ieee80211_chanctx_switch_mode mode);
 
 static inline int drv_start_ap(struct ieee80211_local *local,
                               struct ieee80211_sub_if_data *sdata)
index 6e52659..f9605f1 100644 (file)
@@ -419,6 +419,8 @@ struct ieee80211_sta_tx_tspec {
        bool downgraded;
 };
 
+DECLARE_EWMA(beacon_signal, 16, 4)
+
 struct ieee80211_if_managed {
        struct timer_list timer;
        struct timer_list conn_mon_timer;
@@ -490,16 +492,7 @@ struct ieee80211_if_managed {
 
        s16 p2p_noa_index;
 
-       /* Signal strength from the last Beacon frame in the current BSS. */
-       int last_beacon_signal;
-
-       /*
-        * Weighted average of the signal strength from Beacon frames in the
-        * current BSS. This is in units of 1/16 of the signal unit to maintain
-        * accuracy and to speed up calculations, i.e., the value need to be
-        * divided by 16 to get the actual value.
-        */
-       int ave_beacon_signal;
+       struct ewma_beacon_signal ave_beacon_signal;
 
        /*
         * Number of Beacon frames used in ave_beacon_signal. This can be used
@@ -535,6 +528,7 @@ struct ieee80211_if_managed {
        struct sk_buff *teardown_skb; /* A copy to send through the AP */
        spinlock_t teardown_lock; /* To lock changing teardown_skb */
        bool tdls_chan_switch_prohibited;
+       bool tdls_wider_bw_prohibited;
 
        /* WMM-AC TSPEC support */
        struct ieee80211_sta_tx_tspec tx_tspec[IEEE80211_NUM_ACS];
@@ -1641,6 +1635,9 @@ void ieee80211_purge_tx_queue(struct ieee80211_hw *hw,
 struct sk_buff *
 ieee80211_build_data_template(struct ieee80211_sub_if_data *sdata,
                              struct sk_buff *skb, u32 info_flags);
+void ieee80211_tx_monitor(struct ieee80211_local *local, struct sk_buff *skb,
+                         struct ieee80211_supported_band *sband,
+                         int retry_count, int shift, bool send_to_cooked);
 
 void ieee80211_check_fast_xmit(struct sta_info *sta);
 void ieee80211_check_fast_xmit_all(struct ieee80211_local *local);
@@ -1853,7 +1850,7 @@ void ieee80211_dynamic_ps_disable_work(struct work_struct *work);
 void ieee80211_dynamic_ps_timer(unsigned long data);
 void ieee80211_send_nullfunc(struct ieee80211_local *local,
                             struct ieee80211_sub_if_data *sdata,
-                            int powersave);
+                            bool powersave);
 void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
                             struct ieee80211_hdr *hdr);
 void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata,
index 6964fc6..42d7f0f 100644 (file)
@@ -1204,7 +1204,7 @@ static void ieee80211_iface_work(struct work_struct *work)
        if (!ieee80211_sdata_running(sdata))
                return;
 
-       if (local->scanning)
+       if (test_bit(SCAN_SW_SCANNING, &local->scanning))
                return;
 
        if (!ieee80211_can_run_worker(local))
index ff79a13..9b813a2 100644 (file)
@@ -543,7 +543,8 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
                           NL80211_FEATURE_HT_IBSS |
                           NL80211_FEATURE_VIF_TXPOWER |
                           NL80211_FEATURE_MAC_ON_CREATE |
-                          NL80211_FEATURE_USERSPACE_MPM;
+                          NL80211_FEATURE_USERSPACE_MPM |
+                          NL80211_FEATURE_FULL_AP_CLIENT_STATE;
 
        if (!ops->hw_scan)
                wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN |
index e06a5ca..626e8de 100644 (file)
@@ -94,6 +94,9 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
        ieee80211_ht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan,
                                     ie->ht_operation, &sta_chan_def);
 
+       ieee80211_vht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan,
+                                     ie->vht_operation, &sta_chan_def);
+
        if (!cfg80211_chandef_compatible(&sdata->vif.bss_conf.chandef,
                                         &sta_chan_def))
                return false;
@@ -436,8 +439,6 @@ int mesh_add_ht_oper_ie(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_chanctx_conf *chanctx_conf;
        struct ieee80211_channel *channel;
-       enum nl80211_channel_type channel_type =
-               cfg80211_get_chandef_type(&sdata->vif.bss_conf.chandef);
        struct ieee80211_supported_band *sband;
        struct ieee80211_sta_ht_cap *ht_cap;
        u8 *pos;
@@ -454,7 +455,10 @@ int mesh_add_ht_oper_ie(struct ieee80211_sub_if_data *sdata,
        sband = local->hw.wiphy->bands[channel->band];
        ht_cap = &sband->ht_cap;
 
-       if (!ht_cap->ht_supported || channel_type == NL80211_CHAN_NO_HT)
+       if (!ht_cap->ht_supported ||
+           sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT ||
+           sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 ||
+           sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10)
                return 0;
 
        if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_operation))
@@ -467,6 +471,68 @@ int mesh_add_ht_oper_ie(struct ieee80211_sub_if_data *sdata,
        return 0;
 }
 
+int mesh_add_vht_cap_ie(struct ieee80211_sub_if_data *sdata,
+                       struct sk_buff *skb)
+{
+       struct ieee80211_local *local = sdata->local;
+       enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
+       struct ieee80211_supported_band *sband;
+       u8 *pos;
+
+       sband = local->hw.wiphy->bands[band];
+       if (!sband->vht_cap.vht_supported ||
+           sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT ||
+           sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 ||
+           sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10)
+               return 0;
+
+       if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_vht_cap))
+               return -ENOMEM;
+
+       pos = skb_put(skb, 2 + sizeof(struct ieee80211_vht_cap));
+       ieee80211_ie_build_vht_cap(pos, &sband->vht_cap, sband->vht_cap.cap);
+
+       return 0;
+}
+
+int mesh_add_vht_oper_ie(struct ieee80211_sub_if_data *sdata,
+                        struct sk_buff *skb)
+{
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_chanctx_conf *chanctx_conf;
+       struct ieee80211_channel *channel;
+       struct ieee80211_supported_band *sband;
+       struct ieee80211_sta_vht_cap *vht_cap;
+       u8 *pos;
+
+       rcu_read_lock();
+       chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+       if (WARN_ON(!chanctx_conf)) {
+               rcu_read_unlock();
+               return -EINVAL;
+       }
+       channel = chanctx_conf->def.chan;
+       rcu_read_unlock();
+
+       sband = local->hw.wiphy->bands[channel->band];
+       vht_cap = &sband->vht_cap;
+
+       if (!vht_cap->vht_supported ||
+           sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT ||
+           sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 ||
+           sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10)
+               return 0;
+
+       if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_vht_operation))
+               return -ENOMEM;
+
+       pos = skb_put(skb, 2 + sizeof(struct ieee80211_vht_operation));
+       ieee80211_ie_build_vht_oper(pos, vht_cap,
+                                   &sdata->vif.bss_conf.chandef);
+
+       return 0;
+}
+
 static void ieee80211_mesh_path_timer(unsigned long data)
 {
        struct ieee80211_sub_if_data *sdata =
@@ -540,9 +606,9 @@ int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
  *
  * Return the header length.
  */
-int ieee80211_new_mesh_header(struct ieee80211_sub_if_data *sdata,
-                             struct ieee80211s_hdr *meshhdr,
-                             const char *addr4or5, const char *addr6)
+unsigned int ieee80211_new_mesh_header(struct ieee80211_sub_if_data *sdata,
+                                      struct ieee80211s_hdr *meshhdr,
+                                      const char *addr4or5, const char *addr6)
 {
        if (WARN_ON(!addr4or5 && addr6))
                return 0;
@@ -637,6 +703,8 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
                   2 + ifmsh->mesh_id_len +
                   2 + sizeof(struct ieee80211_meshconf_ie) +
                   2 + sizeof(__le16) + /* awake window */
+                  2 + sizeof(struct ieee80211_vht_cap) +
+                  2 + sizeof(struct ieee80211_vht_operation) +
                   ifmsh->ie_len;
 
        bcn = kzalloc(sizeof(*bcn) + head_len + tail_len, GFP_KERNEL);
@@ -718,6 +786,8 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
            mesh_add_meshid_ie(sdata, skb) ||
            mesh_add_meshconf_ie(sdata, skb) ||
            mesh_add_awake_window_ie(sdata, skb) ||
+           mesh_add_vht_cap_ie(sdata, skb) ||
+           mesh_add_vht_oper_ie(sdata, skb) ||
            mesh_add_vendor_ies(sdata, skb))
                goto out_free;
 
index 50c8473..a159634 100644 (file)
@@ -207,9 +207,9 @@ struct mesh_rmc {
 /* Various */
 int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
                                  const u8 *da, const u8 *sa);
-int ieee80211_new_mesh_header(struct ieee80211_sub_if_data *sdata,
-                             struct ieee80211s_hdr *meshhdr,
-                             const char *addr4or5, const char *addr6);
+unsigned int ieee80211_new_mesh_header(struct ieee80211_sub_if_data *sdata,
+                                      struct ieee80211s_hdr *meshhdr,
+                                      const char *addr4or5, const char *addr6);
 int mesh_rmc_check(struct ieee80211_sub_if_data *sdata,
                   const u8 *addr, struct ieee80211s_hdr *mesh_hdr);
 bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
@@ -227,6 +227,10 @@ int mesh_add_ht_cap_ie(struct ieee80211_sub_if_data *sdata,
                       struct sk_buff *skb);
 int mesh_add_ht_oper_ie(struct ieee80211_sub_if_data *sdata,
                        struct sk_buff *skb);
+int mesh_add_vht_cap_ie(struct ieee80211_sub_if_data *sdata,
+                       struct sk_buff *skb);
+int mesh_add_vht_oper_ie(struct ieee80211_sub_if_data *sdata,
+                        struct sk_buff *skb);
 void mesh_rmc_free(struct ieee80211_sub_if_data *sdata);
 int mesh_rmc_init(struct ieee80211_sub_if_data *sdata);
 void ieee80211s_init(void);
index 5838464..a360b24 100644 (file)
@@ -226,6 +226,8 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
                            2 + sizeof(struct ieee80211_meshconf_ie) +
                            2 + sizeof(struct ieee80211_ht_cap) +
                            2 + sizeof(struct ieee80211_ht_operation) +
+                           2 + sizeof(struct ieee80211_vht_cap) +
+                           2 + sizeof(struct ieee80211_vht_operation) +
                            2 + 8 + /* peering IE */
                            sdata->u.mesh.ie_len);
        if (!skb)
@@ -306,7 +308,9 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
 
        if (action != WLAN_SP_MESH_PEERING_CLOSE) {
                if (mesh_add_ht_cap_ie(sdata, skb) ||
-                   mesh_add_ht_oper_ie(sdata, skb))
+                   mesh_add_ht_oper_ie(sdata, skb) ||
+                   mesh_add_vht_cap_ie(sdata, skb) ||
+                   mesh_add_vht_oper_ie(sdata, skb))
                        goto free;
        }
 
@@ -402,6 +406,9 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata,
                                              elems->ht_cap_elem, sta))
                changed |= IEEE80211_RC_BW_CHANGED;
 
+       ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
+                                           elems->vht_cap_elem, sta);
+
        if (bw != sta->sta.bandwidth)
                changed |= IEEE80211_RC_BW_CHANGED;
 
index cd7e55e..56ef9a8 100644 (file)
@@ -81,13 +81,6 @@ MODULE_PARM_DESC(probe_wait_ms,
                 "Maximum time(ms) to wait for probe response"
                 " before disconnecting (reason 4).");
 
-/*
- * Weight given to the latest Beacon frame when calculating average signal
- * strength for Beacon frames received in the current BSS. This must be
- * between 1 and 15.
- */
-#define IEEE80211_SIGNAL_AVE_WEIGHT    3
-
 /*
  * How many Beacon frames need to have been used in average signal strength
  * before starting to indicate signal change events.
@@ -943,7 +936,7 @@ void ieee80211_send_pspoll(struct ieee80211_local *local,
 
 void ieee80211_send_nullfunc(struct ieee80211_local *local,
                             struct ieee80211_sub_if_data *sdata,
-                            int powersave)
+                            bool powersave)
 {
        struct sk_buff *skb;
        struct ieee80211_hdr_3addr *nullfunc;
@@ -1427,7 +1420,7 @@ static void ieee80211_enable_ps(struct ieee80211_local *local,
                          msecs_to_jiffies(conf->dynamic_ps_timeout));
        } else {
                if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK))
-                       ieee80211_send_nullfunc(local, sdata, 1);
+                       ieee80211_send_nullfunc(local, sdata, true);
 
                if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK) &&
                    ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS))
@@ -1642,7 +1635,7 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work)
                                  msecs_to_jiffies(
                                  local->hw.conf.dynamic_ps_timeout));
                } else {
-                       ieee80211_send_nullfunc(local, sdata, 1);
+                       ieee80211_send_nullfunc(local, sdata, true);
                        /* Flush to get the tx status of nullfunc frame */
                        ieee80211_flush_queues(local, sdata, false);
                }
@@ -2275,7 +2268,7 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)
 
        if (ieee80211_hw_check(&sdata->local->hw, REPORTS_TX_ACK_STATUS)) {
                ifmgd->nullfunc_failed = false;
-               ieee80211_send_nullfunc(sdata->local, sdata, 0);
+               ieee80211_send_nullfunc(sdata->local, sdata, false);
        } else {
                int ssid_len;
 
@@ -3262,16 +3255,6 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
        if (ifmgd->associated &&
            ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid))
                ieee80211_reset_ap_probe(sdata);
-
-       if (ifmgd->auth_data && !ifmgd->auth_data->bss->proberesp_ies &&
-           ether_addr_equal(mgmt->bssid, ifmgd->auth_data->bss->bssid)) {
-               /* got probe response, continue with auth */
-               sdata_info(sdata, "direct probe responded\n");
-               ifmgd->auth_data->tries = 0;
-               ifmgd->auth_data->timeout = jiffies;
-               ifmgd->auth_data->timeout_started = true;
-               run_again(sdata, ifmgd->auth_data->timeout);
-       }
 }
 
 /*
@@ -3374,24 +3357,21 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
        bssid = ifmgd->associated->bssid;
 
        /* Track average RSSI from the Beacon frames of the current AP */
-       ifmgd->last_beacon_signal = rx_status->signal;
        if (ifmgd->flags & IEEE80211_STA_RESET_SIGNAL_AVE) {
                ifmgd->flags &= ~IEEE80211_STA_RESET_SIGNAL_AVE;
-               ifmgd->ave_beacon_signal = rx_status->signal * 16;
+               ewma_beacon_signal_init(&ifmgd->ave_beacon_signal);
                ifmgd->last_cqm_event_signal = 0;
                ifmgd->count_beacon_signal = 1;
                ifmgd->last_ave_beacon_signal = 0;
        } else {
-               ifmgd->ave_beacon_signal =
-                       (IEEE80211_SIGNAL_AVE_WEIGHT * rx_status->signal * 16 +
-                        (16 - IEEE80211_SIGNAL_AVE_WEIGHT) *
-                        ifmgd->ave_beacon_signal) / 16;
                ifmgd->count_beacon_signal++;
        }
 
+       ewma_beacon_signal_add(&ifmgd->ave_beacon_signal, -rx_status->signal);
+
        if (ifmgd->rssi_min_thold != ifmgd->rssi_max_thold &&
            ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT) {
-               int sig = ifmgd->ave_beacon_signal;
+               int sig = -ewma_beacon_signal_read(&ifmgd->ave_beacon_signal);
                int last_sig = ifmgd->last_ave_beacon_signal;
                struct ieee80211_event event = {
                        .type = RSSI_EVENT,
@@ -3418,10 +3398,11 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
        if (bss_conf->cqm_rssi_thold &&
            ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT &&
            !(sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI)) {
-               int sig = ifmgd->ave_beacon_signal / 16;
+               int sig = -ewma_beacon_signal_read(&ifmgd->ave_beacon_signal);
                int last_event = ifmgd->last_cqm_event_signal;
                int thold = bss_conf->cqm_rssi_thold;
                int hyst = bss_conf->cqm_rssi_hyst;
+
                if (sig < thold &&
                    (last_event == 0 || sig < last_event - hyst)) {
                        ifmgd->last_cqm_event_signal = sig;
@@ -3456,31 +3437,27 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
                                          len - baselen, false, &elems,
                                          care_about_ies, ncrc);
 
-       if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK)) {
-               bool directed_tim = ieee80211_check_tim(elems.tim,
-                                                       elems.tim_len,
-                                                       ifmgd->aid);
-               if (directed_tim) {
-                       if (local->hw.conf.dynamic_ps_timeout > 0) {
-                               if (local->hw.conf.flags & IEEE80211_CONF_PS) {
-                                       local->hw.conf.flags &= ~IEEE80211_CONF_PS;
-                                       ieee80211_hw_config(local,
-                                                           IEEE80211_CONF_CHANGE_PS);
-                               }
-                               ieee80211_send_nullfunc(local, sdata, 0);
-                       } else if (!local->pspolling && sdata->u.mgd.powersave) {
-                               local->pspolling = true;
-
-                               /*
-                                * Here is assumed that the driver will be
-                                * able to send ps-poll frame and receive a
-                                * response even though power save mode is
-                                * enabled, but some drivers might require
-                                * to disable power save here. This needs
-                                * to be investigated.
-                                */
-                               ieee80211_send_pspoll(local, sdata);
+       if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK) &&
+           ieee80211_check_tim(elems.tim, elems.tim_len, ifmgd->aid)) {
+               if (local->hw.conf.dynamic_ps_timeout > 0) {
+                       if (local->hw.conf.flags & IEEE80211_CONF_PS) {
+                               local->hw.conf.flags &= ~IEEE80211_CONF_PS;
+                               ieee80211_hw_config(local,
+                                                   IEEE80211_CONF_CHANGE_PS);
                        }
+                       ieee80211_send_nullfunc(local, sdata, false);
+               } else if (!local->pspolling && sdata->u.mgd.powersave) {
+                       local->pspolling = true;
+
+                       /*
+                        * Here is assumed that the driver will be
+                        * able to send ps-poll frame and receive a
+                        * response even though power save mode is
+                        * enabled, but some drivers might require
+                        * to disable power save here. This needs
+                        * to be investigated.
+                        */
+                       ieee80211_send_pspoll(local, sdata);
                }
        }
 
@@ -3717,12 +3694,14 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata,
                                    reason);
 }
 
-static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
+static int ieee80211_auth(struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_mgd_auth_data *auth_data = ifmgd->auth_data;
        u32 tx_flags = 0;
+       u16 trans = 1;
+       u16 status = 0;
 
        sdata_assert_lock(sdata);
 
@@ -3746,54 +3725,27 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
 
        drv_mgd_prepare_tx(local, sdata);
 
-       if (auth_data->bss->proberesp_ies) {
-               u16 trans = 1;
-               u16 status = 0;
-
-               sdata_info(sdata, "send auth to %pM (try %d/%d)\n",
-                          auth_data->bss->bssid, auth_data->tries,
-                          IEEE80211_AUTH_MAX_TRIES);
+       sdata_info(sdata, "send auth to %pM (try %d/%d)\n",
+                  auth_data->bss->bssid, auth_data->tries,
+                  IEEE80211_AUTH_MAX_TRIES);
 
-               auth_data->expected_transaction = 2;
+       auth_data->expected_transaction = 2;
 
-               if (auth_data->algorithm == WLAN_AUTH_SAE) {
-                       trans = auth_data->sae_trans;
-                       status = auth_data->sae_status;
-                       auth_data->expected_transaction = trans;
-               }
-
-               if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS))
-                       tx_flags = IEEE80211_TX_CTL_REQ_TX_STATUS |
-                                  IEEE80211_TX_INTFL_MLME_CONN_TX;
-
-               ieee80211_send_auth(sdata, trans, auth_data->algorithm, status,
-                                   auth_data->data, auth_data->data_len,
-                                   auth_data->bss->bssid,
-                                   auth_data->bss->bssid, NULL, 0, 0,
-                                   tx_flags);
-       } else {
-               const u8 *ssidie;
+       if (auth_data->algorithm == WLAN_AUTH_SAE) {
+               trans = auth_data->sae_trans;
+               status = auth_data->sae_status;
+               auth_data->expected_transaction = trans;
+       }
 
-               sdata_info(sdata, "direct probe to %pM (try %d/%i)\n",
-                          auth_data->bss->bssid, auth_data->tries,
-                          IEEE80211_AUTH_MAX_TRIES);
+       if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS))
+               tx_flags = IEEE80211_TX_CTL_REQ_TX_STATUS |
+                          IEEE80211_TX_INTFL_MLME_CONN_TX;
 
-               rcu_read_lock();
-               ssidie = ieee80211_bss_get_ie(auth_data->bss, WLAN_EID_SSID);
-               if (!ssidie) {
-                       rcu_read_unlock();
-                       return -EINVAL;
-               }
-               /*
-                * Direct probe is sent to broadcast address as some APs
-                * will not answer to direct packet in unassociated state.
-                */
-               ieee80211_send_probe_req(sdata, sdata->vif.addr, NULL,
-                                        ssidie + 2, ssidie[1],
-                                        NULL, 0, (u32) -1, true, 0,
-                                        auth_data->bss->channel, false);
-               rcu_read_unlock();
-       }
+       ieee80211_send_auth(sdata, trans, auth_data->algorithm, status,
+                           auth_data->data, auth_data->data_len,
+                           auth_data->bss->bssid,
+                           auth_data->bss->bssid, NULL, 0, 0,
+                           tx_flags);
 
        if (tx_flags == 0) {
                auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
@@ -3874,8 +3826,7 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
                bool status_acked = ifmgd->status_acked;
 
                ifmgd->status_received = false;
-               if (ifmgd->auth_data &&
-                   (ieee80211_is_probe_req(fc) || ieee80211_is_auth(fc))) {
+               if (ifmgd->auth_data && ieee80211_is_auth(fc)) {
                        if (status_acked) {
                                ifmgd->auth_data->timeout =
                                        jiffies + IEEE80211_AUTH_TIMEOUT_SHORT;
@@ -3906,7 +3857,7 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
                         * so let's just kill the auth data
                         */
                        ieee80211_destroy_auth_data(sdata, false);
-               } else if (ieee80211_probe_auth(sdata)) {
+               } else if (ieee80211_auth(sdata)) {
                        u8 bssid[ETH_ALEN];
                        struct ieee80211_event event = {
                                .type = MLME_EVENT,
@@ -4613,7 +4564,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
        if (err)
                goto err_clear;
 
-       err = ieee80211_probe_auth(sdata);
+       err = ieee80211_auth(sdata);
        if (err) {
                sta_info_destroy_addr(sdata, req->bss->bssid);
                goto err_clear;
index f2c75cf..0440103 100644 (file)
@@ -57,7 +57,7 @@ static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata)
                 * to send a new nullfunc frame to inform the AP that we
                 * are again sleeping.
                 */
-               ieee80211_send_nullfunc(local, sdata, 1);
+               ieee80211_send_nullfunc(local, sdata, true);
 }
 
 /* inform AP that we are awake again, unless power save is enabled */
@@ -66,7 +66,7 @@ static void ieee80211_offchannel_ps_disable(struct ieee80211_sub_if_data *sdata)
        struct ieee80211_local *local = sdata->local;
 
        if (!local->ps_sdata)
-               ieee80211_send_nullfunc(local, sdata, 0);
+               ieee80211_send_nullfunc(local, sdata, false);
        else if (local->offchannel_ps_enabled) {
                /*
                 * In !IEEE80211_HW_PS_NULLFUNC_STACK case the hardware
@@ -93,7 +93,7 @@ static void ieee80211_offchannel_ps_disable(struct ieee80211_sub_if_data *sdata)
                 * restart the timer now and send a nullfunc frame to inform
                 * the AP that we are awake.
                 */
-               ieee80211_send_nullfunc(local, sdata, 0);
+               ieee80211_send_nullfunc(local, sdata, false);
                mod_timer(&local->dynamic_ps_timer, jiffies +
                          msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
        }
index b676b9f..ad88ad4 100644 (file)
@@ -23,7 +23,8 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
 
        ieee80211_del_virtual_monitor(local);
 
-       if (ieee80211_hw_check(hw, AMPDU_AGGREGATION)) {
+       if (ieee80211_hw_check(hw, AMPDU_AGGREGATION) &&
+           !(wowlan && wowlan->any)) {
                mutex_lock(&local->sta_mtx);
                list_for_each_entry(sta, &local->sta_list, list) {
                        set_sta_flag(sta, WLAN_STA_BLOCK_BA);
index 9ce8883..b07e2f7 100644 (file)
@@ -305,7 +305,10 @@ static void __rate_control_send_low(struct ieee80211_hw *hw,
                info->control.rates[0].idx = i;
                break;
        }
-       WARN_ON_ONCE(i == sband->n_bitrates);
+       WARN_ONCE(i == sband->n_bitrates,
+                 "no supported rates (0x%x) in rate_mask 0x%x with flags 0x%x\n",
+                 sta ? sta->supp_rates[sband->band] : 0,
+                 rate_mask, rate_flags);
 
        info->control.rates[0].count =
                (info->flags & IEEE80211_TX_CTL_NO_ACK) ?
index 1db5f7c..820b0ab 100644 (file)
@@ -85,12 +85,10 @@ minstrel_stats_open(struct inode *inode, struct file *file)
        file->private_data = ms;
        p = ms->buf;
        p += sprintf(p, "\n");
-       p += sprintf(p, "best   __________rate_________    ______"
-                       "statistics______    ________last_______    "
-                       "______sum-of________\n");
-       p += sprintf(p, "rate  [name idx airtime max_tp]  [ Ăž(tp) Ăž(prob) "
-                       "sd(prob)]  [prob.|retry|suc|att]  "
-                       "[#success | #attempts]\n");
+       p += sprintf(p,
+                    "best   __________rate_________    ________statistics________    ________last_______    ______sum-of________\n");
+       p += sprintf(p,
+                    "rate  [name idx airtime max_tp]  [avg(tp) avg(prob) sd(prob)]  [prob.|retry|suc|att]  [#success | #attempts]\n");
 
        for (i = 0; i < mi->n_rates; i++) {
                struct minstrel_rate *mr = &mi->r[i];
@@ -112,7 +110,7 @@ minstrel_stats_open(struct inode *inode, struct file *file)
                prob = MINSTREL_TRUNC(mrs->cur_prob * 1000);
                eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);
 
-               p += sprintf(p, "%4u.%1u   %4u.%1u   %3u.%1u    %3u.%1u"
+               p += sprintf(p, "%4u.%1u    %4u.%1u     %3u.%1u    %3u.%1u"
                                "     %3u.%1u %3u   %3u %-3u   "
                                "%9llu   %-9llu\n",
                                tp_max / 10, tp_max % 10,
index 6822ce0..5320e35 100644 (file)
@@ -86,7 +86,7 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p)
                prob = MINSTREL_TRUNC(mrs->cur_prob * 1000);
                eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);
 
-               p += sprintf(p, "%4u.%1u   %4u.%1u   %3u.%1u    %3u.%1u"
+               p += sprintf(p, "%4u.%1u    %4u.%1u     %3u.%1u    %3u.%1u"
                                "     %3u.%1u %3u   %3u %-3u   "
                                "%9llu   %-9llu\n",
                                tp_max / 10, tp_max % 10,
@@ -129,12 +129,10 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file)
        p = ms->buf;
 
        p += sprintf(p, "\n");
-       p += sprintf(p, "              best   ____________rate__________    "
-                       "______statistics______    ________last_______    "
-                       "______sum-of________\n");
-       p += sprintf(p, "mode guard #  rate  [name   idx airtime  max_tp]  "
-                       "[ Ăž(tp) Ăž(prob) sd(prob)]  [prob.|retry|suc|att]  [#success | "
-                       "#attempts]\n");
+       p += sprintf(p,
+                    "              best   ____________rate__________    ________statistics________    ________last_______    ______sum-of________\n");
+       p += sprintf(p,
+                    "mode guard #  rate  [name   idx airtime  max_tp]  [avg(tp) avg(prob) sd(prob)]  [prob.|retry|suc|att]  [#success | #attempts]\n");
 
        p = minstrel_ht_stats_dump(mi, MINSTREL_CCK_GROUP, p);
        for (i = 0; i < MINSTREL_CCK_GROUP; i++)
index b087c71..d5ded87 100644 (file)
@@ -133,6 +133,7 @@ enum ieee80211_agg_stop_reason {
  * @buf_size: reorder buffer size at receiver
  * @failed_bar_ssn: ssn of the last failed BAR tx attempt
  * @bar_pending: BAR needs to be re-sent
+ * @amsdu: support A-MSDU withing A-MDPU
  *
  * This structure's lifetime is managed by RCU, assignments to
  * the array holding it must hold the aggregation mutex.
@@ -158,6 +159,7 @@ struct tid_ampdu_tx {
 
        u16 failed_bar_ssn;
        bool bar_pending;
+       bool amsdu;
 };
 
 /**
index 8ba5832..98fd04c 100644 (file)
@@ -668,16 +668,70 @@ void ieee80211_tx_status_noskb(struct ieee80211_hw *hw,
 }
 EXPORT_SYMBOL(ieee80211_tx_status_noskb);
 
-void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
+void ieee80211_tx_monitor(struct ieee80211_local *local, struct sk_buff *skb,
+                         struct ieee80211_supported_band *sband,
+                         int retry_count, int shift, bool send_to_cooked)
 {
        struct sk_buff *skb2;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_sub_if_data *sdata;
+       struct net_device *prev_dev = NULL;
+       int rtap_len;
+
+       /* send frame to monitor interfaces now */
+       rtap_len = ieee80211_tx_radiotap_len(info);
+       if (WARN_ON_ONCE(skb_headroom(skb) < rtap_len)) {
+               pr_err("ieee80211_tx_status: headroom too small\n");
+               dev_kfree_skb(skb);
+               return;
+       }
+       ieee80211_add_tx_radiotap_header(local, sband, skb, retry_count,
+                                        rtap_len, shift);
+
+       /* XXX: is this sufficient for BPF? */
+       skb_set_mac_header(skb, 0);
+       skb->ip_summed = CHECKSUM_UNNECESSARY;
+       skb->pkt_type = PACKET_OTHERHOST;
+       skb->protocol = htons(ETH_P_802_2);
+       memset(skb->cb, 0, sizeof(skb->cb));
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+               if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
+                       if (!ieee80211_sdata_running(sdata))
+                               continue;
+
+                       if ((sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) &&
+                           !send_to_cooked)
+                               continue;
+
+                       if (prev_dev) {
+                               skb2 = skb_clone(skb, GFP_ATOMIC);
+                               if (skb2) {
+                                       skb2->dev = prev_dev;
+                                       netif_rx(skb2);
+                               }
+                       }
+
+                       prev_dev = sdata->dev;
+               }
+       }
+       if (prev_dev) {
+               skb->dev = prev_dev;
+               netif_rx(skb);
+               skb = NULL;
+       }
+       rcu_read_unlock();
+       dev_kfree_skb(skb);
+}
+
+void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
        struct ieee80211_local *local = hw_to_local(hw);
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        __le16 fc;
        struct ieee80211_supported_band *sband;
-       struct ieee80211_sub_if_data *sdata;
-       struct net_device *prev_dev = NULL;
        struct sta_info *sta;
        struct rhash_head *tmp;
        int retry_count;
@@ -685,7 +739,6 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
        bool send_to_cooked;
        bool acked;
        struct ieee80211_bar *bar;
-       int rtap_len;
        int shift = 0;
        int tid = IEEE80211_NUM_TIDS;
        const struct bucket_table *tbl;
@@ -878,51 +931,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
                return;
        }
 
-       /* send frame to monitor interfaces now */
-       rtap_len = ieee80211_tx_radiotap_len(info);
-       if (WARN_ON_ONCE(skb_headroom(skb) < rtap_len)) {
-               pr_err("ieee80211_tx_status: headroom too small\n");
-               dev_kfree_skb(skb);
-               return;
-       }
-       ieee80211_add_tx_radiotap_header(local, sband, skb, retry_count,
-                                        rtap_len, shift);
-
-       /* XXX: is this sufficient for BPF? */
-       skb_set_mac_header(skb, 0);
-       skb->ip_summed = CHECKSUM_UNNECESSARY;
-       skb->pkt_type = PACKET_OTHERHOST;
-       skb->protocol = htons(ETH_P_802_2);
-       memset(skb->cb, 0, sizeof(skb->cb));
-
-       rcu_read_lock();
-       list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-               if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
-                       if (!ieee80211_sdata_running(sdata))
-                               continue;
-
-                       if ((sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) &&
-                           !send_to_cooked)
-                               continue;
-
-                       if (prev_dev) {
-                               skb2 = skb_clone(skb, GFP_ATOMIC);
-                               if (skb2) {
-                                       skb2->dev = prev_dev;
-                                       netif_rx(skb2);
-                               }
-                       }
-
-                       prev_dev = sdata->dev;
-               }
-       }
-       if (prev_dev) {
-               skb->dev = prev_dev;
-               netif_rx(skb);
-               skb = NULL;
-       }
-       rcu_read_unlock();
-       dev_kfree_skb(skb);
+       /* send to monitor interfaces */
+       ieee80211_tx_monitor(local, skb, sband, retry_count, shift, send_to_cooked);
 }
 EXPORT_SYMBOL(ieee80211_tx_status);
 
index 4e202d0..ecc5e2a 100644 (file)
@@ -41,9 +41,11 @@ static void ieee80211_tdls_add_ext_capab(struct ieee80211_sub_if_data *sdata,
                                         struct sk_buff *skb)
 {
        struct ieee80211_local *local = sdata->local;
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        bool chan_switch = local->hw.wiphy->features &
                           NL80211_FEATURE_TDLS_CHANNEL_SWITCH;
-       bool wider_band = ieee80211_hw_check(&local->hw, TDLS_WIDER_BW);
+       bool wider_band = ieee80211_hw_check(&local->hw, TDLS_WIDER_BW) &&
+                         !ifmgd->tdls_wider_bw_prohibited;
        enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
        struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band];
        bool vht = sband && sband->vht_cap.vht_supported;
@@ -331,8 +333,8 @@ ieee80211_tdls_chandef_vht_upgrade(struct ieee80211_sub_if_data *sdata,
 
        /* proceed to downgrade the chandef until usable or the same */
        while (uc.width > max_width &&
-              !cfg80211_reg_can_beacon(sdata->local->hw.wiphy,
-                                       &uc, sdata->wdev.iftype))
+              !cfg80211_reg_can_beacon_relax(sdata->local->hw.wiphy, &uc,
+                                             sdata->wdev.iftype))
                ieee80211_chandef_downgrade(&uc);
 
        if (!cfg80211_chandef_identical(&uc, &sta->tdls_chandef)) {
index 6f14591..314e3bd 100644 (file)
@@ -497,6 +497,36 @@ TRACE_EVENT(drv_configure_filter,
        )
 );
 
+TRACE_EVENT(drv_config_iface_filter,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
+                unsigned int filter_flags,
+                unsigned int changed_flags),
+
+       TP_ARGS(local, sdata, filter_flags, changed_flags),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               VIF_ENTRY
+               __field(unsigned int, filter_flags)
+               __field(unsigned int, changed_flags)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               VIF_ASSIGN;
+               __entry->filter_flags = filter_flags;
+               __entry->changed_flags = changed_flags;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT VIF_PR_FMT
+               " filter_flags: %#x changed_flags: %#x",
+               LOCAL_PR_ARG, VIF_PR_ARG, __entry->filter_flags,
+               __entry->changed_flags
+       )
+);
+
 TRACE_EVENT(drv_set_tim,
        TP_PROTO(struct ieee80211_local *local,
                 struct ieee80211_sta *sta, bool set),
@@ -944,9 +974,9 @@ TRACE_EVENT(drv_ampdu_action,
                 struct ieee80211_sub_if_data *sdata,
                 enum ieee80211_ampdu_mlme_action action,
                 struct ieee80211_sta *sta, u16 tid,
-                u16 *ssn, u8 buf_size),
+                u16 *ssn, u8 buf_size, bool amsdu),
 
-       TP_ARGS(local, sdata, action, sta, tid, ssn, buf_size),
+       TP_ARGS(local, sdata, action, sta, tid, ssn, buf_size, amsdu),
 
        TP_STRUCT__entry(
                LOCAL_ENTRY
@@ -955,6 +985,7 @@ TRACE_EVENT(drv_ampdu_action,
                __field(u16, tid)
                __field(u16, ssn)
                __field(u8, buf_size)
+               __field(bool, amsdu)
                VIF_ENTRY
        ),
 
@@ -966,12 +997,13 @@ TRACE_EVENT(drv_ampdu_action,
                __entry->tid = tid;
                __entry->ssn = ssn ? *ssn : 0;
                __entry->buf_size = buf_size;
+               __entry->amsdu = amsdu;
        ),
 
        TP_printk(
-               LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " action:%d tid:%d buf:%d",
+               LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " action:%d tid:%d buf:%d amsdu:%d",
                LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action,
-               __entry->tid, __entry->buf_size
+               __entry->tid, __entry->buf_size, __entry->amsdu
        )
 );
 
index 84e0e8c..464ba1a 100644 (file)
@@ -2767,7 +2767,8 @@ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
 
        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);
+               if (!sta->sta.txq[0])
+                       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);
@@ -3512,6 +3513,12 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
 {
        struct ieee80211_mutable_offsets offs = {};
        struct sk_buff *bcn = __ieee80211_beacon_get(hw, vif, &offs, false);
+       struct sk_buff *copy;
+       struct ieee80211_supported_band *sband;
+       int shift;
+
+       if (!bcn)
+               return bcn;
 
        if (tim_offset)
                *tim_offset = offs.tim_offset;
@@ -3519,6 +3526,19 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
        if (tim_length)
                *tim_length = offs.tim_length;
 
+       if (ieee80211_hw_check(hw, BEACON_TX_STATUS) ||
+           !hw_to_local(hw)->monitors)
+               return bcn;
+
+       /* send a copy to monitor interfaces */
+       copy = skb_copy(bcn, GFP_ATOMIC);
+       if (!copy)
+               return bcn;
+
+       shift = ieee80211_vif_get_shift(vif);
+       sband = hw->wiphy->bands[ieee80211_get_sdata_band(vif_to_sdata(vif))];
+       ieee80211_tx_monitor(hw_to_local(hw), copy, sband, 1, shift, false);
+
        return bcn;
 }
 EXPORT_SYMBOL(ieee80211_beacon_get_tim);
index 1104421..60c4dbf 100644 (file)
@@ -1966,7 +1966,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                        if (!sdata->u.mgd.associated)
                                continue;
 
-                       ieee80211_send_nullfunc(local, sdata, 0);
+                       ieee80211_send_nullfunc(local, sdata, false);
                }
        }
 
@@ -2017,8 +2017,9 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                mutex_lock(&local->sta_mtx);
 
                list_for_each_entry(sta, &local->sta_list, list) {
-                       ieee80211_sta_tear_down_BA_sessions(
-                                       sta, AGG_STOP_LOCAL_REQUEST);
+                       if (!local->resuming)
+                               ieee80211_sta_tear_down_BA_sessions(
+                                               sta, AGG_STOP_LOCAL_REQUEST);
                        clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
                }
 
@@ -2324,6 +2325,8 @@ u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
        if (chandef->center_freq2)
                vht_oper->center_freq_seg2_idx =
                        ieee80211_frequency_to_channel(chandef->center_freq2);
+       else
+               vht_oper->center_freq_seg2_idx = 0x00;
 
        switch (chandef->width) {
        case NL80211_CHAN_WIDTH_160:
@@ -2541,7 +2544,7 @@ int ieee80211_ave_rssi(struct ieee80211_vif *vif)
                /* non-managed type inferfaces */
                return 0;
        }
-       return ifmgd->ave_beacon_signal / 16;
+       return -ewma_beacon_signal_read(&ifmgd->ave_beacon_signal);
 }
 EXPORT_SYMBOL_GPL(ieee80211_ave_rssi);
 
index 3893409..f223026 100644 (file)
@@ -419,6 +419,7 @@ use_default_name:
        device_initialize(&rdev->wiphy.dev);
        rdev->wiphy.dev.class = &ieee80211_class;
        rdev->wiphy.dev.platform_data = rdev;
+       device_enable_async_suspend(&rdev->wiphy.dev);
 
        INIT_LIST_HEAD(&rdev->destroy_list);
        spin_lock_init(&rdev->destroy_list_lock);
index 5d8748b..f05ba8b 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2013-2014  Intel Mobile Communications GmbH
+ * Copyright 2015      Intel Deutschland GmbH
  */
 
 #include <linux/if.h>
@@ -2403,6 +2404,16 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag
                }
        }
 
+       if (rdev->ops->get_tx_power) {
+               int dbm, ret;
+
+               ret = rdev_get_tx_power(rdev, wdev, &dbm);
+               if (ret == 0 &&
+                   nla_put_u32(msg, NL80211_ATTR_WIPHY_TX_POWER_LEVEL,
+                               DBM_TO_MBM(dbm)))
+                       goto nla_put_failure;
+       }
+
        if (wdev->ssid_len) {
                if (nla_put(msg, NL80211_ATTR_SSID, wdev->ssid_len, wdev->ssid))
                        goto nla_put_failure;
@@ -3998,7 +4009,8 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
                params->sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
        }
 
-       if (statype != CFG80211_STA_TDLS_PEER_SETUP) {
+       if (statype != CFG80211_STA_TDLS_PEER_SETUP &&
+           statype != CFG80211_STA_AP_CLIENT_UNASSOC) {
                /* reject other things that can't change */
                if (params->sta_modify_mask & STATION_PARAM_APPLY_UAPSD)
                        return -EINVAL;
@@ -4010,7 +4022,8 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
                        return -EINVAL;
        }
 
-       if (statype != CFG80211_STA_AP_CLIENT) {
+       if (statype != CFG80211_STA_AP_CLIENT &&
+           statype != CFG80211_STA_AP_CLIENT_UNASSOC) {
                if (params->vlan)
                        return -EINVAL;
        }
@@ -4022,6 +4035,7 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
                        return -EOPNOTSUPP;
                break;
        case CFG80211_STA_AP_CLIENT:
+       case CFG80211_STA_AP_CLIENT_UNASSOC:
                /* accept only the listed bits */
                if (params->sta_flags_mask &
                                ~(BIT(NL80211_STA_FLAG_AUTHORIZED) |
@@ -9938,6 +9952,9 @@ static int nl80211_vendor_cmd(struct sk_buff *skb, struct genl_info *info)
                                if (!wdev->netdev && !wdev->p2p_started)
                                        return -ENETDOWN;
                        }
+
+                       if (!vcmd->doit)
+                               return -EOPNOTSUPP;
                } else {
                        wdev = NULL;
                }
@@ -9957,6 +9974,193 @@ static int nl80211_vendor_cmd(struct sk_buff *skb, struct genl_info *info)
        return -EOPNOTSUPP;
 }
 
+static int nl80211_prepare_vendor_dump(struct sk_buff *skb,
+                                      struct netlink_callback *cb,
+                                      struct cfg80211_registered_device **rdev,
+                                      struct wireless_dev **wdev)
+{
+       u32 vid, subcmd;
+       unsigned int i;
+       int vcmd_idx = -1;
+       int err;
+       void *data = NULL;
+       unsigned int data_len = 0;
+
+       rtnl_lock();
+
+       if (cb->args[0]) {
+               /* subtract the 1 again here */
+               struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
+               struct wireless_dev *tmp;
+
+               if (!wiphy) {
+                       err = -ENODEV;
+                       goto out_unlock;
+               }
+               *rdev = wiphy_to_rdev(wiphy);
+               *wdev = NULL;
+
+               if (cb->args[1]) {
+                       list_for_each_entry(tmp, &(*rdev)->wdev_list, list) {
+                               if (tmp->identifier == cb->args[1] - 1) {
+                                       *wdev = tmp;
+                                       break;
+                               }
+                       }
+               }
+
+               /* keep rtnl locked in successful case */
+               return 0;
+       }
+
+       err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
+                         nl80211_fam.attrbuf, nl80211_fam.maxattr,
+                         nl80211_policy);
+       if (err)
+               goto out_unlock;
+
+       if (!nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_ID] ||
+           !nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_SUBCMD]) {
+               err = -EINVAL;
+               goto out_unlock;
+       }
+
+       *wdev = __cfg80211_wdev_from_attrs(sock_net(skb->sk),
+                                          nl80211_fam.attrbuf);
+       if (IS_ERR(*wdev))
+               *wdev = NULL;
+
+       *rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk),
+                                          nl80211_fam.attrbuf);
+       if (IS_ERR(*rdev)) {
+               err = PTR_ERR(*rdev);
+               goto out_unlock;
+       }
+
+       vid = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_ID]);
+       subcmd = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_SUBCMD]);
+
+       for (i = 0; i < (*rdev)->wiphy.n_vendor_commands; i++) {
+               const struct wiphy_vendor_command *vcmd;
+
+               vcmd = &(*rdev)->wiphy.vendor_commands[i];
+
+               if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd)
+                       continue;
+
+               if (!vcmd->dumpit) {
+                       err = -EOPNOTSUPP;
+                       goto out_unlock;
+               }
+
+               vcmd_idx = i;
+               break;
+       }
+
+       if (vcmd_idx < 0) {
+               err = -EOPNOTSUPP;
+               goto out_unlock;
+       }
+
+       if (nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_DATA]) {
+               data = nla_data(nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_DATA]);
+               data_len = nla_len(nl80211_fam.attrbuf[NL80211_ATTR_VENDOR_DATA]);
+       }
+
+       /* 0 is the first index - add 1 to parse only once */
+       cb->args[0] = (*rdev)->wiphy_idx + 1;
+       /* add 1 to know if it was NULL */
+       cb->args[1] = *wdev ? (*wdev)->identifier + 1 : 0;
+       cb->args[2] = vcmd_idx;
+       cb->args[3] = (unsigned long)data;
+       cb->args[4] = data_len;
+
+       /* keep rtnl locked in successful case */
+       return 0;
+ out_unlock:
+       rtnl_unlock();
+       return err;
+}
+
+static int nl80211_vendor_cmd_dump(struct sk_buff *skb,
+                                  struct netlink_callback *cb)
+{
+       struct cfg80211_registered_device *rdev;
+       struct wireless_dev *wdev;
+       unsigned int vcmd_idx;
+       const struct wiphy_vendor_command *vcmd;
+       void *data;
+       int data_len;
+       int err;
+       struct nlattr *vendor_data;
+
+       err = nl80211_prepare_vendor_dump(skb, cb, &rdev, &wdev);
+       if (err)
+               return err;
+
+       vcmd_idx = cb->args[2];
+       data = (void *)cb->args[3];
+       data_len = cb->args[4];
+       vcmd = &rdev->wiphy.vendor_commands[vcmd_idx];
+
+       if (vcmd->flags & (WIPHY_VENDOR_CMD_NEED_WDEV |
+                          WIPHY_VENDOR_CMD_NEED_NETDEV)) {
+               if (!wdev)
+                       return -EINVAL;
+               if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_NETDEV &&
+                   !wdev->netdev)
+                       return -EINVAL;
+
+               if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) {
+                       if (wdev->netdev &&
+                           !netif_running(wdev->netdev))
+                               return -ENETDOWN;
+                       if (!wdev->netdev && !wdev->p2p_started)
+                               return -ENETDOWN;
+               }
+       }
+
+       while (1) {
+               void *hdr = nl80211hdr_put(skb, NETLINK_CB(cb->skb).portid,
+                                          cb->nlh->nlmsg_seq, NLM_F_MULTI,
+                                          NL80211_CMD_VENDOR);
+               if (!hdr)
+                       break;
+
+               if (nla_put_u32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
+                   (wdev && nla_put_u64(skb, NL80211_ATTR_WDEV,
+                                        wdev_id(wdev)))) {
+                       genlmsg_cancel(skb, hdr);
+                       break;
+               }
+
+               vendor_data = nla_nest_start(skb, NL80211_ATTR_VENDOR_DATA);
+               if (!vendor_data) {
+                       genlmsg_cancel(skb, hdr);
+                       break;
+               }
+
+               err = vcmd->dumpit(&rdev->wiphy, wdev, skb, data, data_len,
+                                  (unsigned long *)&cb->args[5]);
+               nla_nest_end(skb, vendor_data);
+
+               if (err == -ENOBUFS || err == -ENOENT) {
+                       genlmsg_cancel(skb, hdr);
+                       break;
+               } else if (err) {
+                       genlmsg_cancel(skb, hdr);
+                       goto out;
+               }
+
+               genlmsg_end(skb, hdr);
+       }
+
+       err = skb->len;
+ out:
+       rtnl_unlock();
+       return err;
+}
+
 struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy,
                                           enum nl80211_commands cmd,
                                           enum nl80211_attrs attr,
@@ -10994,6 +11198,7 @@ static const struct genl_ops nl80211_ops[] = {
        {
                .cmd = NL80211_CMD_VENDOR,
                .doit = nl80211_vendor_cmd,
+               .dumpit = nl80211_vendor_cmd_dump,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
                .internal_flags = NL80211_FLAG_NEED_WIPHY |
index 2510b23..7258246 100644 (file)
@@ -1040,8 +1040,8 @@ freq_reg_info_regd(struct wiphy *wiphy, u32 center_freq,
        return ERR_PTR(-EINVAL);
 }
 
-const struct ieee80211_reg_rule *__freq_reg_info(struct wiphy *wiphy,
-                                                u32 center_freq, u32 min_bw)
+static const struct ieee80211_reg_rule *
+__freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 min_bw)
 {
        const struct ieee80211_regdomain *regd = reg_get_regdomain(wiphy);
        const struct ieee80211_reg_rule *reg_rule = NULL;