]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
iwlagn: fix rts cts protection
authorJohannes Berg <johannes.berg@intel.com>
Mon, 9 Aug 2010 17:57:02 +0000 (10:57 -0700)
committerGreg Kroah-Hartman <gregkh@suse.de>
Thu, 26 Aug 2010 23:46:18 +0000 (16:46 -0700)
This is a backport of mainline commit
94597ab23ea10b3bdcba534be00a9f7b35791c07.
I removed the variable renamings from it
and made it apply on 2.6.35. It now also
incorporates some changes from commit
cfecc6b492162fb49209a83dc207f182b87ea27a
since those were required as well.
commit 94597ab23ea10b3bdcba534be00a9f7b35791c07 upstream.

Currently the driver will try to protect all frames,
which leads to a lot of odd things like sending an
RTS with a zeroed RA before multicast frames, which
is clearly bogus.

In order to fix all of this, we need to take a step
back and see what we need to achieve:
 * we need RTS/CTS protection if requested by
   the AP for the BSS, mac80211 tells us this
 * in that case, CTS-to-self should only be
   enabled when mac80211 tells us
 * additionally, as a hardware workaround, on
   some devices we have to protect aggregated
   frames with RTS

To achieve the first two items, set up the RXON
accordingly and set the protection required flag
in the transmit command when mac80211 requests
protection for the frame.

To achieve the last item, set the rate-control
RTS-requested flag for all stations that we have
aggregation sessions with, and set the protection
required flag when sending aggregated frames (on
those devices where this is required).

Since otherwise bugs can occur, do not allow the
user to override the RTS-for-aggregation setting
from sysfs any more.

Finally, also clean up the way all these flags get
set in the driver and move everything into the
device-specific functions.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/net/wireless/iwlwifi/iwl-3945.c
drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
drivers/net/wireless/iwlwifi/iwl-agn-rs.c
drivers/net/wireless/iwlwifi/iwl-agn-tx.c
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-core.c
drivers/net/wireless/iwlwifi/iwl-core.h
drivers/net/wireless/iwlwifi/iwl3945-base.c

index c44a303e62ed45c2bdc9ea9b77db020eb927c39c..2a9480dab2d51ade161ff614e4f5ea4103890a3f 100644 (file)
@@ -915,22 +915,6 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv,
                rts_retry_limit = data_retry_limit;
        tx_cmd->rts_retry_limit = rts_retry_limit;
 
-       if (ieee80211_is_mgmt(fc)) {
-               switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
-               case cpu_to_le16(IEEE80211_STYPE_AUTH):
-               case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
-               case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ):
-               case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ):
-                       if (tx_flags & TX_CMD_FLG_RTS_MSK) {
-                               tx_flags &= ~TX_CMD_FLG_RTS_MSK;
-                               tx_flags |= TX_CMD_FLG_CTS_MSK;
-                       }
-                       break;
-               default:
-                       break;
-               }
-       }
-
        tx_cmd->rate = rate;
        tx_cmd->tx_flags = tx_flags;
 
index 01658cf82d3904dc7cb1dc91bb7bdbf7f3152f85..2a30397ced7de936d18080cacb28ae4a090bd505 100644 (file)
@@ -209,10 +209,21 @@ static void iwlagn_chain_noise_reset(struct iwl_priv *priv)
        }
 }
 
-static void iwlagn_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
-                       __le32 *tx_flags)
+static void iwlagn_rts_tx_cmd_flag(struct iwl_priv *priv,
+                                    struct ieee80211_tx_info *info,
+                                    __le16 fc, __le32 *tx_flags)
 {
-       *tx_flags |= TX_CMD_FLG_RTS_CTS_MSK;
+       if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS ||
+           info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
+               *tx_flags |= TX_CMD_FLG_RTS_CTS_MSK;
+               return;
+       }
+
+       if (priv->cfg->use_rts_for_ht &&
+           info->flags & IEEE80211_TX_CTL_AMPDU) {
+               *tx_flags |= TX_CMD_FLG_RTS_CTS_MSK;
+               return;
+       }
 }
 
 /* Calc max signal level (dBm) among 3 possible receivers */
index cf4a95bae4ffb1369ca5a192919a5caf0445f8cc..ca468312aaf360fdb61a9e8e4f4588b1de2cc808 100644 (file)
@@ -325,18 +325,11 @@ static void rs_tl_turn_on_agg(struct iwl_priv *priv, u8 tid,
                              struct iwl_lq_sta *lq_data,
                              struct ieee80211_sta *sta)
 {
-       if ((tid < TID_MAX_LOAD_COUNT) &&
-           !rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta)) {
-               if (priv->cfg->use_rts_for_ht) {
-                       /*
-                        * switch to RTS/CTS if it is the prefer protection
-                        * method for HT traffic
-                        */
-                       IWL_DEBUG_HT(priv, "use RTS/CTS protection for HT\n");
-                       priv->staging_rxon.flags &= ~RXON_FLG_SELF_CTS_EN;
-                       iwlcore_commit_rxon(priv);
-               }
-       }
+       if (tid < TID_MAX_LOAD_COUNT)
+               rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta);
+       else
+               IWL_ERR(priv, "tid exceeds max load count: %d/%d\n",
+                       tid, TID_MAX_LOAD_COUNT);
 }
 
 static inline int get_num_of_ant_from_rate(u32 rate_n_flags)
index 7d614c4d3c6200d5410bba749105f4d371b2e5b7..3a3d27c20c4241338e36400195b39d04e2d852a8 100644 (file)
@@ -376,10 +376,7 @@ static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv,
                tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
        }
 
-       priv->cfg->ops->utils->rts_tx_cmd_flag(info, &tx_flags);
-
-       if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK))
-               tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
+       priv->cfg->ops->utils->rts_tx_cmd_flag(priv, info, fc, &tx_flags);
 
        tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK);
        if (ieee80211_is_mgmt(fc)) {
@@ -453,21 +450,6 @@ static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv,
        if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE))
                rate_flags |= RATE_MCS_CCK_MSK;
 
-       /* Set up RTS and CTS flags for certain packets */
-       switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
-       case cpu_to_le16(IEEE80211_STYPE_AUTH):
-       case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
-       case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ):
-       case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ):
-               if (tx_cmd->tx_flags & TX_CMD_FLG_RTS_MSK) {
-                       tx_cmd->tx_flags &= ~TX_CMD_FLG_RTS_MSK;
-                       tx_cmd->tx_flags |= TX_CMD_FLG_CTS_MSK;
-               }
-               break;
-       default:
-               break;
-       }
-
        /* Set up antennas */
        priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant);
        rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
index 24aff654fa9c44251b11f3d12ab63d639ea06384..21b03af52aea577242f2b9750f5b8bb1848d8d91 100644 (file)
@@ -200,13 +200,6 @@ int iwl_commit_rxon(struct iwl_priv *priv)
 
        priv->start_calib = 0;
        if (new_assoc) {
-               /*
-                * allow CTS-to-self if possible for new association.
-                * this is relevant only for 5000 series and up,
-                * but will not damage 4965
-                */
-               priv->staging_rxon.flags |= RXON_FLG_SELF_CTS_EN;
-
                /* Apply the new configuration
                 * RXON assoc doesn't clear the station table in uCode,
                 */
@@ -3336,13 +3329,40 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
                        IWL_DEBUG_HT(priv, "priv->_agn.agg_tids_count = %u\n",
                                     priv->_agn.agg_tids_count);
                }
+               if (priv->cfg->use_rts_for_ht) {
+                       struct iwl_station_priv *sta_priv =
+                               (void *) sta->drv_priv;
+                       /*
+                        * switch off RTS/CTS if it was previously enabled
+                        */
+
+                       sta_priv->lq_sta.lq.general_params.flags &=
+                               ~LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK;
+                       iwl_send_lq_cmd(priv, &sta_priv->lq_sta.lq,
+                               CMD_ASYNC, false);
+               }
+               break;
                if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                        return 0;
                else
                        return ret;
        case IEEE80211_AMPDU_TX_OPERATIONAL:
-               /* do nothing */
-               return -EOPNOTSUPP;
+               if (priv->cfg->use_rts_for_ht) {
+                       struct iwl_station_priv *sta_priv =
+                               (void *) sta->drv_priv;
+
+                       /*
+                        * switch to RTS/CTS if it is the prefer protection
+                        * method for HT traffic
+                        */
+
+                       sta_priv->lq_sta.lq.general_params.flags |=
+                               LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK;
+                       iwl_send_lq_cmd(priv, &sta_priv->lq_sta.lq,
+                               CMD_ASYNC, false);
+               }
+               ret = 0;
+               break;
        default:
                IWL_DEBUG_HT(priv, "unknown\n");
                return -EINVAL;
index 5bbc5298ef96e50b29206ea3e5ea8ca408e22695..3d4b650fabce3551a4220174c52a0033070e1b73 100644 (file)
@@ -403,19 +403,36 @@ EXPORT_SYMBOL(iwlcore_free_geos);
  *  iwlcore_rts_tx_cmd_flag: Set rts/cts. 3945 and 4965 only share this
  *  function.
  */
-void iwlcore_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
-                               __le32 *tx_flags)
+void iwlcore_rts_tx_cmd_flag(struct iwl_priv *priv,
+                              struct ieee80211_tx_info *info,
+                              __le16 fc, __le32 *tx_flags)
 {
        if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) {
                *tx_flags |= TX_CMD_FLG_RTS_MSK;
                *tx_flags &= ~TX_CMD_FLG_CTS_MSK;
+               *tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
+
+               if (!ieee80211_is_mgmt(fc))
+                       return;
+
+               switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
+               case cpu_to_le16(IEEE80211_STYPE_AUTH):
+               case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
+               case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ):
+               case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ):
+                       *tx_flags &= ~TX_CMD_FLG_RTS_MSK;
+                       *tx_flags |= TX_CMD_FLG_CTS_MSK;
+                       break;
+               }
        } else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
                *tx_flags &= ~TX_CMD_FLG_RTS_MSK;
                *tx_flags |= TX_CMD_FLG_CTS_MSK;
+               *tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
        }
 }
 EXPORT_SYMBOL(iwlcore_rts_tx_cmd_flag);
 
+
 static bool is_single_rx_stream(struct iwl_priv *priv)
 {
        return priv->current_ht_config.smps == IEEE80211_SMPS_STATIC ||
@@ -1936,6 +1953,10 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
                        priv->staging_rxon.flags |= RXON_FLG_TGG_PROTECT_MSK;
                else
                        priv->staging_rxon.flags &= ~RXON_FLG_TGG_PROTECT_MSK;
+               if (bss_conf->use_cts_prot)
+                       priv->staging_rxon.flags |= RXON_FLG_SELF_CTS_EN;
+               else
+                       priv->staging_rxon.flags &= ~RXON_FLG_SELF_CTS_EN;
        }
 
        if (changes & BSS_CHANGED_BASIC_RATES) {
index 31775bd9c36170faa839da119456fd4cf747a385..ed4a208d0c3e58316adb1cd51dab6158d8ce45d9 100644 (file)
@@ -102,8 +102,9 @@ struct iwl_hcmd_utils_ops {
                        u32 min_average_noise,
                        u8 default_chain);
        void (*chain_noise_reset)(struct iwl_priv *priv);
-       void (*rts_tx_cmd_flag)(struct ieee80211_tx_info *info,
-                       __le32 *tx_flags);
+       void (*rts_tx_cmd_flag)(struct iwl_priv *priv,
+                                 struct ieee80211_tx_info *info,
+                                 __le16 fc, __le32 *tx_flags);
        int  (*calc_rssi)(struct iwl_priv *priv,
                          struct iwl_rx_phy_res *rx_resp);
        void (*request_scan)(struct iwl_priv *priv, struct ieee80211_vif *vif);
@@ -375,8 +376,9 @@ void iwl_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif);
 void iwl_mac_reset_tsf(struct ieee80211_hw *hw);
 int iwl_alloc_txq_mem(struct iwl_priv *priv);
 void iwl_free_txq_mem(struct iwl_priv *priv);
-void iwlcore_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
-                               __le32 *tx_flags);
+void iwlcore_rts_tx_cmd_flag(struct iwl_priv *priv,
+                              struct ieee80211_tx_info *info,
+                              __le16 fc, __le32 *tx_flags);
 #ifdef CONFIG_IWLWIFI_DEBUGFS
 int iwl_alloc_traffic_mem(struct iwl_priv *priv);
 void iwl_free_traffic_mem(struct iwl_priv *priv);
index a27872de41061d62cec0af818aa72f88927396da..0e966fc7c245cb52aa63a828cde5f291cac19a99 100644 (file)
@@ -434,10 +434,7 @@ static void iwl3945_build_tx_cmd_basic(struct iwl_priv *priv,
                tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
        }
 
-       priv->cfg->ops->utils->rts_tx_cmd_flag(info, &tx_flags);
-
-       if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK))
-               tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
+       priv->cfg->ops->utils->rts_tx_cmd_flag(priv, info, fc, &tx_flags);
 
        tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK);
        if (ieee80211_is_mgmt(fc)) {