Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless
authorJohn W. Linville <linville@tuxdriver.com>
Fri, 2 Dec 2011 20:44:03 +0000 (15:44 -0500)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 2 Dec 2011 20:44:03 +0000 (15:44 -0500)
Conflicts:
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/libertas/cfg.c

27 files changed:
1  2 
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/iwlwifi/iwl-1000.c
drivers/net/wireless/iwlwifi/iwl-5000.c
drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
drivers/net/wireless/iwlwifi/iwl-agn-sta.c
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-agn.h
drivers/net/wireless/iwlwifi/iwl-core.c
drivers/net/wireless/iwlwifi/iwl-core.h
drivers/net/wireless/iwlwifi/iwl-shared.h
drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
drivers/net/wireless/libertas/cfg.c
drivers/net/wireless/libertas/if_spi.c
drivers/net/wireless/mwifiex/scan.c
drivers/net/wireless/p54/p54spi.c
drivers/net/wireless/prism54/isl_ioctl.c
drivers/net/wireless/rt2x00/rt2800lib.c
drivers/net/wireless/rtlwifi/ps.c
net/mac80211/agg-tx.c
net/mac80211/debugfs_sta.c
net/mac80211/main.c
net/mac80211/mlme.c
net/mac80211/rx.c
net/mac80211/status.c
net/mac80211/util.c
net/wireless/nl80211.c
net/wireless/reg.c

@@@ -16,7 -16,6 +16,7 @@@
  
  #include <linux/io.h>
  #include <linux/slab.h>
 +#include <linux/module.h>
  #include <asm/unaligned.h>
  
  #include "hw.h"
@@@ -1350,7 -1349,6 +1350,7 @@@ static bool ath9k_hw_set_reset_power_on
  
  static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type)
  {
 +      bool ret = false;
  
        if (AR_SREV_9300_20_OR_LATER(ah)) {
                REG_WRITE(ah, AR_WA, ah->WARegVal);
  
        switch (type) {
        case ATH9K_RESET_POWER_ON:
 -              return ath9k_hw_set_reset_power_on(ah);
 +              ret = ath9k_hw_set_reset_power_on(ah);
 +              break;
        case ATH9K_RESET_WARM:
        case ATH9K_RESET_COLD:
 -              return ath9k_hw_set_reset(ah, type);
 +              ret = ath9k_hw_set_reset(ah, type);
 +              break;
        default:
 -              return false;
 +              break;
        }
 +
 +      if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
 +              REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
 +
 +      return ret;
  }
  
  static bool ath9k_hw_chip_reset(struct ath_hw *ah,
@@@ -1514,7 -1505,6 +1514,7 @@@ int ath9k_hw_reset(struct ath_hw *ah, s
                   struct ath9k_hw_cal_data *caldata, bool bChannelChange)
  {
        struct ath_common *common = ath9k_hw_common(ah);
 +      struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
        u32 saveLedState;
        struct ath9k_channel *curchan = ah->curchan;
        u32 saveDefAntenna;
        u64 tsf = 0;
        int i, r;
        bool allow_fbs = false;
 +      bool mci = !!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI);
 +      bool save_fullsleep = ah->chip_fullsleep;
 +
 +      if (mci) {
 +
 +              ar9003_mci_2g5g_changed(ah, IS_CHAN_2GHZ(chan));
 +
 +              if (mci_hw->bt_state == MCI_BT_CAL_START) {
 +                      u32 payload[4] = {0, 0, 0, 0};
 +
 +                      ath_dbg(common, ATH_DBG_MCI, "MCI stop rx for BT CAL");
 +
 +                      mci_hw->bt_state = MCI_BT_CAL;
 +
 +                      /*
 +                       * MCI FIX: disable mci interrupt here. This is to avoid
 +                       * SW_MSG_DONE or RX_MSG bits to trigger MCI_INT and
 +                       * lead to mci_intr reentry.
 +                       */
 +
 +                      ar9003_mci_disable_interrupt(ah);
 +
 +                      ath_dbg(common, ATH_DBG_MCI, "send WLAN_CAL_GRANT");
 +                      MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_GRANT);
 +                      ar9003_mci_send_message(ah, MCI_GPM, 0, payload,
 +                                              16, true, false);
 +
 +                      ath_dbg(common, ATH_DBG_MCI, "\nMCI BT is calibrating");
 +
 +                      /* Wait BT calibration to be completed for 25ms */
 +
 +                      if (ar9003_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_DONE,
 +                                                                0, 25000))
 +                              ath_dbg(common, ATH_DBG_MCI,
 +                                      "MCI got BT_CAL_DONE\n");
 +                      else
 +                              ath_dbg(common, ATH_DBG_MCI,
 +                                      "MCI ### BT cal takes to long, force"
 +                                      "bt_state to be bt_awake\n");
 +                      mci_hw->bt_state = MCI_BT_AWAKE;
 +                      /* MCI FIX: enable mci interrupt here */
 +                      ar9003_mci_enable_interrupt(ah);
 +
 +                      return true;
 +              }
 +      }
 +
  
        if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
                return -EIO;
                if (ath9k_hw_channel_change(ah, chan)) {
                        ath9k_hw_loadnf(ah, ah->curchan);
                        ath9k_hw_start_nfcal(ah, true);
 +                      if (mci && mci_hw->ready)
 +                              ar9003_mci_2g5g_switch(ah, true);
 +
                        if (AR_SREV_9271(ah))
                                ar9002_hw_load_ani_reg(ah, chan);
                        return 0;
                }
        }
  
 +      if (mci) {
 +              ar9003_mci_disable_interrupt(ah);
 +
 +              if (mci_hw->ready && !save_fullsleep) {
 +                      ar9003_mci_mute_bt(ah);
 +                      udelay(20);
 +                      REG_WRITE(ah, AR_BTCOEX_CTRL, 0);
 +              }
 +
 +              mci_hw->bt_state = MCI_BT_SLEEP;
 +              mci_hw->ready = false;
 +      }
 +
 +
        saveDefAntenna = REG_READ(ah, AR_DEF_ANTENNA);
        if (saveDefAntenna == 0)
                saveDefAntenna = 1;
        if (r)
                return r;
  
 +      if (mci)
 +              ar9003_mci_reset(ah, false, IS_CHAN_2GHZ(chan), save_fullsleep);
 +
        /*
         * Some AR91xx SoC devices frequently fail to accept TSF writes
         * right after the chip reset. When that happens, write a new
        ath9k_hw_loadnf(ah, chan);
        ath9k_hw_start_nfcal(ah, true);
  
 +      if (mci && mci_hw->ready) {
 +
 +              if (IS_CHAN_2GHZ(chan) &&
 +                  (mci_hw->bt_state == MCI_BT_SLEEP)) {
 +
 +                      if (ar9003_mci_check_int(ah,
 +                          AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET) ||
 +                          ar9003_mci_check_int(ah,
 +                          AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)) {
 +
 +                              /*
 +                               * BT is sleeping. Check if BT wakes up during
 +                               * WLAN calibration. If BT wakes up during
 +                               * WLAN calibration, need to go through all
 +                               * message exchanges again and recal.
 +                               */
 +
 +                              ath_dbg(common, ATH_DBG_MCI, "MCI BT wakes up"
 +                                      "during WLAN calibration\n");
 +
 +                              REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW,
 +                                        AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET |
 +                                        AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE);
 +                              ath_dbg(common, ATH_DBG_MCI, "MCI send"
 +                                      "REMOTE_RESET\n");
 +                              ar9003_mci_remote_reset(ah, true);
 +                              ar9003_mci_send_sys_waking(ah, true);
 +                              udelay(1);
 +                              if (IS_CHAN_2GHZ(chan))
 +                                      ar9003_mci_send_lna_transfer(ah, true);
 +
 +                              mci_hw->bt_state = MCI_BT_AWAKE;
 +
 +                              ath_dbg(common, ATH_DBG_MCI, "MCI re-cal\n");
 +
 +                              if (caldata) {
 +                                      caldata->done_txiqcal_once = false;
 +                                      caldata->done_txclcal_once = false;
 +                                      caldata->rtt_hist.num_readings = 0;
 +                              }
 +
 +                              if (!ath9k_hw_init_cal(ah, chan))
 +                                      return -EIO;
 +
 +                      }
 +              }
 +              ar9003_mci_enable_interrupt(ah);
 +      }
 +
        ENABLE_REGWRITE_BUFFER(ah);
  
        ath9k_hw_restore_chainmask(ah);
        if (ah->btcoex_hw.enabled)
                ath9k_hw_btcoex_enable(ah);
  
 +      if (mci && mci_hw->ready) {
 +              /*
 +               * check BT state again to make
 +               * sure it's not changed.
 +               */
 +
 +              ar9003_mci_sync_bt_state(ah);
 +              ar9003_mci_2g5g_switch(ah, true);
 +
 +              if ((mci_hw->bt_state == MCI_BT_AWAKE) &&
 +                              (mci_hw->query_bt == true)) {
 +                      mci_hw->need_flush_btinfo = true;
 +              }
 +      }
 +
        if (AR_SREV_9300_20_OR_LATER(ah)) {
                ar9003_hw_bb_watchdog_config(ah);
  
@@@ -1967,7 -1826,8 +1967,8 @@@ static void ath9k_set_power_sleep(struc
        }
  
        /* Clear Bit 14 of AR_WA after putting chip into Full Sleep mode. */
-       REG_WRITE(ah, AR_WA, ah->WARegVal & ~AR_WA_D3_L1_DISABLE);
+       if (AR_SREV_9300_20_OR_LATER(ah))
+               REG_WRITE(ah, AR_WA, ah->WARegVal & ~AR_WA_D3_L1_DISABLE);
  }
  
  /*
@@@ -2073,7 -1933,6 +2074,7 @@@ static bool ath9k_hw_set_power_awake(st
  bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
  {
        struct ath_common *common = ath9k_hw_common(ah);
 +      struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
        int status = true, setChip = true;
        static const char *modes[] = {
                "AWAKE",
        switch (mode) {
        case ATH9K_PM_AWAKE:
                status = ath9k_hw_set_power_awake(ah, setChip);
 +
 +              if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
 +                      REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
 +
                break;
        case ATH9K_PM_FULL_SLEEP:
 +
 +              if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI) {
 +                      if (ar9003_mci_state(ah, MCI_STATE_ENABLE, NULL) &&
 +                              (mci->bt_state != MCI_BT_SLEEP) &&
 +                              !mci->halted_bt_gpm) {
 +                              ath_dbg(common, ATH_DBG_MCI, "MCI halt BT GPM"
 +                                              "(full_sleep)");
 +                              ar9003_mci_send_coex_halt_bt_gpm(ah,
 +                                                               true, true);
 +                      }
 +
 +                      mci->ready = false;
 +                      REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
 +              }
 +
                ath9k_set_power_sleep(ah, setChip);
                ah->chip_fullsleep = true;
                break;
        case ATH9K_PM_NETWORK_SLEEP:
 +
 +              if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
 +                      REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2);
 +
                ath9k_set_power_network_sleep(ah, setChip);
                break;
        default:
@@@ -2312,8 -2148,6 +2313,8 @@@ int ath9k_hw_fill_cap_info(struct ath_h
  
        if (AR_SREV_9485(ah) || AR_SREV_9285(ah) || AR_SREV_9330(ah))
                chip_chainmask = 1;
 +      else if (AR_SREV_9462(ah))
 +              chip_chainmask = 3;
        else if (!AR_SREV_9280_20_OR_LATER(ah))
                chip_chainmask = 7;
        else if (!AR_SREV_9300_20_OR_LATER(ah) || AR_SREV_9340(ah))
                pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS;
  
        if (common->btcoex_enabled) {
 -              if (AR_SREV_9300_20_OR_LATER(ah)) {
 +              if (AR_SREV_9462(ah))
 +                      btcoex_hw->scheme = ATH_BTCOEX_CFG_MCI;
 +              else if (AR_SREV_9300_20_OR_LATER(ah)) {
                        btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE;
                        btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9300;
                        btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9300;
  
        if (AR_SREV_9300_20_OR_LATER(ah)) {
                ah->enabled_cals |= TX_IQ_CAL;
 -              if (!AR_SREV_9330(ah))
 +              if (AR_SREV_9485_OR_LATER(ah))
                        ah->enabled_cals |= TX_IQ_ON_AGC_CAL;
        }
        if (AR_SREV_9462(ah))
 -              pCap->hw_caps |= ATH9K_HW_CAP_RTT;
 +              pCap->hw_caps |= ATH9K_HW_CAP_RTT | ATH9K_HW_CAP_MCI;
  
        return 0;
  }
@@@ -2751,7 -2583,7 +2752,7 @@@ void ath9k_hw_set_txpowerlimit(struct a
        struct ath9k_channel *chan = ah->curchan;
        struct ieee80211_channel *channel = chan->chan;
  
 -      reg->power_limit = min_t(int, limit, MAX_RATE_POWER);
 +      reg->power_limit = min_t(u32, limit, MAX_RATE_POWER);
        if (test)
                channel->max_power = MAX_RATE_POWER / 2;
  
@@@ -147,7 -147,16 +147,7 @@@ static int iwl1000_hw_set_hw_params(str
        iwl1000_set_ct_threshold(priv);
  
        /* Set initial sensitivity parameters */
 -      /* Set initial calibration set */
        hw_params(priv).sens = &iwl1000_sensitivity;
 -      hw_params(priv).calib_init_cfg =
 -                      BIT(IWL_CALIB_XTAL)             |
 -                      BIT(IWL_CALIB_LO)               |
 -                      BIT(IWL_CALIB_TX_IQ)            |
 -                      BIT(IWL_CALIB_TX_IQ_PERD)       |
 -                      BIT(IWL_CALIB_BASE_BAND);
 -      if (priv->cfg->need_dc_calib)
 -              hw_params(priv).calib_init_cfg |= BIT(IWL_CALIB_DC);
  
        return 0;
  }
@@@ -182,6 -191,7 +182,7 @@@ static struct iwl_base_params iwl1000_b
        .chain_noise_scale = 1000,
        .wd_timeout = IWL_DEF_WD_TIMEOUT,
        .max_event_log_size = 128,
+       .wd_disable = true,
  };
  static struct iwl_ht_params iwl1000_ht_params = {
        .ht_greenfield_support = true,
@@@ -186,7 -186,14 +186,7 @@@ static int iwl5000_hw_set_hw_params(str
        iwl5000_set_ct_threshold(priv);
  
        /* Set initial sensitivity parameters */
 -      /* Set initial calibration set */
        hw_params(priv).sens = &iwl5000_sensitivity;
 -      hw_params(priv).calib_init_cfg =
 -              BIT(IWL_CALIB_XTAL)             |
 -              BIT(IWL_CALIB_LO)               |
 -              BIT(IWL_CALIB_TX_IQ)            |
 -              BIT(IWL_CALIB_TX_IQ_PERD)       |
 -              BIT(IWL_CALIB_BASE_BAND);
  
        return 0;
  }
@@@ -215,7 -222,14 +215,7 @@@ static int iwl5150_hw_set_hw_params(str
        iwl5150_set_ct_threshold(priv);
  
        /* Set initial sensitivity parameters */
 -      /* Set initial calibration set */
        hw_params(priv).sens = &iwl5150_sensitivity;
 -      hw_params(priv).calib_init_cfg =
 -              BIT(IWL_CALIB_LO)               |
 -              BIT(IWL_CALIB_TX_IQ)            |
 -              BIT(IWL_CALIB_BASE_BAND);
 -      if (priv->cfg->need_dc_calib)
 -              hw_params(priv).calib_init_cfg |= BIT(IWL_CALIB_DC);
  
        return 0;
  }
@@@ -350,6 -364,7 +350,7 @@@ static struct iwl_base_params iwl5000_b
        .wd_timeout = IWL_LONG_WD_TIMEOUT,
        .max_event_log_size = 512,
        .no_idle_support = true,
+       .wd_disable = true,
  };
  static struct iwl_ht_params iwl5000_ht_params = {
        .ht_greenfield_support = true,
@@@ -419,7 -434,7 +420,7 @@@ struct iwl_cfg iwl5350_agn_cfg = 
        .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,       \
        .lib = &iwl5150_lib,                                    \
        .base_params = &iwl5000_base_params,                    \
 -      .need_dc_calib = true,                                  \
 +      .no_xtal_calib = true,                                  \
        .led_mode = IWL_LED_BLINK,                              \
        .internal_wimax_coex = true
  
@@@ -45,8 -45,7 +45,8 @@@ static int iwlagn_disable_bss(struct iw
        send->filter_flags = old_filter;
  
        if (ret)
 -              IWL_ERR(priv, "Error clearing ASSOC_MSK on BSS (%d)\n", ret);
 +              IWL_DEBUG_QUIET_RFKILL(priv,
 +                      "Error clearing ASSOC_MSK on BSS (%d)\n", ret);
  
        return ret;
  }
@@@ -117,7 -116,7 +117,7 @@@ static void iwlagn_update_qos(struct iw
        if (ctx->ht.enabled)
                ctx->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK;
  
 -      IWL_DEBUG_QOS(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n",
 +      IWL_DEBUG_INFO(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n",
                      ctx->qos_data.qos_active,
                      ctx->qos_data.def_qos_parm.qos_flags);
  
                               sizeof(struct iwl_qosparam_cmd),
                               &ctx->qos_data.def_qos_parm);
        if (ret)
 -              IWL_ERR(priv, "Failed to update QoS\n");
 +              IWL_DEBUG_QUIET_RFKILL(priv, "Failed to update QoS\n");
  }
  
  static int iwlagn_update_beacon(struct iwl_priv *priv,
@@@ -529,6 -528,24 +529,24 @@@ int iwlagn_commit_rxon(struct iwl_priv 
        return 0;
  }
  
+ void iwlagn_config_ht40(struct ieee80211_conf *conf,
+       struct iwl_rxon_context *ctx)
+ {
+       if (conf_is_ht40_minus(conf)) {
+               ctx->ht.extension_chan_offset =
+                       IEEE80211_HT_PARAM_CHA_SEC_BELOW;
+               ctx->ht.is_40mhz = true;
+       } else if (conf_is_ht40_plus(conf)) {
+               ctx->ht.extension_chan_offset =
+                       IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+               ctx->ht.is_40mhz = true;
+       } else {
+               ctx->ht.extension_chan_offset =
+                       IEEE80211_HT_PARAM_CHA_SEC_NONE;
+               ctx->ht.is_40mhz = false;
+       }
+ }
  int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed)
  {
        struct iwl_priv *priv = hw->priv;
  
        mutex_lock(&priv->shrd->mutex);
  
 +      if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
 +              goto out;
 +
        if (unlikely(test_bit(STATUS_SCANNING, &priv->shrd->status))) {
                IWL_DEBUG_MAC80211(priv, "leave - scanning\n");
                goto out;
                                ctx->ht.enabled = conf_is_ht(conf);
  
                        if (ctx->ht.enabled) {
-                               if (conf_is_ht40_minus(conf)) {
-                                       ctx->ht.extension_chan_offset =
-                                               IEEE80211_HT_PARAM_CHA_SEC_BELOW;
-                                       ctx->ht.is_40mhz = true;
-                               } else if (conf_is_ht40_plus(conf)) {
-                                       ctx->ht.extension_chan_offset =
-                                               IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
-                                       ctx->ht.is_40mhz = true;
-                               } else {
-                                       ctx->ht.extension_chan_offset =
-                                               IEEE80211_HT_PARAM_CHA_SEC_NONE;
-                                       ctx->ht.is_40mhz = false;
-                               }
+                               /* if HT40 is used, it should not change
+                                * after associated except channel switch */
+                               if (iwl_is_associated_ctx(ctx) &&
+                                    !ctx->ht.is_40mhz)
+                                       iwlagn_config_ht40(conf, ctx);
                        } else
                                ctx->ht.is_40mhz = false;
  
@@@ -844,8 -850,7 +854,8 @@@ void iwlagn_bss_info_changed(struct iee
                        if (ctx->last_tx_rejected) {
                                ctx->last_tx_rejected = false;
                                iwl_trans_wake_any_queue(trans(priv),
 -                                                       ctx->ctxid);
 +                                                       ctx->ctxid,
 +                                                       "Disassoc: flush queue");
                        }
                        ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
  
@@@ -647,7 -647,7 +647,7 @@@ void iwl_reprogram_ap_sta(struct iwl_pr
        int ret;
        struct iwl_addsta_cmd sta_cmd;
        struct iwl_link_quality_cmd lq;
 -      bool active;
 +      bool active, have_lq = false;
  
        spin_lock_irqsave(&priv->shrd->sta_lock, flags);
        if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) {
  
        memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(sta_cmd));
        sta_cmd.mode = 0;
 -      memcpy(&lq, priv->stations[sta_id].lq, sizeof(lq));
 +      if (priv->stations[sta_id].lq) {
 +              memcpy(&lq, priv->stations[sta_id].lq, sizeof(lq));
 +              have_lq = true;
 +      }
  
        active = priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE;
        priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE;
        if (ret)
                IWL_ERR(priv, "failed to re-add STA %pM (%d)\n",
                        priv->stations[sta_id].sta.sta.addr, ret);
 -      iwl_send_lq_cmd(priv, ctx, &lq, CMD_SYNC, true);
 +      if (have_lq)
 +              iwl_send_lq_cmd(priv, ctx, &lq, CMD_SYNC, true);
  }
  
  int iwl_get_free_ucode_key_offset(struct iwl_priv *priv)
@@@ -829,6 -825,28 +829,6 @@@ int iwl_send_lq_cmd(struct iwl_priv *pr
        return ret;
  }
  
 -int iwlagn_mac_sta_remove(struct ieee80211_hw *hw,
 -                     struct ieee80211_vif *vif,
 -                     struct ieee80211_sta *sta)
 -{
 -      struct iwl_priv *priv = hw->priv;
 -      struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
 -      int ret;
 -
 -      IWL_DEBUG_MAC80211(priv, "enter: received request to remove "
 -                         "station %pM\n", sta->addr);
 -      mutex_lock(&priv->shrd->mutex);
 -      IWL_DEBUG_INFO(priv, "proceeding to remove station %pM\n",
 -                      sta->addr);
 -      ret = iwl_remove_station(priv, sta_priv->sta_id, sta->addr);
 -      if (ret)
 -              IWL_ERR(priv, "Error removing station %pM\n",
 -                      sta->addr);
 -      mutex_unlock(&priv->shrd->mutex);
 -      IWL_DEBUG_MAC80211(priv, "leave\n");
 -
 -      return ret;
 -}
  
  void iwl_sta_fill_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
                     u8 sta_id, struct iwl_link_quality_cmd *link_cmd)
@@@ -1250,9 -1268,6 +1250,6 @@@ int iwl_set_dynamic_key(struct iwl_pri
  
        switch (keyconf->cipher) {
        case WLAN_CIPHER_SUITE_TKIP:
-               keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
-               keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
                if (sta)
                        addr = sta->addr;
                else /* station mode case only */
                                          seq.tkip.iv32, p1k, CMD_SYNC);
                break;
        case WLAN_CIPHER_SUITE_CCMP:
-               keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
-               /* fall through */
        case WLAN_CIPHER_SUITE_WEP40:
        case WLAN_CIPHER_SUITE_WEP104:
                ret = iwlagn_send_sta_key(priv, keyconf, sta_id,
@@@ -1446,7 -1459,20 +1441,7 @@@ int iwl_sta_rx_agg_stop(struct iwl_pri
        return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
  }
  
 -static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
 -{
 -      unsigned long flags;
  
 -      spin_lock_irqsave(&priv->shrd->sta_lock, flags);
 -      priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK;
 -      priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK;
 -      priv->stations[sta_id].sta.sta.modify_mask = 0;
 -      priv->stations[sta_id].sta.sleep_tx_count = 0;
 -      priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
 -      iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
 -      spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
 -
 -}
  
  void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt)
  {
        spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
  
  }
 -
 -void iwlagn_mac_sta_notify(struct ieee80211_hw *hw,
 -                         struct ieee80211_vif *vif,
 -                         enum sta_notify_cmd cmd,
 -                         struct ieee80211_sta *sta)
 -{
 -      struct iwl_priv *priv = hw->priv;
 -      struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
 -      int sta_id;
 -
 -      IWL_DEBUG_MAC80211(priv, "enter\n");
 -
 -      switch (cmd) {
 -      case STA_NOTIFY_SLEEP:
 -              WARN_ON(!sta_priv->client);
 -              sta_priv->asleep = true;
 -              if (atomic_read(&sta_priv->pending_frames) > 0)
 -                      ieee80211_sta_block_awake(hw, sta, true);
 -              break;
 -      case STA_NOTIFY_AWAKE:
 -              WARN_ON(!sta_priv->client);
 -              if (!sta_priv->asleep)
 -                      break;
 -              sta_priv->asleep = false;
 -              sta_id = iwl_sta_id(sta);
 -              if (sta_id != IWL_INVALID_STATION)
 -                      iwl_sta_modify_ps_wake(priv, sta_id);
 -              break;
 -      default:
 -              break;
 -      }
 -      IWL_DEBUG_MAC80211(priv, "leave\n");
 -}
@@@ -30,6 -30,7 +30,6 @@@
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/slab.h>
 -#include <linux/dma-mapping.h>
  #include <linux/delay.h>
  #include <linux/sched.h>
  #include <linux/skbuff.h>
@@@ -451,6 -452,52 +451,6 @@@ static void iwl_bg_tx_flush(struct work
        iwlagn_dev_txfifo_flush(priv, IWL_DROP_ALL);
  }
  
 -/******************************************************************************
 - *
 - * uCode download functions
 - *
 - ******************************************************************************/
 -
 -static void iwl_free_fw_desc(struct iwl_priv *priv, struct fw_desc *desc)
 -{
 -      if (desc->v_addr)
 -              dma_free_coherent(bus(priv)->dev, desc->len,
 -                                desc->v_addr, desc->p_addr);
 -      desc->v_addr = NULL;
 -      desc->len = 0;
 -}
 -
 -static void iwl_free_fw_img(struct iwl_priv *priv, struct fw_img *img)
 -{
 -      iwl_free_fw_desc(priv, &img->code);
 -      iwl_free_fw_desc(priv, &img->data);
 -}
 -
 -static void iwl_dealloc_ucode(struct iwl_priv *priv)
 -{
 -      iwl_free_fw_img(priv, &priv->ucode_rt);
 -      iwl_free_fw_img(priv, &priv->ucode_init);
 -      iwl_free_fw_img(priv, &priv->ucode_wowlan);
 -}
 -
 -static int iwl_alloc_fw_desc(struct iwl_priv *priv, struct fw_desc *desc,
 -                           const void *data, size_t len)
 -{
 -      if (!len) {
 -              desc->v_addr = NULL;
 -              return -EINVAL;
 -      }
 -
 -      desc->v_addr = dma_alloc_coherent(bus(priv)->dev, len,
 -                                        &desc->p_addr, GFP_KERNEL);
 -      if (!desc->v_addr)
 -              return -ENOMEM;
 -
 -      desc->len = len;
 -      memcpy(desc->v_addr, data, len);
 -      return 0;
 -}
 -
  static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
  {
        int i;
        BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
  }
  
 -
 -struct iwlagn_ucode_capabilities {
 -      u32 max_probe_length;
 -      u32 standard_phy_calibration_size;
 -      u32 flags;
 -};
 -
  static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context);
 -static int iwlagn_mac_setup_register(struct iwl_priv *priv,
 -                                struct iwlagn_ucode_capabilities *capa);
  
  #define UCODE_EXPERIMENTAL_INDEX      100
  #define UCODE_EXPERIMENTAL_TAG                "exp"
@@@ -984,32 -1040,30 +984,32 @@@ static void iwl_ucode_callback(const st
        /* Runtime instructions and 2 copies of data:
         * 1) unmodified from disk
         * 2) backup cache for save/restore during power-downs */
 -      if (iwl_alloc_fw_desc(priv, &priv->ucode_rt.code,
 +      if (iwl_alloc_fw_desc(bus(priv), &trans(priv)->ucode_rt.code,
                              pieces.inst, pieces.inst_size))
                goto err_pci_alloc;
 -      if (iwl_alloc_fw_desc(priv, &priv->ucode_rt.data,
 +      if (iwl_alloc_fw_desc(bus(priv), &trans(priv)->ucode_rt.data,
                              pieces.data, pieces.data_size))
                goto err_pci_alloc;
  
        /* Initialization instructions and data */
        if (pieces.init_size && pieces.init_data_size) {
 -              if (iwl_alloc_fw_desc(priv, &priv->ucode_init.code,
 +              if (iwl_alloc_fw_desc(bus(priv), &trans(priv)->ucode_init.code,
                                      pieces.init, pieces.init_size))
                        goto err_pci_alloc;
 -              if (iwl_alloc_fw_desc(priv, &priv->ucode_init.data,
 +              if (iwl_alloc_fw_desc(bus(priv), &trans(priv)->ucode_init.data,
                                      pieces.init_data, pieces.init_data_size))
                        goto err_pci_alloc;
        }
  
        /* WoWLAN instructions and data */
        if (pieces.wowlan_inst_size && pieces.wowlan_data_size) {
 -              if (iwl_alloc_fw_desc(priv, &priv->ucode_wowlan.code,
 +              if (iwl_alloc_fw_desc(bus(priv),
 +                                    &trans(priv)->ucode_wowlan.code,
                                      pieces.wowlan_inst,
                                      pieces.wowlan_inst_size))
                        goto err_pci_alloc;
 -              if (iwl_alloc_fw_desc(priv, &priv->ucode_wowlan.data,
 +              if (iwl_alloc_fw_desc(bus(priv),
 +                                    &trans(priv)->ucode_wowlan.data,
                                      pieces.wowlan_data,
                                      pieces.wowlan_data_size))
                        goto err_pci_alloc;
  
   err_pci_alloc:
        IWL_ERR(priv, "failed to allocate pci memory\n");
 -      iwl_dealloc_ucode(priv);
 +      iwl_dealloc_ucode(trans(priv));
   out_unbind:
        complete(&priv->firmware_loading_complete);
        device_release_driver(bus(priv)->dev);
@@@ -1298,7 -1352,7 +1298,7 @@@ int iwl_alive_start(struct iwl_priv *pr
  
  static void iwl_cancel_deferred_work(struct iwl_priv *priv);
  
 -static void __iwl_down(struct iwl_priv *priv)
 +void __iwl_down(struct iwl_priv *priv)
  {
        int exit_pending;
  
        priv->beacon_skb = NULL;
  }
  
 -static void iwl_down(struct iwl_priv *priv)
 +void iwl_down(struct iwl_priv *priv)
  {
        mutex_lock(&priv->shrd->mutex);
        __iwl_down(priv);
        iwl_cancel_deferred_work(priv);
  }
  
 -#define MAX_HW_RESTARTS 5
 -
 -static int __iwl_up(struct iwl_priv *priv)
 -{
 -      struct iwl_rxon_context *ctx;
 -      int ret;
 -
 -      lockdep_assert_held(&priv->shrd->mutex);
 -
 -      if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) {
 -              IWL_WARN(priv, "Exit pending; will not bring the NIC up\n");
 -              return -EIO;
 -      }
 -
 -      for_each_context(priv, ctx) {
 -              ret = iwlagn_alloc_bcast_station(priv, ctx);
 -              if (ret) {
 -                      iwl_dealloc_bcast_stations(priv);
 -                      return ret;
 -              }
 -      }
 -
 -      ret = iwlagn_run_init_ucode(priv);
 -      if (ret) {
 -              IWL_ERR(priv, "Failed to run INIT ucode: %d\n", ret);
 -              goto error;
 -      }
 -
 -      ret = iwlagn_load_ucode_wait_alive(priv,
 -                                         &priv->ucode_rt,
 -                                         IWL_UCODE_REGULAR);
 -      if (ret) {
 -              IWL_ERR(priv, "Failed to start RT ucode: %d\n", ret);
 -              goto error;
 -      }
 -
 -      ret = iwl_alive_start(priv);
 -      if (ret)
 -              goto error;
 -      return 0;
 -
 - error:
 -      set_bit(STATUS_EXIT_PENDING, &priv->shrd->status);
 -      __iwl_down(priv);
 -      clear_bit(STATUS_EXIT_PENDING, &priv->shrd->status);
 -
 -      IWL_ERR(priv, "Unable to initialize device.\n");
 -      return ret;
 -}
 -
 -
  /*****************************************************************************
   *
   * Workqueue callbacks
@@@ -1397,7 -1502,7 +1397,7 @@@ static void iwl_bg_run_time_calib_work(
        mutex_unlock(&priv->shrd->mutex);
  }
  
 -static void iwlagn_prepare_restart(struct iwl_priv *priv)
 +void iwlagn_prepare_restart(struct iwl_priv *priv)
  {
        struct iwl_rxon_context *ctx;
        bool bt_full_concurrent;
@@@ -1454,182 -1559,1498 +1454,182 @@@ static void iwl_bg_restart(struct work_
        }
  }
  
 -/*****************************************************************************
 - *
 - * mac80211 entry point functions
 - *
 - *****************************************************************************/
 -
 -static const struct ieee80211_iface_limit iwlagn_sta_ap_limits[] = {
 -      {
 -              .max = 1,
 -              .types = BIT(NL80211_IFTYPE_STATION),
 -      },
 -      {
 -              .max = 1,
 -              .types = BIT(NL80211_IFTYPE_AP),
 -      },
 -};
 -
 -static const struct ieee80211_iface_limit iwlagn_2sta_limits[] = {
 -      {
 -              .max = 2,
 -              .types = BIT(NL80211_IFTYPE_STATION),
 -      },
 -};
 -
 -static const struct ieee80211_iface_limit iwlagn_p2p_sta_go_limits[] = {
 -      {
 -              .max = 1,
 -              .types = BIT(NL80211_IFTYPE_STATION),
 -      },
 -      {
 -              .max = 1,
 -              .types = BIT(NL80211_IFTYPE_P2P_GO) |
 -                       BIT(NL80211_IFTYPE_AP),
 -      },
 -};
 -
 -static const struct ieee80211_iface_limit iwlagn_p2p_2sta_limits[] = {
 -      {
 -              .max = 2,
 -              .types = BIT(NL80211_IFTYPE_STATION),
 -      },
 -      {
 -              .max = 1,
 -              .types = BIT(NL80211_IFTYPE_P2P_CLIENT),
 -      },
 -};
  
 -static const struct ieee80211_iface_combination
 -iwlagn_iface_combinations_dualmode[] = {
 -      { .num_different_channels = 1,
 -        .max_interfaces = 2,
 -        .beacon_int_infra_match = true,
 -        .limits = iwlagn_sta_ap_limits,
 -        .n_limits = ARRAY_SIZE(iwlagn_sta_ap_limits),
 -      },
 -      { .num_different_channels = 1,
 -        .max_interfaces = 2,
 -        .limits = iwlagn_2sta_limits,
 -        .n_limits = ARRAY_SIZE(iwlagn_2sta_limits),
 -      },
 -};
  
 -static const struct ieee80211_iface_combination
 -iwlagn_iface_combinations_p2p[] = {
 -      { .num_different_channels = 1,
 -        .max_interfaces = 2,
 -        .beacon_int_infra_match = true,
 -        .limits = iwlagn_p2p_sta_go_limits,
 -        .n_limits = ARRAY_SIZE(iwlagn_p2p_sta_go_limits),
 -      },
 -      { .num_different_channels = 1,
 -        .max_interfaces = 2,
 -        .limits = iwlagn_p2p_2sta_limits,
 -        .n_limits = ARRAY_SIZE(iwlagn_p2p_2sta_limits),
 -      },
 -};
  
 -/*
 - * Not a mac80211 entry point function, but it fits in with all the
 - * other mac80211 functions grouped here.
 - */
 -static int iwlagn_mac_setup_register(struct iwl_priv *priv,
 -                                struct iwlagn_ucode_capabilities *capa)
 +void iwlagn_disable_roc(struct iwl_priv *priv)
  {
 -      int ret;
 -      struct ieee80211_hw *hw = priv->hw;
 -      struct iwl_rxon_context *ctx;
 -
 -      hw->rate_control_algorithm = "iwl-agn-rs";
 -
 -      /* Tell mac80211 our characteristics */
 -      hw->flags = IEEE80211_HW_SIGNAL_DBM |
 -                  IEEE80211_HW_AMPDU_AGGREGATION |
 -                  IEEE80211_HW_NEED_DTIM_PERIOD |
 -                  IEEE80211_HW_SPECTRUM_MGMT |
 -                  IEEE80211_HW_REPORTS_TX_ACK_STATUS;
 -
 -      /*
 -       * Including the following line will crash some AP's.  This
 -       * workaround removes the stimulus which causes the crash until
 -       * the AP software can be fixed.
 -      hw->max_tx_aggregation_subframes = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
 -       */
 -
 -      hw->flags |= IEEE80211_HW_SUPPORTS_PS |
 -                   IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
 -
 -      if (priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE)
 -              hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
 -                           IEEE80211_HW_SUPPORTS_STATIC_SMPS;
 -
 -      if (capa->flags & IWL_UCODE_TLV_FLAGS_MFP)
 -              hw->flags |= IEEE80211_HW_MFP_CAPABLE;
 -
 -      hw->sta_data_size = sizeof(struct iwl_station_priv);
 -      hw->vif_data_size = sizeof(struct iwl_vif_priv);
 -
 -      for_each_context(priv, ctx) {
 -              hw->wiphy->interface_modes |= ctx->interface_modes;
 -              hw->wiphy->interface_modes |= ctx->exclusive_interface_modes;
 -      }
 -
 -      BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
 -
 -      if (hw->wiphy->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT)) {
 -              hw->wiphy->iface_combinations = iwlagn_iface_combinations_p2p;
 -              hw->wiphy->n_iface_combinations =
 -                      ARRAY_SIZE(iwlagn_iface_combinations_p2p);
 -      } else if (hw->wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) {
 -              hw->wiphy->iface_combinations = iwlagn_iface_combinations_dualmode;
 -              hw->wiphy->n_iface_combinations =
 -                      ARRAY_SIZE(iwlagn_iface_combinations_dualmode);
 -      }
 -
 -      hw->wiphy->max_remain_on_channel_duration = 1000;
 -
 -      hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
 -                          WIPHY_FLAG_DISABLE_BEACON_HINTS |
 -                          WIPHY_FLAG_IBSS_RSN;
 -
 -      if (priv->ucode_wowlan.code.len && device_can_wakeup(bus(priv)->dev)) {
 -              hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
 -                                        WIPHY_WOWLAN_DISCONNECT |
 -                                        WIPHY_WOWLAN_EAP_IDENTITY_REQ |
 -                                        WIPHY_WOWLAN_RFKILL_RELEASE;
 -              if (!iwlagn_mod_params.sw_crypto)
 -                      hw->wiphy->wowlan.flags |=
 -                              WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
 -                              WIPHY_WOWLAN_GTK_REKEY_FAILURE;
 -
 -              hw->wiphy->wowlan.n_patterns = IWLAGN_WOWLAN_MAX_PATTERNS;
 -              hw->wiphy->wowlan.pattern_min_len =
 -                                      IWLAGN_WOWLAN_MIN_PATTERN_LEN;
 -              hw->wiphy->wowlan.pattern_max_len =
 -                                      IWLAGN_WOWLAN_MAX_PATTERN_LEN;
 -      }
 -
 -      if (iwlagn_mod_params.power_save)
 -              hw->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
 -      else
 -              hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
 +      struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN];
  
 -      hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
 -      /* we create the 802.11 header and a zero-length SSID element */
 -      hw->wiphy->max_scan_ie_len = capa->max_probe_length - 24 - 2;
 +      lockdep_assert_held(&priv->shrd->mutex);
  
 -      /* Default value; 4 EDCA QOS priorities */
 -      hw->queues = 4;
 +      if (!priv->hw_roc_setup)
 +              return;
  
 -      hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL;
 +      ctx->staging.dev_type = RXON_DEV_TYPE_P2P;
 +      ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
  
 -      if (priv->bands[IEEE80211_BAND_2GHZ].n_channels)
 -              priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
 -                      &priv->bands[IEEE80211_BAND_2GHZ];
 -      if (priv->bands[IEEE80211_BAND_5GHZ].n_channels)
 -              priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
 -                      &priv->bands[IEEE80211_BAND_5GHZ];
 +      priv->hw_roc_channel = NULL;
  
 -      iwl_leds_init(priv);
 +      memset(ctx->staging.node_addr, 0, ETH_ALEN);
  
 -      ret = ieee80211_register_hw(priv->hw);
 -      if (ret) {
 -              IWL_ERR(priv, "Failed to register hw (error %d)\n", ret);
 -              return ret;
 -      }
 -      priv->mac80211_registered = 1;
 +      iwlagn_commit_rxon(priv, ctx);
  
 -      return 0;
 +      ctx->is_active = false;
 +      priv->hw_roc_setup = false;
  }
  
 -
 -static int iwlagn_mac_start(struct ieee80211_hw *hw)
 +static void iwlagn_disable_roc_work(struct work_struct *work)
  {
 -      struct iwl_priv *priv = hw->priv;
 -      int ret;
 -
 -      IWL_DEBUG_MAC80211(priv, "enter\n");
 +      struct iwl_priv *priv = container_of(work, struct iwl_priv,
 +                                           hw_roc_disable_work.work);
  
 -      /* we should be verifying the device is ready to be opened */
        mutex_lock(&priv->shrd->mutex);
 -      ret = __iwl_up(priv);
 +      iwlagn_disable_roc(priv);
        mutex_unlock(&priv->shrd->mutex);
 -      if (ret)
 -              return ret;
 -
 -      IWL_DEBUG_INFO(priv, "Start UP work done.\n");
 -
 -      /* Now we should be done, and the READY bit should be set. */
 -      if (WARN_ON(!test_bit(STATUS_READY, &priv->shrd->status)))
 -              ret = -EIO;
 -
 -      iwlagn_led_enable(priv);
 -
 -      priv->is_open = 1;
 -      IWL_DEBUG_MAC80211(priv, "leave\n");
 -      return 0;
  }
  
 -static void iwlagn_mac_stop(struct ieee80211_hw *hw)
 +/*****************************************************************************
 + *
 + * driver setup and teardown
 + *
 + *****************************************************************************/
 +
 +static void iwl_setup_deferred_work(struct iwl_priv *priv)
  {
 -      struct iwl_priv *priv = hw->priv;
 +      priv->shrd->workqueue = create_singlethread_workqueue(DRV_NAME);
  
 -      IWL_DEBUG_MAC80211(priv, "enter\n");
 +      init_waitqueue_head(&priv->shrd->wait_command_queue);
  
 -      if (!priv->is_open)
 -              return;
 +      INIT_WORK(&priv->restart, iwl_bg_restart);
 +      INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update);
 +      INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work);
 +      INIT_WORK(&priv->tx_flush, iwl_bg_tx_flush);
 +      INIT_WORK(&priv->bt_full_concurrency, iwl_bg_bt_full_concurrency);
 +      INIT_WORK(&priv->bt_runtime_config, iwl_bg_bt_runtime_config);
 +      INIT_DELAYED_WORK(&priv->hw_roc_disable_work,
 +                        iwlagn_disable_roc_work);
  
 -      priv->is_open = 0;
 +      iwl_setup_scan_deferred_work(priv);
  
 -      iwl_down(priv);
 +      if (priv->cfg->lib->bt_setup_deferred_work)
 +              priv->cfg->lib->bt_setup_deferred_work(priv);
  
 -      flush_workqueue(priv->shrd->workqueue);
 +      init_timer(&priv->statistics_periodic);
 +      priv->statistics_periodic.data = (unsigned long)priv;
 +      priv->statistics_periodic.function = iwl_bg_statistics_periodic;
  
 -      /* User space software may expect getting rfkill changes
 -       * even if interface is down */
 -      iwl_write32(bus(priv), CSR_INT, 0xFFFFFFFF);
 -      iwl_enable_rfkill_int(priv);
 +      init_timer(&priv->ucode_trace);
 +      priv->ucode_trace.data = (unsigned long)priv;
 +      priv->ucode_trace.function = iwl_bg_ucode_trace;
  
 -      IWL_DEBUG_MAC80211(priv, "leave\n");
 +      init_timer(&priv->watchdog);
 +      priv->watchdog.data = (unsigned long)priv;
 +      priv->watchdog.function = iwl_bg_watchdog;
  }
  
 -#ifdef CONFIG_PM_SLEEP
 -static int iwlagn_send_patterns(struct iwl_priv *priv,
 -                              struct cfg80211_wowlan *wowlan)
 +static void iwl_cancel_deferred_work(struct iwl_priv *priv)
  {
 -      struct iwlagn_wowlan_patterns_cmd *pattern_cmd;
 -      struct iwl_host_cmd cmd = {
 -              .id = REPLY_WOWLAN_PATTERNS,
 -              .dataflags[0] = IWL_HCMD_DFL_NOCOPY,
 -              .flags = CMD_SYNC,
 -      };
 -      int i, err;
 +      if (priv->cfg->lib->cancel_deferred_work)
 +              priv->cfg->lib->cancel_deferred_work(priv);
  
 -      if (!wowlan->n_patterns)
 -              return 0;
 +      cancel_work_sync(&priv->run_time_calib_work);
 +      cancel_work_sync(&priv->beacon_update);
  
 -      cmd.len[0] = sizeof(*pattern_cmd) +
 -                      wowlan->n_patterns * sizeof(struct iwlagn_wowlan_pattern);
 +      iwl_cancel_scan_deferred_work(priv);
  
 -      pattern_cmd = kmalloc(cmd.len[0], GFP_KERNEL);
 -      if (!pattern_cmd)
 -              return -ENOMEM;
 +      cancel_work_sync(&priv->bt_full_concurrency);
 +      cancel_work_sync(&priv->bt_runtime_config);
 +      cancel_delayed_work_sync(&priv->hw_roc_disable_work);
  
 -      pattern_cmd->n_patterns = cpu_to_le32(wowlan->n_patterns);
 +      del_timer_sync(&priv->statistics_periodic);
 +      del_timer_sync(&priv->ucode_trace);
 +}
  
 -      for (i = 0; i < wowlan->n_patterns; i++) {
 -              int mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8);
 +static void iwl_init_hw_rates(struct iwl_priv *priv,
 +                            struct ieee80211_rate *rates)
 +{
 +      int i;
  
 -              memcpy(&pattern_cmd->patterns[i].mask,
 -                      wowlan->patterns[i].mask, mask_len);
 -              memcpy(&pattern_cmd->patterns[i].pattern,
 -                      wowlan->patterns[i].pattern,
 -                      wowlan->patterns[i].pattern_len);
 -              pattern_cmd->patterns[i].mask_size = mask_len;
 -              pattern_cmd->patterns[i].pattern_size =
 -                      wowlan->patterns[i].pattern_len;
 +      for (i = 0; i < IWL_RATE_COUNT_LEGACY; i++) {
 +              rates[i].bitrate = iwl_rates[i].ieee * 5;
 +              rates[i].hw_value = i; /* Rate scaling will work on indexes */
 +              rates[i].hw_value_short = i;
 +              rates[i].flags = 0;
 +              if ((i >= IWL_FIRST_CCK_RATE) && (i <= IWL_LAST_CCK_RATE)) {
 +                      /*
 +                       * If CCK != 1M then set short preamble rate flag.
 +                       */
 +                      rates[i].flags |=
 +                              (iwl_rates[i].plcp == IWL_RATE_1M_PLCP) ?
 +                                      0 : IEEE80211_RATE_SHORT_PREAMBLE;
 +              }
        }
 -
 -      cmd.data[0] = pattern_cmd;
 -      err = iwl_trans_send_cmd(trans(priv), &cmd);
 -      kfree(pattern_cmd);
 -      return err;
  }
 -#endif
  
 -static void iwlagn_mac_set_rekey_data(struct ieee80211_hw *hw,
 -                                    struct ieee80211_vif *vif,
 -                                    struct cfg80211_gtk_rekey_data *data)
 +static int iwl_init_drv(struct iwl_priv *priv)
  {
 -      struct iwl_priv *priv = hw->priv;
 -
 -      if (iwlagn_mod_params.sw_crypto)
 -              return;
 +      int ret;
  
 -      IWL_DEBUG_MAC80211(priv, "enter\n");
 -      mutex_lock(&priv->shrd->mutex);
 +      spin_lock_init(&priv->shrd->sta_lock);
  
 -      if (priv->contexts[IWL_RXON_CTX_BSS].vif != vif)
 -              goto out;
 +      mutex_init(&priv->shrd->mutex);
  
 -      memcpy(priv->kek, data->kek, NL80211_KEK_LEN);
 -      memcpy(priv->kck, data->kck, NL80211_KCK_LEN);
 -      priv->replay_ctr = cpu_to_le64(be64_to_cpup((__be64 *)&data->replay_ctr));
 -      priv->have_rekey_data = true;
 +      INIT_LIST_HEAD(&priv->calib_results);
  
 - out:
 -      mutex_unlock(&priv->shrd->mutex);
 -      IWL_DEBUG_MAC80211(priv, "leave\n");
 -}
 +      priv->ieee_channels = NULL;
 +      priv->ieee_rates = NULL;
 +      priv->band = IEEE80211_BAND_2GHZ;
  
 -struct wowlan_key_data {
 -      struct iwl_rxon_context *ctx;
 -      struct iwlagn_wowlan_rsc_tsc_params_cmd *rsc_tsc;
 -      struct iwlagn_wowlan_tkip_params_cmd *tkip;
 -      const u8 *bssid;
 -      bool error, use_rsc_tsc, use_tkip;
 -};
 +      priv->iw_mode = NL80211_IFTYPE_STATION;
 +      priv->current_ht_config.smps = IEEE80211_SMPS_STATIC;
 +      priv->missed_beacon_threshold = IWL_MISSED_BEACON_THRESHOLD_DEF;
 +      priv->agg_tids_count = 0;
  
 -#ifdef CONFIG_PM_SLEEP
 -static void iwlagn_convert_p1k(u16 *p1k, __le16 *out)
 -{
 -      int i;
 +      /* initialize force reset */
 +      priv->force_reset[IWL_RF_RESET].reset_duration =
 +              IWL_DELAY_NEXT_FORCE_RF_RESET;
 +      priv->force_reset[IWL_FW_RESET].reset_duration =
 +              IWL_DELAY_NEXT_FORCE_FW_RELOAD;
  
 -      for (i = 0; i < IWLAGN_P1K_SIZE; i++)
 -              out[i] = cpu_to_le16(p1k[i]);
 -}
 +      priv->rx_statistics_jiffies = jiffies;
  
 -static void iwlagn_wowlan_program_keys(struct ieee80211_hw *hw,
 -                                     struct ieee80211_vif *vif,
 -                                     struct ieee80211_sta *sta,
 -                                     struct ieee80211_key_conf *key,
 -                                     void *_data)
 -{
 -      struct iwl_priv *priv = hw->priv;
 -      struct wowlan_key_data *data = _data;
 -      struct iwl_rxon_context *ctx = data->ctx;
 -      struct aes_sc *aes_sc, *aes_tx_sc = NULL;
 -      struct tkip_sc *tkip_sc, *tkip_tx_sc = NULL;
 -      struct iwlagn_p1k_cache *rx_p1ks;
 -      u8 *rx_mic_key;
 -      struct ieee80211_key_seq seq;
 -      u32 cur_rx_iv32 = 0;
 -      u16 p1k[IWLAGN_P1K_SIZE];
 -      int ret, i;
 +      /* Choose which receivers/antennas to use */
 +      iwlagn_set_rxon_chain(priv, &priv->contexts[IWL_RXON_CTX_BSS]);
  
 -      mutex_lock(&priv->shrd->mutex);
 +      iwl_init_scan_params(priv);
  
 -      if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
 -           key->cipher == WLAN_CIPHER_SUITE_WEP104) &&
 -           !sta && !ctx->key_mapping_keys)
 -              ret = iwl_set_default_wep_key(priv, ctx, key);
 -      else
 -              ret = iwl_set_dynamic_key(priv, ctx, key, sta);
 +      /* init bt coex */
 +      if (priv->cfg->bt_params &&
 +          priv->cfg->bt_params->advanced_bt_coexist) {
 +              priv->kill_ack_mask = IWLAGN_BT_KILL_ACK_MASK_DEFAULT;
 +              priv->kill_cts_mask = IWLAGN_BT_KILL_CTS_MASK_DEFAULT;
 +              priv->bt_valid = IWLAGN_BT_ALL_VALID_MSK;
 +              priv->bt_on_thresh = BT_ON_THRESHOLD_DEF;
 +              priv->bt_duration = BT_DURATION_LIMIT_DEF;
 +              priv->dynamic_frag_thresh = BT_FRAG_THRESHOLD_DEF;
 +      }
  
 +      ret = iwl_init_channel_map(priv);
        if (ret) {
 -              IWL_ERR(priv, "Error setting key during suspend!\n");
 -              data->error = true;
 +              IWL_ERR(priv, "initializing regulatory failed: %d\n", ret);
 +              goto err;
        }
  
 -      switch (key->cipher) {
 -      case WLAN_CIPHER_SUITE_TKIP:
 -              if (sta) {
 -                      tkip_sc = data->rsc_tsc->all_tsc_rsc.tkip.unicast_rsc;
 -                      tkip_tx_sc = &data->rsc_tsc->all_tsc_rsc.tkip.tsc;
 -
 -                      rx_p1ks = data->tkip->rx_uni;
 -
 -                      ieee80211_get_key_tx_seq(key, &seq);
 -                      tkip_tx_sc->iv16 = cpu_to_le16(seq.tkip.iv16);
 -                      tkip_tx_sc->iv32 = cpu_to_le32(seq.tkip.iv32);
 +      ret = iwl_init_geos(priv);
 +      if (ret) {
 +              IWL_ERR(priv, "initializing geos failed: %d\n", ret);
 +              goto err_free_channel_map;
 +      }
 +      iwl_init_hw_rates(priv, priv->ieee_rates);
  
 -                      ieee80211_get_tkip_p1k_iv(key, seq.tkip.iv32, p1k);
 -                      iwlagn_convert_p1k(p1k, data->tkip->tx.p1k);
 +      return 0;
  
 -                      memcpy(data->tkip->mic_keys.tx,
 -                             &key->key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY],
 -                             IWLAGN_MIC_KEY_SIZE);
 -
 -                      rx_mic_key = data->tkip->mic_keys.rx_unicast;
 -              } else {
 -                      tkip_sc = data->rsc_tsc->all_tsc_rsc.tkip.multicast_rsc;
 -                      rx_p1ks = data->tkip->rx_multi;
 -                      rx_mic_key = data->tkip->mic_keys.rx_mcast;
 -              }
 -
 -              /*
 -               * For non-QoS this relies on the fact that both the uCode and
 -               * mac80211 use TID 0 (as they need to to avoid replay attacks)
 -               * for checking the IV in the frames.
 -               */
 -              for (i = 0; i < IWLAGN_NUM_RSC; i++) {
 -                      ieee80211_get_key_rx_seq(key, i, &seq);
 -                      tkip_sc[i].iv16 = cpu_to_le16(seq.tkip.iv16);
 -                      tkip_sc[i].iv32 = cpu_to_le32(seq.tkip.iv32);
 -                      /* wrapping isn't allowed, AP must rekey */
 -                      if (seq.tkip.iv32 > cur_rx_iv32)
 -                              cur_rx_iv32 = seq.tkip.iv32;
 -              }
 -
 -              ieee80211_get_tkip_rx_p1k(key, data->bssid, cur_rx_iv32, p1k);
 -              iwlagn_convert_p1k(p1k, rx_p1ks[0].p1k);
 -              ieee80211_get_tkip_rx_p1k(key, data->bssid,
 -                                        cur_rx_iv32 + 1, p1k);
 -              iwlagn_convert_p1k(p1k, rx_p1ks[1].p1k);
 -
 -              memcpy(rx_mic_key,
 -                     &key->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY],
 -                     IWLAGN_MIC_KEY_SIZE);
 -
 -              data->use_tkip = true;
 -              data->use_rsc_tsc = true;
 -              break;
 -      case WLAN_CIPHER_SUITE_CCMP:
 -              if (sta) {
 -                      u8 *pn = seq.ccmp.pn;
 -
 -                      aes_sc = data->rsc_tsc->all_tsc_rsc.aes.unicast_rsc;
 -                      aes_tx_sc = &data->rsc_tsc->all_tsc_rsc.aes.tsc;
 -
 -                      ieee80211_get_key_tx_seq(key, &seq);
 -                      aes_tx_sc->pn = cpu_to_le64(
 -                                      (u64)pn[5] |
 -                                      ((u64)pn[4] << 8) |
 -                                      ((u64)pn[3] << 16) |
 -                                      ((u64)pn[2] << 24) |
 -                                      ((u64)pn[1] << 32) |
 -                                      ((u64)pn[0] << 40));
 -              } else
 -                      aes_sc = data->rsc_tsc->all_tsc_rsc.aes.multicast_rsc;
 -
 -              /*
 -               * For non-QoS this relies on the fact that both the uCode and
 -               * mac80211 use TID 0 for checking the IV in the frames.
 -               */
 -              for (i = 0; i < IWLAGN_NUM_RSC; i++) {
 -                      u8 *pn = seq.ccmp.pn;
 -
 -                      ieee80211_get_key_rx_seq(key, i, &seq);
 -                      aes_sc->pn = cpu_to_le64(
 -                                      (u64)pn[5] |
 -                                      ((u64)pn[4] << 8) |
 -                                      ((u64)pn[3] << 16) |
 -                                      ((u64)pn[2] << 24) |
 -                                      ((u64)pn[1] << 32) |
 -                                      ((u64)pn[0] << 40));
 -              }
 -              data->use_rsc_tsc = true;
 -              break;
 -      }
 -
 -      mutex_unlock(&priv->shrd->mutex);
 -}
 -
 -static int iwlagn_mac_suspend(struct ieee80211_hw *hw,
 -                            struct cfg80211_wowlan *wowlan)
 -{
 -      struct iwl_priv *priv = hw->priv;
 -      struct iwlagn_wowlan_wakeup_filter_cmd wakeup_filter_cmd;
 -      struct iwl_rxon_cmd rxon;
 -      struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 -      struct iwlagn_wowlan_kek_kck_material_cmd kek_kck_cmd;
 -      struct iwlagn_wowlan_tkip_params_cmd tkip_cmd = {};
 -      struct wowlan_key_data key_data = {
 -              .ctx = ctx,
 -              .bssid = ctx->active.bssid_addr,
 -              .use_rsc_tsc = false,
 -              .tkip = &tkip_cmd,
 -              .use_tkip = false,
 -      };
 -      int ret, i;
 -      u16 seq;
 -
 -      if (WARN_ON(!wowlan))
 -              return -EINVAL;
 -
 -      IWL_DEBUG_MAC80211(priv, "enter\n");
 -      mutex_lock(&priv->shrd->mutex);
 -
 -      /* Don't attempt WoWLAN when not associated, tear down instead. */
 -      if (!ctx->vif || ctx->vif->type != NL80211_IFTYPE_STATION ||
 -          !iwl_is_associated_ctx(ctx)) {
 -              ret = 1;
 -              goto out;
 -      }
 -
 -      key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL);
 -      if (!key_data.rsc_tsc) {
 -              ret = -ENOMEM;
 -              goto out;
 -      }
 -
 -      memset(&wakeup_filter_cmd, 0, sizeof(wakeup_filter_cmd));
 -
 -      /*
 -       * We know the last used seqno, and the uCode expects to know that
 -       * one, it will increment before TX.
 -       */
 -      seq = le16_to_cpu(priv->last_seq_ctl) & IEEE80211_SCTL_SEQ;
 -      wakeup_filter_cmd.non_qos_seq = cpu_to_le16(seq);
 -
 -      /*
 -       * For QoS counters, we store the one to use next, so subtract 0x10
 -       * since the uCode will add 0x10 before using the value.
 -       */
 -      for (i = 0; i < 8; i++) {
 -              seq = priv->shrd->tid_data[IWL_AP_ID][i].seq_number;
 -              seq -= 0x10;
 -              wakeup_filter_cmd.qos_seq[i] = cpu_to_le16(seq);
 -      }
 -
 -      if (wowlan->disconnect)
 -              wakeup_filter_cmd.enabled |=
 -                      cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_BEACON_MISS |
 -                                  IWLAGN_WOWLAN_WAKEUP_LINK_CHANGE);
 -      if (wowlan->magic_pkt)
 -              wakeup_filter_cmd.enabled |=
 -                      cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_MAGIC_PACKET);
 -      if (wowlan->gtk_rekey_failure)
 -              wakeup_filter_cmd.enabled |=
 -                      cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_GTK_REKEY_FAIL);
 -      if (wowlan->eap_identity_req)
 -              wakeup_filter_cmd.enabled |=
 -                      cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_EAP_IDENT_REQ);
 -      if (wowlan->four_way_handshake)
 -              wakeup_filter_cmd.enabled |=
 -                      cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_4WAY_HANDSHAKE);
 -      if (wowlan->rfkill_release)
 -              wakeup_filter_cmd.enabled |=
 -                      cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_RFKILL);
 -      if (wowlan->n_patterns)
 -              wakeup_filter_cmd.enabled |=
 -                      cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_PATTERN_MATCH);
 -
 -      iwl_scan_cancel_timeout(priv, 200);
 -
 -      memcpy(&rxon, &ctx->active, sizeof(rxon));
 -
 -      iwl_trans_stop_device(trans(priv));
 -
 -      priv->shrd->wowlan = true;
 -
 -      ret = iwlagn_load_ucode_wait_alive(priv, &priv->ucode_wowlan,
 -                                         IWL_UCODE_WOWLAN);
 -      if (ret)
 -              goto error;
 -
 -      /* now configure WoWLAN ucode */
 -      ret = iwl_alive_start(priv);
 -      if (ret)
 -              goto error;
 -
 -      memcpy(&ctx->staging, &rxon, sizeof(rxon));
 -      ret = iwlagn_commit_rxon(priv, ctx);
 -      if (ret)
 -              goto error;
 -
 -      ret = iwl_power_update_mode(priv, true);
 -      if (ret)
 -              goto error;
 -
 -      if (!iwlagn_mod_params.sw_crypto) {
 -              /* mark all keys clear */
 -              priv->ucode_key_table = 0;
 -              ctx->key_mapping_keys = 0;
 -
 -              /*
 -               * This needs to be unlocked due to lock ordering
 -               * constraints. Since we're in the suspend path
 -               * that isn't really a problem though.
 -               */
 -              mutex_unlock(&priv->shrd->mutex);
 -              ieee80211_iter_keys(priv->hw, ctx->vif,
 -                                  iwlagn_wowlan_program_keys,
 -                                  &key_data);
 -              mutex_lock(&priv->shrd->mutex);
 -              if (key_data.error) {
 -                      ret = -EIO;
 -                      goto error;
 -              }
 -
 -              if (key_data.use_rsc_tsc) {
 -                      struct iwl_host_cmd rsc_tsc_cmd = {
 -                              .id = REPLY_WOWLAN_TSC_RSC_PARAMS,
 -                              .flags = CMD_SYNC,
 -                              .data[0] = key_data.rsc_tsc,
 -                              .dataflags[0] = IWL_HCMD_DFL_NOCOPY,
 -                              .len[0] = sizeof(*key_data.rsc_tsc),
 -                      };
 -
 -                      ret = iwl_trans_send_cmd(trans(priv), &rsc_tsc_cmd);
 -                      if (ret)
 -                              goto error;
 -              }
 -
 -              if (key_data.use_tkip) {
 -                      ret = iwl_trans_send_cmd_pdu(trans(priv),
 -                                               REPLY_WOWLAN_TKIP_PARAMS,
 -                                               CMD_SYNC, sizeof(tkip_cmd),
 -                                               &tkip_cmd);
 -                      if (ret)
 -                              goto error;
 -              }
 -
 -              if (priv->have_rekey_data) {
 -                      memset(&kek_kck_cmd, 0, sizeof(kek_kck_cmd));
 -                      memcpy(kek_kck_cmd.kck, priv->kck, NL80211_KCK_LEN);
 -                      kek_kck_cmd.kck_len = cpu_to_le16(NL80211_KCK_LEN);
 -                      memcpy(kek_kck_cmd.kek, priv->kek, NL80211_KEK_LEN);
 -                      kek_kck_cmd.kek_len = cpu_to_le16(NL80211_KEK_LEN);
 -                      kek_kck_cmd.replay_ctr = priv->replay_ctr;
 -
 -                      ret = iwl_trans_send_cmd_pdu(trans(priv),
 -                                               REPLY_WOWLAN_KEK_KCK_MATERIAL,
 -                                               CMD_SYNC, sizeof(kek_kck_cmd),
 -                                               &kek_kck_cmd);
 -                      if (ret)
 -                              goto error;
 -              }
 -      }
 -
 -      ret = iwl_trans_send_cmd_pdu(trans(priv), REPLY_WOWLAN_WAKEUP_FILTER,
 -                               CMD_SYNC, sizeof(wakeup_filter_cmd),
 -                               &wakeup_filter_cmd);
 -      if (ret)
 -              goto error;
 -
 -      ret = iwlagn_send_patterns(priv, wowlan);
 -      if (ret)
 -              goto error;
 -
 -      device_set_wakeup_enable(bus(priv)->dev, true);
 -
 -      /* Now let the ucode operate on its own */
 -      iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_SET,
 -                        CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
 -
 -      goto out;
 -
 - error:
 -      priv->shrd->wowlan = false;
 -      iwlagn_prepare_restart(priv);
 -      ieee80211_restart_hw(priv->hw);
 - out:
 -      mutex_unlock(&priv->shrd->mutex);
 -      kfree(key_data.rsc_tsc);
 -      IWL_DEBUG_MAC80211(priv, "leave\n");
 -
 -      return ret;
 -}
 -
 -static int iwlagn_mac_resume(struct ieee80211_hw *hw)
 -{
 -      struct iwl_priv *priv = hw->priv;
 -      struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 -      struct ieee80211_vif *vif;
 -      unsigned long flags;
 -      u32 base, status = 0xffffffff;
 -      int ret = -EIO;
 -
 -      IWL_DEBUG_MAC80211(priv, "enter\n");
 -      mutex_lock(&priv->shrd->mutex);
 -
 -      iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_CLR,
 -                        CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
 -
 -      base = priv->device_pointers.error_event_table;
 -      if (iwlagn_hw_valid_rtc_data_addr(base)) {
 -              spin_lock_irqsave(&bus(priv)->reg_lock, flags);
 -              ret = iwl_grab_nic_access_silent(bus(priv));
 -              if (ret == 0) {
 -                      iwl_write32(bus(priv), HBUS_TARG_MEM_RADDR, base);
 -                      status = iwl_read32(bus(priv), HBUS_TARG_MEM_RDAT);
 -                      iwl_release_nic_access(bus(priv));
 -              }
 -              spin_unlock_irqrestore(&bus(priv)->reg_lock, flags);
 -
 -#ifdef CONFIG_IWLWIFI_DEBUGFS
 -              if (ret == 0) {
 -                      if (!priv->wowlan_sram)
 -                              priv->wowlan_sram =
 -                                      kzalloc(priv->ucode_wowlan.data.len,
 -                                              GFP_KERNEL);
 -
 -                      if (priv->wowlan_sram)
 -                              _iwl_read_targ_mem_words(
 -                                      bus(priv), 0x800000, priv->wowlan_sram,
 -                                      priv->ucode_wowlan.data.len / 4);
 -              }
 -#endif
 -      }
 -
 -      /* we'll clear ctx->vif during iwlagn_prepare_restart() */
 -      vif = ctx->vif;
 -
 -      priv->shrd->wowlan = false;
 -
 -      device_set_wakeup_enable(bus(priv)->dev, false);
 -
 -      iwlagn_prepare_restart(priv);
 -
 -      memset((void *)&ctx->active, 0, sizeof(ctx->active));
 -      iwl_connection_init_rx_config(priv, ctx);
 -      iwlagn_set_rxon_chain(priv, ctx);
 -
 -      mutex_unlock(&priv->shrd->mutex);
 -      IWL_DEBUG_MAC80211(priv, "leave\n");
 -
 -      ieee80211_resume_disconnect(vif);
 -
 -      return 1;
 -}
 -#endif
 -
 -static void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 -{
 -      struct iwl_priv *priv = hw->priv;
 -
 -      IWL_DEBUG_MACDUMP(priv, "enter\n");
 -
 -      IWL_DEBUG_TX(priv, "dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
 -                   ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate);
 -
 -      if (iwlagn_tx_skb(priv, skb))
 -              dev_kfree_skb_any(skb);
 -
 -      IWL_DEBUG_MACDUMP(priv, "leave\n");
 -}
 -
 -static void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw,
 -                                     struct ieee80211_vif *vif,
 -                                     struct ieee80211_key_conf *keyconf,
 -                                     struct ieee80211_sta *sta,
 -                                     u32 iv32, u16 *phase1key)
 -{
 -      struct iwl_priv *priv = hw->priv;
 -
 -      iwl_update_tkip_key(priv, vif, keyconf, sta, iv32, phase1key);
 -}
 -
 -static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 -                            struct ieee80211_vif *vif,
 -                            struct ieee80211_sta *sta,
 -                            struct ieee80211_key_conf *key)
 -{
 -      struct iwl_priv *priv = hw->priv;
 -      struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
 -      struct iwl_rxon_context *ctx = vif_priv->ctx;
 -      int ret;
 -      bool is_default_wep_key = false;
 -
 -      IWL_DEBUG_MAC80211(priv, "enter\n");
 -
 -      if (iwlagn_mod_params.sw_crypto) {
 -              IWL_DEBUG_MAC80211(priv, "leave - hwcrypto disabled\n");
 -              return -EOPNOTSUPP;
 -      }
 -
 -      switch (key->cipher) {
 -      case WLAN_CIPHER_SUITE_TKIP:
 -              key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
 -              /* fall through */
 -      case WLAN_CIPHER_SUITE_CCMP:
 -              key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
 -              break;
 -      default:
 -              break;
 -      }
 -
 -      /*
 -       * We could program these keys into the hardware as well, but we
 -       * don't expect much multicast traffic in IBSS and having keys
 -       * for more stations is probably more useful.
 -       *
 -       * Mark key TX-only and return 0.
 -       */
 -      if (vif->type == NL80211_IFTYPE_ADHOC &&
 -          !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
 -              key->hw_key_idx = WEP_INVALID_OFFSET;
 -              return 0;
 -      }
 -
 -      /* If they key was TX-only, accept deletion */
 -      if (cmd == DISABLE_KEY && key->hw_key_idx == WEP_INVALID_OFFSET)
 -              return 0;
 -
 -      mutex_lock(&priv->shrd->mutex);
 -      iwl_scan_cancel_timeout(priv, 100);
 -
 -      BUILD_BUG_ON(WEP_INVALID_OFFSET == IWLAGN_HW_KEY_DEFAULT);
 -
 -      /*
 -       * If we are getting WEP group key and we didn't receive any key mapping
 -       * so far, we are in legacy wep mode (group key only), otherwise we are
 -       * in 1X mode.
 -       * In legacy wep mode, we use another host command to the uCode.
 -       */
 -      if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
 -           key->cipher == WLAN_CIPHER_SUITE_WEP104) && !sta) {
 -              if (cmd == SET_KEY)
 -                      is_default_wep_key = !ctx->key_mapping_keys;
 -              else
 -                      is_default_wep_key =
 -                              key->hw_key_idx == IWLAGN_HW_KEY_DEFAULT;
 -      }
 -
 -
 -      switch (cmd) {
 -      case SET_KEY:
 -              if (is_default_wep_key) {
 -                      ret = iwl_set_default_wep_key(priv, vif_priv->ctx, key);
 -                      break;
 -              }
 -              ret = iwl_set_dynamic_key(priv, vif_priv->ctx, key, sta);
 -              if (ret) {
 -                      /*
 -                       * can't add key for RX, but we don't need it
 -                       * in the device for TX so still return 0
 -                       */
 -                      ret = 0;
 -                      key->hw_key_idx = WEP_INVALID_OFFSET;
 -              }
 -
 -              IWL_DEBUG_MAC80211(priv, "enable hwcrypto key\n");
 -              break;
 -      case DISABLE_KEY:
 -              if (is_default_wep_key)
 -                      ret = iwl_remove_default_wep_key(priv, ctx, key);
 -              else
 -                      ret = iwl_remove_dynamic_key(priv, ctx, key, sta);
 -
 -              IWL_DEBUG_MAC80211(priv, "disable hwcrypto key\n");
 -              break;
 -      default:
 -              ret = -EINVAL;
 -      }
 -
 -      mutex_unlock(&priv->shrd->mutex);
 -      IWL_DEBUG_MAC80211(priv, "leave\n");
 -
 -      return ret;
 -}
 -
 -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)
 -{
 -      struct iwl_priv *priv = hw->priv;
 -      int ret = -EINVAL;
 -      struct iwl_station_priv *sta_priv = (void *) sta->drv_priv;
 -      struct iwl_rxon_context *ctx =  iwl_rxon_ctx_from_vif(vif);
 -
 -      IWL_DEBUG_HT(priv, "A-MPDU action on addr %pM tid %d\n",
 -                   sta->addr, tid);
 -
 -      if (!(priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE))
 -              return -EACCES;
 -
 -      IWL_DEBUG_MAC80211(priv, "enter\n");
 -      mutex_lock(&priv->shrd->mutex);
 -
 -      switch (action) {
 -      case IEEE80211_AMPDU_RX_START:
 -              IWL_DEBUG_HT(priv, "start Rx\n");
 -              ret = iwl_sta_rx_agg_start(priv, sta, tid, *ssn);
 -              break;
 -      case IEEE80211_AMPDU_RX_STOP:
 -              IWL_DEBUG_HT(priv, "stop Rx\n");
 -              ret = iwl_sta_rx_agg_stop(priv, sta, tid);
 -              if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
 -                      ret = 0;
 -              break;
 -      case IEEE80211_AMPDU_TX_START:
 -              IWL_DEBUG_HT(priv, "start Tx\n");
 -              ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn);
 -              break;
 -      case IEEE80211_AMPDU_TX_STOP:
 -              IWL_DEBUG_HT(priv, "stop Tx\n");
 -              ret = iwlagn_tx_agg_stop(priv, vif, sta, tid);
 -              if ((ret == 0) && (priv->agg_tids_count > 0)) {
 -                      priv->agg_tids_count--;
 -                      IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n",
 -                                   priv->agg_tids_count);
 -              }
 -              if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
 -                      ret = 0;
 -              if (!priv->agg_tids_count && priv->cfg->ht_params &&
 -                  priv->cfg->ht_params->use_rts_for_aggregation) {
 -                      /*
 -                       * 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, iwl_rxon_ctx_from_vif(vif),
 -                                      &sta_priv->lq_sta.lq, CMD_ASYNC, false);
 -              }
 -              break;
 -      case IEEE80211_AMPDU_TX_OPERATIONAL:
 -              buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF);
 -
 -              iwl_trans_tx_agg_setup(trans(priv), ctx->ctxid, iwl_sta_id(sta),
 -                              tid, buf_size);
 -
 -              /*
 -               * If the limit is 0, then it wasn't initialised yet,
 -               * use the default. We can do that since we take the
 -               * minimum below, and we don't want to go above our
 -               * default due to hardware restrictions.
 -               */
 -              if (sta_priv->max_agg_bufsize == 0)
 -                      sta_priv->max_agg_bufsize =
 -                              LINK_QUAL_AGG_FRAME_LIMIT_DEF;
 -
 -              /*
 -               * Even though in theory the peer could have different
 -               * aggregation reorder buffer sizes for different sessions,
 -               * our ucode doesn't allow for that and has a global limit
 -               * for each station. Therefore, use the minimum of all the
 -               * aggregation sessions and our default value.
 -               */
 -              sta_priv->max_agg_bufsize =
 -                      min(sta_priv->max_agg_bufsize, buf_size);
 -
 -              if (priv->cfg->ht_params &&
 -                  priv->cfg->ht_params->use_rts_for_aggregation) {
 -                      /*
 -                       * 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;
 -              }
 -              priv->agg_tids_count++;
 -              IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n",
 -                           priv->agg_tids_count);
 -
 -              sta_priv->lq_sta.lq.agg_params.agg_frame_cnt_limit =
 -                      sta_priv->max_agg_bufsize;
 -
 -              iwl_send_lq_cmd(priv, iwl_rxon_ctx_from_vif(vif),
 -                              &sta_priv->lq_sta.lq, CMD_ASYNC, false);
 -
 -              IWL_INFO(priv, "Tx aggregation enabled on ra = %pM tid = %d\n",
 -                       sta->addr, tid);
 -              ret = 0;
 -              break;
 -      }
 -      mutex_unlock(&priv->shrd->mutex);
 -      IWL_DEBUG_MAC80211(priv, "leave\n");
 -      return ret;
 -}
 -
 -static int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
 -                            struct ieee80211_vif *vif,
 -                            struct ieee80211_sta *sta)
 -{
 -      struct iwl_priv *priv = hw->priv;
 -      struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
 -      struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
 -      bool is_ap = vif->type == NL80211_IFTYPE_STATION;
 -      int ret = 0;
 -      u8 sta_id;
 -
 -      IWL_DEBUG_MAC80211(priv, "received request to add station %pM\n",
 -                      sta->addr);
 -      mutex_lock(&priv->shrd->mutex);
 -      IWL_DEBUG_INFO(priv, "proceeding to add station %pM\n",
 -                      sta->addr);
 -      sta_priv->sta_id = IWL_INVALID_STATION;
 -
 -      atomic_set(&sta_priv->pending_frames, 0);
 -      if (vif->type == NL80211_IFTYPE_AP)
 -              sta_priv->client = true;
 -
 -      ret = iwl_add_station_common(priv, vif_priv->ctx, sta->addr,
 -                                   is_ap, sta, &sta_id);
 -      if (ret) {
 -              IWL_ERR(priv, "Unable to add station %pM (%d)\n",
 -                      sta->addr, ret);
 -              /* Should we return success if return code is EEXIST ? */
 -              goto out;
 -      }
 -
 -      sta_priv->sta_id = sta_id;
 -
 -      /* Initialize rate scaling */
 -      IWL_DEBUG_INFO(priv, "Initializing rate scaling for station %pM\n",
 -                     sta->addr);
 -      iwl_rs_rate_init(priv, sta, sta_id);
 - out:
 -      mutex_unlock(&priv->shrd->mutex);
 -      IWL_DEBUG_MAC80211(priv, "leave\n");
 -
 -      return ret;
 -}
 -
 -static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
 -                              struct ieee80211_channel_switch *ch_switch)
 -{
 -      struct iwl_priv *priv = hw->priv;
 -      const struct iwl_channel_info *ch_info;
 -      struct ieee80211_conf *conf = &hw->conf;
 -      struct ieee80211_channel *channel = ch_switch->channel;
 -      struct iwl_ht_config *ht_conf = &priv->current_ht_config;
 -      /*
 -       * MULTI-FIXME
 -       * When we add support for multiple interfaces, we need to
 -       * revisit this. The channel switch command in the device
 -       * only affects the BSS context, but what does that really
 -       * mean? And what if we get a CSA on the second interface?
 -       * This needs a lot of work.
 -       */
 -      struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 -      u16 ch;
 -
 -      IWL_DEBUG_MAC80211(priv, "enter\n");
 -
 -      mutex_lock(&priv->shrd->mutex);
 -
 -      if (iwl_is_rfkill(priv->shrd))
 -              goto out;
 -
 -      if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status) ||
 -          test_bit(STATUS_SCANNING, &priv->shrd->status) ||
 -          test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status))
 -              goto out;
 -
 -      if (!iwl_is_associated_ctx(ctx))
 -              goto out;
 -
 -      if (!priv->cfg->lib->set_channel_switch)
 -              goto out;
 -
 -      ch = channel->hw_value;
 -      if (le16_to_cpu(ctx->active.channel) == ch)
 -              goto out;
 -
 -      ch_info = iwl_get_channel_info(priv, channel->band, ch);
 -      if (!is_channel_valid(ch_info)) {
 -              IWL_DEBUG_MAC80211(priv, "invalid channel\n");
 -              goto out;
 -      }
 -
 -      spin_lock_irq(&priv->shrd->lock);
 -
 -      priv->current_ht_config.smps = conf->smps_mode;
 -
 -      /* Configure HT40 channels */
 -      ctx->ht.enabled = conf_is_ht(conf);
 -      if (ctx->ht.enabled)
 -              iwlagn_config_ht40(conf, ctx);
 -      else
 -              ctx->ht.is_40mhz = false;
 -
 -      if ((le16_to_cpu(ctx->staging.channel) != ch))
 -              ctx->staging.flags = 0;
 -
 -      iwl_set_rxon_channel(priv, channel, ctx);
 -      iwl_set_rxon_ht(priv, ht_conf);
 -      iwl_set_flags_for_band(priv, ctx, channel->band, ctx->vif);
 -
 -      spin_unlock_irq(&priv->shrd->lock);
 -
 -      iwl_set_rate(priv);
 -      /*
 -       * at this point, staging_rxon has the
 -       * configuration for channel switch
 -       */
 -      set_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status);
 -      priv->switch_channel = cpu_to_le16(ch);
 -      if (priv->cfg->lib->set_channel_switch(priv, ch_switch)) {
 -              clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status);
 -              priv->switch_channel = 0;
 -              ieee80211_chswitch_done(ctx->vif, false);
 -      }
 -
 -out:
 -      mutex_unlock(&priv->shrd->mutex);
 -      IWL_DEBUG_MAC80211(priv, "leave\n");
 -}
 -
 -static void iwlagn_configure_filter(struct ieee80211_hw *hw,
 -                                  unsigned int changed_flags,
 -                                  unsigned int *total_flags,
 -                                  u64 multicast)
 -{
 -      struct iwl_priv *priv = hw->priv;
 -      __le32 filter_or = 0, filter_nand = 0;
 -      struct iwl_rxon_context *ctx;
 -
 -#define CHK(test, flag)       do { \
 -      if (*total_flags & (test))              \
 -              filter_or |= (flag);            \
 -      else                                    \
 -              filter_nand |= (flag);          \
 -      } while (0)
 -
 -      IWL_DEBUG_MAC80211(priv, "Enter: changed: 0x%x, total: 0x%x\n",
 -                      changed_flags, *total_flags);
 -
 -      CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK);
 -      /* Setting _just_ RXON_FILTER_CTL2HOST_MSK causes FH errors */
 -      CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_PROMISC_MSK);
 -      CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK);
 -
 -#undef CHK
 -
 -      mutex_lock(&priv->shrd->mutex);
 -
 -      for_each_context(priv, ctx) {
 -              ctx->staging.filter_flags &= ~filter_nand;
 -              ctx->staging.filter_flags |= filter_or;
 -
 -              /*
 -               * Not committing directly because hardware can perform a scan,
 -               * but we'll eventually commit the filter flags change anyway.
 -               */
 -      }
 -
 -      mutex_unlock(&priv->shrd->mutex);
 -
 -      /*
 -       * Receiving all multicast frames is always enabled by the
 -       * default flags setup in iwl_connection_init_rx_config()
 -       * since we currently do not support programming multicast
 -       * filters into the device.
 -       */
 -      *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS |
 -                      FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
 -}
 -
 -static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop)
 -{
 -      struct iwl_priv *priv = hw->priv;
 -
 -      mutex_lock(&priv->shrd->mutex);
 -      IWL_DEBUG_MAC80211(priv, "enter\n");
 -
 -      if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) {
 -              IWL_DEBUG_TX(priv, "Aborting flush due to device shutdown\n");
 -              goto done;
 -      }
 -      if (iwl_is_rfkill(priv->shrd)) {
 -              IWL_DEBUG_TX(priv, "Aborting flush due to RF Kill\n");
 -              goto done;
 -      }
 -
 -      /*
 -       * mac80211 will not push any more frames for transmit
 -       * until the flush is completed
 -       */
 -      if (drop) {
 -              IWL_DEBUG_MAC80211(priv, "send flush command\n");
 -              if (iwlagn_txfifo_flush(priv, IWL_DROP_ALL)) {
 -                      IWL_ERR(priv, "flush request fail\n");
 -                      goto done;
 -              }
 -      }
 -      IWL_DEBUG_MAC80211(priv, "wait transmit/flush all frames\n");
 -      iwl_trans_wait_tx_queue_empty(trans(priv));
 -done:
 -      mutex_unlock(&priv->shrd->mutex);
 -      IWL_DEBUG_MAC80211(priv, "leave\n");
 -}
 -
 -void iwlagn_disable_roc(struct iwl_priv *priv)
 -{
 -      struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN];
 -
 -      lockdep_assert_held(&priv->shrd->mutex);
 -
 -      if (!priv->hw_roc_setup)
 -              return;
 -
 -      ctx->staging.dev_type = RXON_DEV_TYPE_P2P;
 -      ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
 -
 -      priv->hw_roc_channel = NULL;
 -
 -      memset(ctx->staging.node_addr, 0, ETH_ALEN);
 -
 -      iwlagn_commit_rxon(priv, ctx);
 -
 -      ctx->is_active = false;
 -      priv->hw_roc_setup = false;
 -}
 -
 -static void iwlagn_disable_roc_work(struct work_struct *work)
 -{
 -      struct iwl_priv *priv = container_of(work, struct iwl_priv,
 -                                           hw_roc_disable_work.work);
 -
 -      mutex_lock(&priv->shrd->mutex);
 -      iwlagn_disable_roc(priv);
 -      mutex_unlock(&priv->shrd->mutex);
 -}
 -
 -static int iwlagn_mac_remain_on_channel(struct ieee80211_hw *hw,
 -                                   struct ieee80211_channel *channel,
 -                                   enum nl80211_channel_type channel_type,
 -                                   int duration)
 -{
 -      struct iwl_priv *priv = hw->priv;
 -      struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN];
 -      int err = 0;
 -
 -      if (!(priv->shrd->valid_contexts & BIT(IWL_RXON_CTX_PAN)))
 -              return -EOPNOTSUPP;
 -
 -      if (!(ctx->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT)))
 -              return -EOPNOTSUPP;
 -
 -      IWL_DEBUG_MAC80211(priv, "enter\n");
 -      mutex_lock(&priv->shrd->mutex);
 -
 -      if (test_bit(STATUS_SCAN_HW, &priv->shrd->status)) {
 -              err = -EBUSY;
 -              goto out;
 -      }
 -
 -      priv->hw_roc_channel = channel;
 -      priv->hw_roc_chantype = channel_type;
 -      priv->hw_roc_duration = duration;
 -      priv->hw_roc_start_notified = false;
 -      cancel_delayed_work(&priv->hw_roc_disable_work);
 -
 -      if (!ctx->is_active) {
 -              ctx->is_active = true;
 -              ctx->staging.dev_type = RXON_DEV_TYPE_P2P;
 -              memcpy(ctx->staging.node_addr,
 -                     priv->contexts[IWL_RXON_CTX_BSS].staging.node_addr,
 -                     ETH_ALEN);
 -              memcpy(ctx->staging.bssid_addr,
 -                     priv->contexts[IWL_RXON_CTX_BSS].staging.node_addr,
 -                     ETH_ALEN);
 -              err = iwlagn_commit_rxon(priv, ctx);
 -              if (err)
 -                      goto out;
 -              ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK |
 -                                           RXON_FILTER_PROMISC_MSK |
 -                                           RXON_FILTER_CTL2HOST_MSK;
 -
 -              err = iwlagn_commit_rxon(priv, ctx);
 -              if (err) {
 -                      iwlagn_disable_roc(priv);
 -                      goto out;
 -              }
 -              priv->hw_roc_setup = true;
 -      }
 -
 -      err = iwl_scan_initiate(priv, ctx->vif, IWL_SCAN_ROC, channel->band);
 -      if (err)
 -              iwlagn_disable_roc(priv);
 -
 - out:
 -      mutex_unlock(&priv->shrd->mutex);
 -      IWL_DEBUG_MAC80211(priv, "leave\n");
 -
 -      return err;
 -}
 -
 -static int iwlagn_mac_cancel_remain_on_channel(struct ieee80211_hw *hw)
 -{
 -      struct iwl_priv *priv = hw->priv;
 -
 -      if (!(priv->shrd->valid_contexts & BIT(IWL_RXON_CTX_PAN)))
 -              return -EOPNOTSUPP;
 -
 -      IWL_DEBUG_MAC80211(priv, "enter\n");
 -      mutex_lock(&priv->shrd->mutex);
 -      iwl_scan_cancel_timeout(priv, priv->hw_roc_duration);
 -      iwlagn_disable_roc(priv);
 -      mutex_unlock(&priv->shrd->mutex);
 -      IWL_DEBUG_MAC80211(priv, "leave\n");
 -
 -      return 0;
 -}
 -
 -static int iwlagn_mac_tx_sync(struct ieee80211_hw *hw,
 -                            struct ieee80211_vif *vif,
 -                            const u8 *bssid,
 -                            enum ieee80211_tx_sync_type type)
 -{
 -      struct iwl_priv *priv = hw->priv;
 -      struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
 -      struct iwl_rxon_context *ctx = vif_priv->ctx;
 -      int ret;
 -      u8 sta_id;
 -
 -      IWL_DEBUG_MAC80211(priv, "enter\n");
 -      mutex_lock(&priv->shrd->mutex);
 -
 -      if (iwl_is_associated_ctx(ctx)) {
 -              ret = 0;
 -              goto out;
 -      }
 -
 -      if (ctx->preauth_bssid || test_bit(STATUS_SCAN_HW, &priv->shrd->status)) {
 -              ret = -EBUSY;
 -              goto out;
 -      }
 -
 -      ret = iwl_add_station_common(priv, ctx, bssid, true, NULL, &sta_id);
 -      if (ret)
 -              goto out;
 -
 -      if (WARN_ON(sta_id != ctx->ap_sta_id)) {
 -              ret = -EIO;
 -              goto out_remove_sta;
 -      }
 -
 -      memcpy(ctx->bssid, bssid, ETH_ALEN);
 -      ctx->preauth_bssid = true;
 -
 -      ret = iwlagn_commit_rxon(priv, ctx);
 -
 -      if (ret == 0)
 -              goto out;
 -
 - out_remove_sta:
 -      iwl_remove_station(priv, sta_id, bssid);
 - out:
 -      mutex_unlock(&priv->shrd->mutex);
 -      IWL_DEBUG_MAC80211(priv, "leave\n");
 -
 -      return ret;
 -}
 -
 -static void iwlagn_mac_finish_tx_sync(struct ieee80211_hw *hw,
 -                                 struct ieee80211_vif *vif,
 -                                 const u8 *bssid,
 -                                 enum ieee80211_tx_sync_type type)
 -{
 -      struct iwl_priv *priv = hw->priv;
 -      struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
 -      struct iwl_rxon_context *ctx = vif_priv->ctx;
 -
 -      IWL_DEBUG_MAC80211(priv, "enter\n");
 -      mutex_lock(&priv->shrd->mutex);
 -
 -      if (iwl_is_associated_ctx(ctx))
 -              goto out;
 -
 -      iwl_remove_station(priv, ctx->ap_sta_id, bssid);
 -      ctx->preauth_bssid = false;
 -      /* no need to commit */
 - out:
 -      mutex_unlock(&priv->shrd->mutex);
 -      IWL_DEBUG_MAC80211(priv, "leave\n");
 -}
 -
 -/*****************************************************************************
 - *
 - * driver setup and teardown
 - *
 - *****************************************************************************/
 -
 -static void iwl_setup_deferred_work(struct iwl_priv *priv)
 -{
 -      priv->shrd->workqueue = create_singlethread_workqueue(DRV_NAME);
 -
 -      init_waitqueue_head(&priv->shrd->wait_command_queue);
 -
 -      INIT_WORK(&priv->restart, iwl_bg_restart);
 -      INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update);
 -      INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work);
 -      INIT_WORK(&priv->tx_flush, iwl_bg_tx_flush);
 -      INIT_WORK(&priv->bt_full_concurrency, iwl_bg_bt_full_concurrency);
 -      INIT_WORK(&priv->bt_runtime_config, iwl_bg_bt_runtime_config);
 -      INIT_DELAYED_WORK(&priv->hw_roc_disable_work,
 -                        iwlagn_disable_roc_work);
 -
 -      iwl_setup_scan_deferred_work(priv);
 -
 -      if (priv->cfg->lib->bt_setup_deferred_work)
 -              priv->cfg->lib->bt_setup_deferred_work(priv);
 -
 -      init_timer(&priv->statistics_periodic);
 -      priv->statistics_periodic.data = (unsigned long)priv;
 -      priv->statistics_periodic.function = iwl_bg_statistics_periodic;
 -
 -      init_timer(&priv->ucode_trace);
 -      priv->ucode_trace.data = (unsigned long)priv;
 -      priv->ucode_trace.function = iwl_bg_ucode_trace;
 -
 -      init_timer(&priv->watchdog);
 -      priv->watchdog.data = (unsigned long)priv;
 -      priv->watchdog.function = iwl_bg_watchdog;
 -}
 -
 -static void iwl_cancel_deferred_work(struct iwl_priv *priv)
 -{
 -      if (priv->cfg->lib->cancel_deferred_work)
 -              priv->cfg->lib->cancel_deferred_work(priv);
 -
 -      cancel_work_sync(&priv->run_time_calib_work);
 -      cancel_work_sync(&priv->beacon_update);
 -
 -      iwl_cancel_scan_deferred_work(priv);
 -
 -      cancel_work_sync(&priv->bt_full_concurrency);
 -      cancel_work_sync(&priv->bt_runtime_config);
 -      cancel_delayed_work_sync(&priv->hw_roc_disable_work);
 -
 -      del_timer_sync(&priv->statistics_periodic);
 -      del_timer_sync(&priv->ucode_trace);
 -}
 -
 -static void iwl_init_hw_rates(struct iwl_priv *priv,
 -                            struct ieee80211_rate *rates)
 -{
 -      int i;
 -
 -      for (i = 0; i < IWL_RATE_COUNT_LEGACY; i++) {
 -              rates[i].bitrate = iwl_rates[i].ieee * 5;
 -              rates[i].hw_value = i; /* Rate scaling will work on indexes */
 -              rates[i].hw_value_short = i;
 -              rates[i].flags = 0;
 -              if ((i >= IWL_FIRST_CCK_RATE) && (i <= IWL_LAST_CCK_RATE)) {
 -                      /*
 -                       * If CCK != 1M then set short preamble rate flag.
 -                       */
 -                      rates[i].flags |=
 -                              (iwl_rates[i].plcp == IWL_RATE_1M_PLCP) ?
 -                                      0 : IEEE80211_RATE_SHORT_PREAMBLE;
 -              }
 -      }
 -}
 -
 -static int iwl_init_drv(struct iwl_priv *priv)
 -{
 -      int ret;
 -
 -      spin_lock_init(&priv->shrd->sta_lock);
 -
 -      mutex_init(&priv->shrd->mutex);
 -
 -      priv->ieee_channels = NULL;
 -      priv->ieee_rates = NULL;
 -      priv->band = IEEE80211_BAND_2GHZ;
 -
 -      priv->iw_mode = NL80211_IFTYPE_STATION;
 -      priv->current_ht_config.smps = IEEE80211_SMPS_STATIC;
 -      priv->missed_beacon_threshold = IWL_MISSED_BEACON_THRESHOLD_DEF;
 -      priv->agg_tids_count = 0;
 -
 -      /* initialize force reset */
 -      priv->force_reset[IWL_RF_RESET].reset_duration =
 -              IWL_DELAY_NEXT_FORCE_RF_RESET;
 -      priv->force_reset[IWL_FW_RESET].reset_duration =
 -              IWL_DELAY_NEXT_FORCE_FW_RELOAD;
 -
 -      priv->rx_statistics_jiffies = jiffies;
 -
 -      /* Choose which receivers/antennas to use */
 -      iwlagn_set_rxon_chain(priv, &priv->contexts[IWL_RXON_CTX_BSS]);
 -
 -      iwl_init_scan_params(priv);
 -
 -      /* init bt coex */
 -      if (priv->cfg->bt_params &&
 -          priv->cfg->bt_params->advanced_bt_coexist) {
 -              priv->kill_ack_mask = IWLAGN_BT_KILL_ACK_MASK_DEFAULT;
 -              priv->kill_cts_mask = IWLAGN_BT_KILL_CTS_MASK_DEFAULT;
 -              priv->bt_valid = IWLAGN_BT_ALL_VALID_MSK;
 -              priv->bt_on_thresh = BT_ON_THRESHOLD_DEF;
 -              priv->bt_duration = BT_DURATION_LIMIT_DEF;
 -              priv->dynamic_frag_thresh = BT_FRAG_THRESHOLD_DEF;
 -      }
 -
 -      ret = iwl_init_channel_map(priv);
 -      if (ret) {
 -              IWL_ERR(priv, "initializing regulatory failed: %d\n", ret);
 -              goto err;
 -      }
 -
 -      ret = iwl_init_geos(priv);
 -      if (ret) {
 -              IWL_ERR(priv, "initializing geos failed: %d\n", ret);
 -              goto err_free_channel_map;
 -      }
 -      iwl_init_hw_rates(priv, priv->ieee_rates);
 -
 -      return 0;
 -
 -err_free_channel_map:
 -      iwl_free_channel_map(priv);
 -err:
 -      return ret;
 -}
 +err_free_channel_map:
 +      iwl_free_channel_map(priv);
 +err:
 +      return ret;
 +}
  
  static void iwl_uninit_drv(struct iwl_priv *priv)
  {
                kmem_cache_destroy(priv->tx_cmd_pool);
        kfree(priv->scan_cmd);
        kfree(priv->beacon_cmd);
 +      kfree(rcu_dereference_raw(priv->noa_data));
  #ifdef CONFIG_IWLWIFI_DEBUGFS
        kfree(priv->wowlan_sram);
  #endif
  }
  
 -static void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw,
 -                         enum ieee80211_rssi_event rssi_event)
 -{
 -      struct iwl_priv *priv = hw->priv;
 -
 -      IWL_DEBUG_MAC80211(priv, "enter\n");
 -      mutex_lock(&priv->shrd->mutex);
 -
 -      if (priv->cfg->bt_params &&
 -                      priv->cfg->bt_params->advanced_bt_coexist) {
 -              if (rssi_event == RSSI_EVENT_LOW)
 -                      priv->bt_enable_pspoll = true;
 -              else if (rssi_event == RSSI_EVENT_HIGH)
 -                      priv->bt_enable_pspoll = false;
 -
 -              iwlagn_send_advance_bt_config(priv);
 -      } else {
 -              IWL_DEBUG_MAC80211(priv, "Advanced BT coex disabled,"
 -                              "ignoring RSSI callback\n");
 -      }
 -
 -      mutex_unlock(&priv->shrd->mutex);
 -      IWL_DEBUG_MAC80211(priv, "leave\n");
 -}
 -
 -static int iwlagn_mac_set_tim(struct ieee80211_hw *hw,
 -                         struct ieee80211_sta *sta, bool set)
 -{
 -      struct iwl_priv *priv = hw->priv;
 -
 -      queue_work(priv->shrd->workqueue, &priv->beacon_update);
  
 -      return 0;
 -}
 -
 -struct ieee80211_ops iwlagn_hw_ops = {
 -      .tx = iwlagn_mac_tx,
 -      .start = iwlagn_mac_start,
 -      .stop = iwlagn_mac_stop,
 -#ifdef CONFIG_PM_SLEEP
 -      .suspend = iwlagn_mac_suspend,
 -      .resume = iwlagn_mac_resume,
 -#endif
 -      .add_interface = iwlagn_mac_add_interface,
 -      .remove_interface = iwlagn_mac_remove_interface,
 -      .change_interface = iwlagn_mac_change_interface,
 -      .config = iwlagn_mac_config,
 -      .configure_filter = iwlagn_configure_filter,
 -      .set_key = iwlagn_mac_set_key,
 -      .update_tkip_key = iwlagn_mac_update_tkip_key,
 -      .set_rekey_data = iwlagn_mac_set_rekey_data,
 -      .conf_tx = iwlagn_mac_conf_tx,
 -      .bss_info_changed = iwlagn_bss_info_changed,
 -      .ampdu_action = iwlagn_mac_ampdu_action,
 -      .hw_scan = iwlagn_mac_hw_scan,
 -      .sta_notify = iwlagn_mac_sta_notify,
 -      .sta_add = iwlagn_mac_sta_add,
 -      .sta_remove = iwlagn_mac_sta_remove,
 -      .channel_switch = iwlagn_mac_channel_switch,
 -      .flush = iwlagn_mac_flush,
 -      .tx_last_beacon = iwlagn_mac_tx_last_beacon,
 -      .remain_on_channel = iwlagn_mac_remain_on_channel,
 -      .cancel_remain_on_channel = iwlagn_mac_cancel_remain_on_channel,
 -      .rssi_callback = iwlagn_mac_rssi_callback,
 -      CFG80211_TESTMODE_CMD(iwlagn_mac_testmode_cmd)
 -      CFG80211_TESTMODE_DUMP(iwlagn_mac_testmode_dump)
 -      .tx_sync = iwlagn_mac_tx_sync,
 -      .finish_tx_sync = iwlagn_mac_finish_tx_sync,
 -      .set_tim = iwlagn_mac_set_tim,
 -};
  
  static u32 iwl_hw_detect(struct iwl_priv *priv)
  {
@@@ -1680,35 -3169,26 +1680,35 @@@ static int iwl_set_hw_params(struct iwl
        return priv->cfg->lib->set_hw_params(priv);
  }
  
 -/* This function both allocates and initializes hw and priv. */
 -static struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg)
 -{
 -      struct iwl_priv *priv;
 -      /* mac80211 allocates memory for this device instance, including
 -       *   space for this driver's private structure */
 -      struct ieee80211_hw *hw;
  
 -      hw = ieee80211_alloc_hw(sizeof(struct iwl_priv), &iwlagn_hw_ops);
 -      if (hw == NULL) {
 -              pr_err("%s: Can not allocate network device\n",
 -                     cfg->name);
 -              goto out;
 -      }
  
 -      priv = hw->priv;
 -      priv->hw = hw;
 +static void iwl_debug_config(struct iwl_priv *priv)
 +{
 +      dev_printk(KERN_INFO, bus(priv)->dev, "CONFIG_IWLWIFI_DEBUG "
 +#ifdef CONFIG_IWLWIFI_DEBUG
 +              "enabled\n");
 +#else
 +              "disabled\n");
 +#endif
 +      dev_printk(KERN_INFO, bus(priv)->dev, "CONFIG_IWLWIFI_DEBUGFS "
 +#ifdef CONFIG_IWLWIFI_DEBUGFS
 +              "enabled\n");
 +#else
 +              "disabled\n");
 +#endif
 +      dev_printk(KERN_INFO, bus(priv)->dev, "CONFIG_IWLWIFI_DEVICE_TRACING "
 +#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
 +              "enabled\n");
 +#else
 +              "disabled\n");
 +#endif
  
 -out:
 -      return hw;
 +      dev_printk(KERN_INFO, bus(priv)->dev, "CONFIG_IWLWIFI_DEVICE_SVTOOL "
 +#ifdef CONFIG_IWLWIFI_DEVICE_SVTOOL
 +              "enabled\n");
 +#else
 +              "disabled\n");
 +#endif
  }
  
  int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops,
        /************************
         * 1. Allocating HW data
         ************************/
 -      hw = iwl_alloc_all(cfg);
 +      hw = iwl_alloc_all();
        if (!hw) {
 +              pr_err("%s: Cannot allocate network device\n", cfg->name);
                err = -ENOMEM;
                goto out;
        }
  
        SET_IEEE80211_DEV(hw, bus(priv)->dev);
  
 +      /* what debugging capabilities we have */
 +      iwl_debug_config(priv);
 +
        IWL_DEBUG_INFO(priv, "*** LOAD DRIVER ***\n");
        priv->cfg = cfg;
  
@@@ -1920,7 -3396,7 +1920,7 @@@ void __devexit iwl_remove(struct iwl_pr
        /*This will stop the queues, move the device to low power state */
        iwl_trans_stop_device(trans(priv));
  
 -      iwl_dealloc_ucode(priv);
 +      iwl_dealloc_ucode(trans(priv));
  
        iwl_eeprom_free(priv);
  
@@@ -2022,9 -3498,10 +2022,10 @@@ MODULE_PARM_DESC(plcp_check, "Check plc
  module_param_named(ack_check, iwlagn_mod_params.ack_check, bool, S_IRUGO);
  MODULE_PARM_DESC(ack_check, "Check ack health (default: 0 [disabled])");
  
- module_param_named(wd_disable, iwlagn_mod_params.wd_disable, bool, S_IRUGO);
+ module_param_named(wd_disable, iwlagn_mod_params.wd_disable, int, S_IRUGO);
  MODULE_PARM_DESC(wd_disable,
-               "Disable stuck queue watchdog timer (default: 0 [enabled])");
+               "Disable stuck queue watchdog timer 0=system default, "
+               "1=disable, 2=enable (default: 0)");
  
  /*
   * set bt_coex_active to true, uCode will do kill/defer
  
  #include "iwl-dev.h"
  
 +struct iwlagn_ucode_capabilities {
 +      u32 max_probe_length;
 +      u32 standard_phy_calibration_size;
 +      u32 flags;
 +};
 +
  extern struct ieee80211_ops iwlagn_hw_ops;
  
  int iwl_reset_ict(struct iwl_trans *trans);
@@@ -83,15 -77,6 +83,15 @@@ static inline void iwl_set_calib_hdr(st
        hdr->data_valid = 1;
  }
  
 +void __iwl_down(struct iwl_priv *priv);
 +void iwl_down(struct iwl_priv *priv);
 +void iwlagn_prepare_restart(struct iwl_priv *priv);
 +
 +/* MAC80211 */
 +struct ieee80211_hw *iwl_alloc_all(void);
 +int iwlagn_mac_setup_register(struct iwl_priv *priv,
 +                            struct iwlagn_ucode_capabilities *capa);
 +
  /* RXON */
  int iwlagn_set_pan_params(struct iwl_priv *priv);
  int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
@@@ -101,6 -86,8 +101,8 @@@ void iwlagn_bss_info_changed(struct iee
                             struct ieee80211_vif *vif,
                             struct ieee80211_bss_conf *bss_conf,
                             u32 changes);
+ void iwlagn_config_ht40(struct ieee80211_conf *conf,
+                       struct iwl_rxon_context *ctx);
  
  /* uCode */
  int iwlagn_rx_calib_result(struct iwl_priv *priv,
@@@ -110,7 -97,8 +112,7 @@@ int iwlagn_send_bt_env(struct iwl_priv 
  void iwlagn_send_prio_tbl(struct iwl_priv *priv);
  int iwlagn_run_init_ucode(struct iwl_priv *priv);
  int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv,
 -                               struct fw_img *image,
 -                               enum iwlagn_ucode_type ucode_type);
 +                               enum iwl_ucode_type ucode_type);
  
  /* lib */
  int iwlagn_send_tx_power(struct iwl_priv *priv);
@@@ -119,12 -107,6 +121,12 @@@ u16 iwlagn_eeprom_calib_version(struct 
  int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control);
  void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control);
  int iwlagn_send_beacon_cmd(struct iwl_priv *priv);
 +#ifdef CONFIG_PM_SLEEP
 +int iwlagn_send_patterns(struct iwl_priv *priv,
 +                       struct cfg80211_wowlan *wowlan);
 +int iwlagn_suspend(struct iwl_priv *priv,
 +                 struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan);
 +#endif
  
  /* rx */
  int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band);
@@@ -216,6 -198,9 +218,6 @@@ int iwl_add_station_common(struct iwl_p
                           struct ieee80211_sta *sta, u8 *sta_id_r);
  int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id,
                       const u8 *addr);
 -int iwlagn_mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 -                     struct ieee80211_sta *sta);
 -
  u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
                    const u8 *addr, bool is_ap, struct ieee80211_sta *sta);
  
@@@ -333,6 -318,10 +335,6 @@@ void iwl_sta_modify_sleep_tx_count(stru
  int iwl_update_bcast_station(struct iwl_priv *priv,
                             struct iwl_rxon_context *ctx);
  int iwl_update_bcast_stations(struct iwl_priv *priv);
 -void iwlagn_mac_sta_notify(struct ieee80211_hw *hw,
 -                         struct ieee80211_vif *vif,
 -                         enum sta_notify_cmd cmd,
 -                         struct ieee80211_sta *sta);
  
  /* rate */
  static inline u32 iwl_ant_idx_to_flags(u8 ant_idx)
@@@ -1120,8 -1120,229 +1120,8 @@@ int iwl_send_statistics_request(struct 
                                        &statistics_cmd);
  }
  
 -int iwlagn_mac_conf_tx(struct ieee80211_hw *hw,
 -                  struct ieee80211_vif *vif, u16 queue,
 -                  const struct ieee80211_tx_queue_params *params)
 -{
 -      struct iwl_priv *priv = hw->priv;
 -      struct iwl_rxon_context *ctx;
 -      unsigned long flags;
 -      int q;
 -
 -      IWL_DEBUG_MAC80211(priv, "enter\n");
 -
 -      if (!iwl_is_ready_rf(priv->shrd)) {
 -              IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n");
 -              return -EIO;
 -      }
 -
 -      if (queue >= AC_NUM) {
 -              IWL_DEBUG_MAC80211(priv, "leave - queue >= AC_NUM %d\n", queue);
 -              return 0;
 -      }
 -
 -      q = AC_NUM - 1 - queue;
 -
 -      spin_lock_irqsave(&priv->shrd->lock, flags);
 -
 -      /*
 -       * MULTI-FIXME
 -       * This may need to be done per interface in nl80211/cfg80211/mac80211.
 -       */
 -      for_each_context(priv, ctx) {
 -              ctx->qos_data.def_qos_parm.ac[q].cw_min =
 -                      cpu_to_le16(params->cw_min);
 -              ctx->qos_data.def_qos_parm.ac[q].cw_max =
 -                      cpu_to_le16(params->cw_max);
 -              ctx->qos_data.def_qos_parm.ac[q].aifsn = params->aifs;
 -              ctx->qos_data.def_qos_parm.ac[q].edca_txop =
 -                              cpu_to_le16((params->txop * 32));
 -
 -              ctx->qos_data.def_qos_parm.ac[q].reserved1 = 0;
 -      }
 -
 -      spin_unlock_irqrestore(&priv->shrd->lock, flags);
 -
 -      IWL_DEBUG_MAC80211(priv, "leave\n");
 -      return 0;
 -}
 -
 -int iwlagn_mac_tx_last_beacon(struct ieee80211_hw *hw)
 -{
 -      struct iwl_priv *priv = hw->priv;
 -
 -      return priv->ibss_manager == IWL_IBSS_MANAGER;
 -}
 -
 -static int iwl_set_mode(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
 -{
 -      iwl_connection_init_rx_config(priv, ctx);
 -
 -      iwlagn_set_rxon_chain(priv, ctx);
 -
 -      return iwlagn_commit_rxon(priv, ctx);
 -}
 -
 -static int iwl_setup_interface(struct iwl_priv *priv,
 -                             struct iwl_rxon_context *ctx)
 -{
 -      struct ieee80211_vif *vif = ctx->vif;
 -      int err;
 -
 -      lockdep_assert_held(&priv->shrd->mutex);
 -
 -      /*
 -       * This variable will be correct only when there's just
 -       * a single context, but all code using it is for hardware
 -       * that supports only one context.
 -       */
 -      priv->iw_mode = vif->type;
 -
 -      ctx->is_active = true;
 -
 -      err = iwl_set_mode(priv, ctx);
 -      if (err) {
 -              if (!ctx->always_active)
 -                      ctx->is_active = false;
 -              return err;
 -      }
 -
 -      if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist &&
 -          vif->type == NL80211_IFTYPE_ADHOC) {
 -              /*
 -               * pretend to have high BT traffic as long as we
 -               * are operating in IBSS mode, as this will cause
 -               * the rate scaling etc. to behave as intended.
 -               */
 -              priv->bt_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_HIGH;
 -      }
 -
 -      return 0;
 -}
 -
 -int iwlagn_mac_add_interface(struct ieee80211_hw *hw,
 -                           struct ieee80211_vif *vif)
 -{
 -      struct iwl_priv *priv = hw->priv;
 -      struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
 -      struct iwl_rxon_context *tmp, *ctx = NULL;
 -      int err;
 -      enum nl80211_iftype viftype = ieee80211_vif_type_p2p(vif);
 -
 -      IWL_DEBUG_MAC80211(priv, "enter: type %d, addr %pM\n",
 -                         viftype, vif->addr);
 -
 -      cancel_delayed_work_sync(&priv->hw_roc_disable_work);
 -
 -      mutex_lock(&priv->shrd->mutex);
 -
 -      iwlagn_disable_roc(priv);
 -
 -      if (!iwl_is_ready_rf(priv->shrd)) {
 -              IWL_WARN(priv, "Try to add interface when device not ready\n");
 -              err = -EINVAL;
 -              goto out;
 -      }
 -
 -      for_each_context(priv, tmp) {
 -              u32 possible_modes =
 -                      tmp->interface_modes | tmp->exclusive_interface_modes;
 -
 -              if (tmp->vif) {
 -                      /* check if this busy context is exclusive */
 -                      if (tmp->exclusive_interface_modes &
 -                                              BIT(tmp->vif->type)) {
 -                              err = -EINVAL;
 -                              goto out;
 -                      }
 -                      continue;
 -              }
  
 -              if (!(possible_modes & BIT(viftype)))
 -                      continue;
 -
 -              /* have maybe usable context w/o interface */
 -              ctx = tmp;
 -              break;
 -      }
 -
 -      if (!ctx) {
 -              err = -EOPNOTSUPP;
 -              goto out;
 -      }
 -
 -      vif_priv->ctx = ctx;
 -      ctx->vif = vif;
 -
 -      err = iwl_setup_interface(priv, ctx);
 -      if (!err)
 -              goto out;
 -
 -      ctx->vif = NULL;
 -      priv->iw_mode = NL80211_IFTYPE_STATION;
 - out:
 -      mutex_unlock(&priv->shrd->mutex);
 -
 -      IWL_DEBUG_MAC80211(priv, "leave\n");
 -      return err;
 -}
 -
 -static void iwl_teardown_interface(struct iwl_priv *priv,
 -                                 struct ieee80211_vif *vif,
 -                                 bool mode_change)
 -{
 -      struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
 -
 -      lockdep_assert_held(&priv->shrd->mutex);
 -
 -      if (priv->scan_vif == vif) {
 -              iwl_scan_cancel_timeout(priv, 200);
 -              iwl_force_scan_end(priv);
 -      }
 -
 -      if (!mode_change) {
 -              iwl_set_mode(priv, ctx);
 -              if (!ctx->always_active)
 -                      ctx->is_active = false;
 -      }
 -
 -      /*
 -       * When removing the IBSS interface, overwrite the
 -       * BT traffic load with the stored one from the last
 -       * notification, if any. If this is a device that
 -       * doesn't implement this, this has no effect since
 -       * both values are the same and zero.
 -       */
 -      if (vif->type == NL80211_IFTYPE_ADHOC)
 -              priv->bt_traffic_load = priv->last_bt_traffic_load;
 -}
 -
 -void iwlagn_mac_remove_interface(struct ieee80211_hw *hw,
 -                            struct ieee80211_vif *vif)
 -{
 -      struct iwl_priv *priv = hw->priv;
 -      struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
 -
 -      IWL_DEBUG_MAC80211(priv, "enter\n");
 -
 -      mutex_lock(&priv->shrd->mutex);
 -
 -      if (WARN_ON(ctx->vif != vif)) {
 -              struct iwl_rxon_context *tmp;
 -              IWL_ERR(priv, "ctx->vif = %p, vif = %p\n", ctx->vif, vif);
 -              for_each_context(priv, tmp)
 -                      IWL_ERR(priv, "\tID = %d:\tctx = %p\tctx->vif = %p\n",
 -                              tmp->ctxid, tmp, tmp->vif);
 -      }
 -      ctx->vif = NULL;
 -
 -      iwl_teardown_interface(priv, vif, false);
  
 -      mutex_unlock(&priv->shrd->mutex);
 -
 -      IWL_DEBUG_MAC80211(priv, "leave\n");
 -
 -}
  
  #ifdef CONFIG_IWLWIFI_DEBUGFS
  
@@@ -1428,13 -1649,97 +1428,13 @@@ int iwl_force_reset(struct iwl_priv *pr
        return 0;
  }
  
 -int iwlagn_mac_change_interface(struct ieee80211_hw *hw,
 -                              struct ieee80211_vif *vif,
 -                              enum nl80211_iftype newtype, bool newp2p)
 -{
 -      struct iwl_priv *priv = hw->priv;
 -      struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
 -      struct iwl_rxon_context *bss_ctx = &priv->contexts[IWL_RXON_CTX_BSS];
 -      struct iwl_rxon_context *tmp;
 -      enum nl80211_iftype newviftype = newtype;
 -      u32 interface_modes;
 -      int err;
 -
 -      IWL_DEBUG_MAC80211(priv, "enter\n");
 -
 -      newtype = ieee80211_iftype_p2p(newtype, newp2p);
 -
 -      mutex_lock(&priv->shrd->mutex);
 -
 -      if (!ctx->vif || !iwl_is_ready_rf(priv->shrd)) {
 -              /*
 -               * Huh? But wait ... this can maybe happen when
 -               * we're in the middle of a firmware restart!
 -               */
 -              err = -EBUSY;
 -              goto out;
 -      }
 -
 -      interface_modes = ctx->interface_modes | ctx->exclusive_interface_modes;
 -
 -      if (!(interface_modes & BIT(newtype))) {
 -              err = -EBUSY;
 -              goto out;
 -      }
 -
 -      /*
 -       * Refuse a change that should be done by moving from the PAN
 -       * context to the BSS context instead, if the BSS context is
 -       * available and can support the new interface type.
 -       */
 -      if (ctx->ctxid == IWL_RXON_CTX_PAN && !bss_ctx->vif &&
 -          (bss_ctx->interface_modes & BIT(newtype) ||
 -           bss_ctx->exclusive_interface_modes & BIT(newtype))) {
 -              BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
 -              err = -EBUSY;
 -              goto out;
 -      }
 -
 -      if (ctx->exclusive_interface_modes & BIT(newtype)) {
 -              for_each_context(priv, tmp) {
 -                      if (ctx == tmp)
 -                              continue;
 -
 -                      if (!tmp->vif)
 -                              continue;
 -
 -                      /*
 -                       * The current mode switch would be exclusive, but
 -                       * another context is active ... refuse the switch.
 -                       */
 -                      err = -EBUSY;
 -                      goto out;
 -              }
 -      }
 -
 -      /* success */
 -      iwl_teardown_interface(priv, vif, true);
 -      vif->type = newviftype;
 -      vif->p2p = newp2p;
 -      err = iwl_setup_interface(priv, ctx);
 -      WARN_ON(err);
 -      /*
 -       * We've switched internally, but submitting to the
 -       * device may have failed for some reason. Mask this
 -       * error, because otherwise mac80211 will not switch
 -       * (and set the interface type back) and we'll be
 -       * out of sync with it.
 -       */
 -      err = 0;
 -
 - out:
 -      mutex_unlock(&priv->shrd->mutex);
 -      IWL_DEBUG_MAC80211(priv, "leave\n");
 -
 -      return err;
 -}
  
  int iwl_cmd_echo_test(struct iwl_priv *priv)
  {
        int ret;
        struct iwl_host_cmd cmd = {
                .id = REPLY_ECHO,
 +              .len = { 0 },
                .flags = CMD_SYNC,
        };
  
@@@ -1505,11 -1810,23 +1505,23 @@@ void iwl_setup_watchdog(struct iwl_pri
  {
        unsigned int timeout = priv->cfg->base_params->wd_timeout;
  
-       if (timeout && !iwlagn_mod_params.wd_disable)
-               mod_timer(&priv->watchdog,
-                         jiffies + msecs_to_jiffies(IWL_WD_TICK(timeout)));
-       else
-               del_timer(&priv->watchdog);
+       if (!iwlagn_mod_params.wd_disable) {
+               /* use system default */
+               if (timeout && !priv->cfg->base_params->wd_disable)
+                       mod_timer(&priv->watchdog,
+                               jiffies +
+                               msecs_to_jiffies(IWL_WD_TICK(timeout)));
+               else
+                       del_timer(&priv->watchdog);
+       } else {
+               /* module parameter overwrite default configuration */
+               if (timeout && iwlagn_mod_params.wd_disable == 2)
+                       mod_timer(&priv->watchdog,
+                               jiffies +
+                               msecs_to_jiffies(IWL_WD_TICK(timeout)));
+               else
+                       del_timer(&priv->watchdog);
+       }
  }
  
  /**
@@@ -113,6 -113,7 +113,7 @@@ struct iwl_lib_ops 
   * @shadow_reg_enable: HW shadhow register bit
   * @no_idle_support: do not support idle mode
   * @hd_v2: v2 of enhanced sensitivity value, used for 2000 series and up
+  * wd_disable: disable watchdog timer
   */
  struct iwl_base_params {
        int eeprom_size;
        const bool shadow_reg_enable;
        const bool no_idle_support;
        const bool hd_v2;
+       const bool wd_disable;
  };
  /*
   * @advanced_bt_coexist: support advanced bt coexist
@@@ -184,9 -186,8 +186,9 @@@ struct iwl_ht_params 
   * @ht_params: point to ht patameters
   * @bt_params: pointer to bt parameters
   * @pa_type: used by 6000 series only to identify the type of Power Amplifier
 - * @need_dc_calib: need to perform init dc calibration
   * @need_temp_offset_calib: need to perform temperature offset calibration
 + * @no_xtal_calib: some devices do not need crystal calibration data,
 + *    don't send it to those
   * @scan_antennas: available antenna for scan operation
   * @led_mode: 0=blinking, 1=On(RF On)/Off(RF Off)
   * @adv_pm: advance power management
@@@ -223,8 -224,8 +225,8 @@@ struct iwl_cfg 
        struct iwl_ht_params *ht_params;
        struct iwl_bt_params *bt_params;
        enum iwl_pa_type pa_type;         /* if used set to IWL_PA_SYSTEM */
 -      const bool need_dc_calib;         /* if used set to true */
        const bool need_temp_offset_calib; /* if used set to true */
 +      const bool no_xtal_calib;
        u8 scan_rx_antennas[IEEE80211_NUM_BANDS];
        enum iwl_led_mode led_mode;
        const bool adv_pm;
   *   L i b                 *
   ***************************/
  
 -int iwlagn_mac_conf_tx(struct ieee80211_hw *hw,
 -                  struct ieee80211_vif *vif, u16 queue,
 -                  const struct ieee80211_tx_queue_params *params);
 -int iwlagn_mac_tx_last_beacon(struct ieee80211_hw *hw);
  void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
                           int hw_decrypt);
  int iwl_check_rxon_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
@@@ -257,6 -262,13 +259,6 @@@ bool iwl_is_ht40_tx_allowed(struct iwl_
  void iwl_connection_init_rx_config(struct iwl_priv *priv,
                                   struct iwl_rxon_context *ctx);
  void iwl_set_rate(struct iwl_priv *priv);
 -int iwlagn_mac_add_interface(struct ieee80211_hw *hw,
 -                        struct ieee80211_vif *vif);
 -void iwlagn_mac_remove_interface(struct ieee80211_hw *hw,
 -                            struct ieee80211_vif *vif);
 -int iwlagn_mac_change_interface(struct ieee80211_hw *hw,
 -                           struct ieee80211_vif *vif,
 -                           enum nl80211_iftype newtype, bool newp2p);
  int iwl_cmd_echo_test(struct iwl_priv *priv);
  #ifdef CONFIG_IWLWIFI_DEBUGFS
  int iwl_alloc_traffic_mem(struct iwl_priv *priv);
@@@ -313,6 -325,9 +315,6 @@@ void iwl_init_scan_params(struct iwl_pr
  int iwl_scan_cancel(struct iwl_priv *priv);
  void iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);
  void iwl_force_scan_end(struct iwl_priv *priv);
 -int iwlagn_mac_hw_scan(struct ieee80211_hw *hw,
 -                  struct ieee80211_vif *vif,
 -                  struct cfg80211_scan_request *req);
  void iwl_internal_short_hw_scan(struct iwl_priv *priv);
  int iwl_force_reset(struct iwl_priv *priv, int mode, bool external);
  u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
@@@ -120,7 -120,7 +120,7 @@@ extern struct iwl_mod_params iwlagn_mod
   * @restart_fw: restart firmware, default = 1
   * @plcp_check: enable plcp health check, default = true
   * @ack_check: disable ack health check, default = false
-  * @wd_disable: enable stuck queue check, default = false
+  * @wd_disable: enable stuck queue check, default = 0
   * @bt_coex_active: enable bt coex, default = true
   * @led_mode: system default, default = 0
   * @no_sleep_autoadjust: disable autoadjust, default = true
@@@ -141,7 -141,7 +141,7 @@@ struct iwl_mod_params 
        int restart_fw;
        bool plcp_check;
        bool ack_check;
-       bool wd_disable;
+       int  wd_disable;
        bool bt_coex_active;
        int led_mode;
        bool no_sleep_autoadjust;
   * @ct_kill_exit_threshold: when to reeable the device - in hw dependent unit
   *    relevant for 1000, 6000 and up
   * @wd_timeout: TX queues watchdog timeout
 - * @calib_init_cfg: setup initial calibrations for the hw
   * @calib_rt_cfg: setup runtime calibrations for the hw
   * @struct iwl_sensitivity_ranges: range of sensitivity values
   */
@@@ -194,6 -195,7 +194,6 @@@ struct iwl_hw_params 
        u32 ct_kill_exit_threshold;
        unsigned int wd_timeout;
  
 -      u32 calib_init_cfg;
        u32 calib_rt_cfg;
        const struct iwl_sensitivity_ranges *sens;
  };
@@@ -990,29 -990,16 +990,16 @@@ static int iwl_trans_tx_stop(struct iwl
        return 0;
  }
  
- static void iwl_trans_pcie_disable_sync_irq(struct iwl_trans *trans)
+ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
  {
        unsigned long flags;
-       struct iwl_trans_pcie *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
  
+       /* tell the device to stop sending interrupts */
        spin_lock_irqsave(&trans->shrd->lock, flags);
        iwl_disable_interrupts(trans);
        spin_unlock_irqrestore(&trans->shrd->lock, flags);
  
-       /* wait to make sure we flush pending tasklet*/
-       synchronize_irq(bus(trans)->irq);
-       tasklet_kill(&trans_pcie->irq_tasklet);
- }
- static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
- {
-       /* stop and reset the on-board processor */
-       iwl_write32(bus(trans), CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
-       /* tell the device to stop sending interrupts */
-       iwl_trans_pcie_disable_sync_irq(trans);
        /* device going down, Stop using ICT table */
        iwl_disable_ict(trans);
  
  
        /* Stop the device, and put it in low power state */
        iwl_apm_stop(priv(trans));
+       /* Upon stop, the APM issues an interrupt if HW RF kill is set.
+        * Clean again the interrupt here
+        */
+       spin_lock_irqsave(&trans->shrd->lock, flags);
+       iwl_disable_interrupts(trans);
+       spin_unlock_irqrestore(&trans->shrd->lock, flags);
+       /* wait to make sure we flush pending tasklet*/
+       synchronize_irq(bus(trans)->irq);
+       tasklet_kill(&trans_pcie->irq_tasklet);
+       /* stop and reset the on-board processor */
+       iwl_write32(bus(trans), CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
  }
  
  static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
                hdr->seq_ctrl = hdr->seq_ctrl &
                                cpu_to_le16(IEEE80211_SCTL_FRAG);
                hdr->seq_ctrl |= cpu_to_le16(seq_number);
 -              seq_number += 0x10;
                /* aggregation is on for this <sta,tid> */
                if (info->flags & IEEE80211_TX_CTL_AMPDU) {
 -                      WARN_ON_ONCE(tid_data->agg.state != IWL_AGG_ON);
 +                      if (WARN_ON_ONCE(tid_data->agg.state != IWL_AGG_ON)) {
 +                              IWL_ERR(trans, "TX_CTL_AMPDU while not in AGG:"
 +                                      " Tx flags = 0x%08x, agg.state = %d",
 +                                      info->flags, tid_data->agg.state);
 +                              IWL_ERR(trans, "sta_id = %d, tid = %d "
 +                                      "txq_id = %d, seq_num = %d", sta_id,
 +                                      tid, tid_data->agg.txq_id,
 +                                      seq_number >> 4);
 +                      }
                        txq_id = tid_data->agg.txq_id;
                        is_agg = true;
                }
 +              seq_number += 0x10;
        }
  
        /* Copy MAC header from skb into command buffer */
                        txq->need_update = 1;
                        iwl_txq_update_write_ptr(trans, txq);
                } else {
 -                      iwl_stop_queue(trans, txq);
 +                      iwl_stop_queue(trans, txq, "Queue is full");
                }
        }
        return 0;
@@@ -1291,21 -1284,20 +1292,21 @@@ static int iwlagn_txq_check_empty(struc
                /* aggregated HW queue */
                if ((txq_id  == tid_data->agg.txq_id) &&
                    (q->read_ptr == q->write_ptr)) {
 -                      IWL_DEBUG_HT(trans,
 +                      IWL_DEBUG_TX_QUEUES(trans,
                                "HW queue empty: continue DELBA flow\n");
                        iwl_trans_pcie_txq_agg_disable(trans, txq_id);
                        tid_data->agg.state = IWL_AGG_OFF;
                        iwl_stop_tx_ba_trans_ready(priv(trans),
                                                   NUM_IWL_RXON_CTX,
                                                   sta_id, tid);
 -                      iwl_wake_queue(trans, &trans_pcie->txq[txq_id]);
 +                      iwl_wake_queue(trans, &trans_pcie->txq[txq_id],
 +                                     "DELBA flow complete");
                }
                break;
        case IWL_EMPTYING_HW_QUEUE_ADDBA:
                /* We are reclaiming the last packet of the queue */
                if (tid_data->tfds_in_queue == 0) {
 -                      IWL_DEBUG_HT(trans,
 +                      IWL_DEBUG_TX_QUEUES(trans,
                                "HW queue empty: continue ADDBA flow\n");
                        tid_data->agg.state = IWL_AGG_ON;
                        iwl_start_tx_ba_trans_ready(priv(trans),
@@@ -1358,12 -1350,12 +1359,12 @@@ static void iwl_trans_pcie_reclaim(stru
        }
  
        if (txq->q.read_ptr != tfd_num) {
 -              IWL_DEBUG_TX_REPLY(trans, "Retry scheduler reclaim "
 -                              "scd_ssn=%d idx=%d txq=%d swq=%d\n",
 -                              ssn , tfd_num, txq_id, txq->swq_id);
 +              IWL_DEBUG_TX_REPLY(trans, "[Q %d | AC %d] %d -> %d (%d)\n",
 +                              txq_id, iwl_get_queue_ac(txq), txq->q.read_ptr,
 +                              tfd_num, ssn);
                freed = iwl_tx_queue_reclaim(trans, txq_id, tfd_num, skbs);
                if (iwl_queue_space(&txq->q) > txq->q.low_mark && cond)
 -                      iwl_wake_queue(trans, txq);
 +                      iwl_wake_queue(trans, txq, "Packets reclaimed");
        }
  
        iwl_free_tfds_in_queue(trans, sta_id, tid, freed);
@@@ -1427,8 -1419,7 +1428,8 @@@ static int iwl_trans_pcie_resume(struc
  #endif /* CONFIG_PM_SLEEP */
  
  static void iwl_trans_pcie_wake_any_queue(struct iwl_trans *trans,
 -                                        enum iwl_rxon_context_id ctx)
 +                                        enum iwl_rxon_context_id ctx,
 +                                        const char *msg)
  {
        u8 ac, txq_id;
        struct iwl_trans_pcie *trans_pcie =
  
        for (ac = 0; ac < AC_NUM; ac++) {
                txq_id = trans_pcie->ac_to_queue[ctx][ac];
 -              IWL_DEBUG_INFO(trans, "Queue Status: Q[%d] %s\n",
 +              IWL_DEBUG_TX_QUEUES(trans, "Queue Status: Q[%d] %s\n",
                        ac,
                        (atomic_read(&trans_pcie->queue_stop_count[ac]) > 0)
                              ? "stopped" : "awake");
 -              iwl_wake_queue(trans, &trans_pcie->txq[txq_id]);
 +              iwl_wake_queue(trans, &trans_pcie->txq[txq_id], msg);
        }
  }
  
@@@ -1463,12 -1454,11 +1464,12 @@@ static struct iwl_trans *iwl_trans_pcie
        return iwl_trans;
  }
  
 -static void iwl_trans_pcie_stop_queue(struct iwl_trans *trans, int txq_id)
 +static void iwl_trans_pcie_stop_queue(struct iwl_trans *trans, int txq_id,
 +                                    const char *msg)
  {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
  
 -      iwl_stop_queue(trans, &trans_pcie->txq[txq_id]);
 +      iwl_stop_queue(trans, &trans_pcie->txq[txq_id], msg);
  }
  
  #define IWL_FLUSH_WAIT_MS     2000
@@@ -1523,12 -1513,8 +1524,12 @@@ static int iwl_trans_pcie_check_stuck_q
        if (time_after(jiffies, timeout)) {
                IWL_ERR(trans, "Queue %d stuck for %u ms.\n", q->id,
                        hw_params(trans).wd_timeout);
 -              IWL_ERR(trans, "Current read_ptr %d write_ptr %d\n",
 +              IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n",
                        q->read_ptr, q->write_ptr);
 +              IWL_ERR(trans, "Current HW read_ptr %d write_ptr %d\n",
 +                      iwl_read_prph(bus(trans), SCD_QUEUE_RDPTR(cnt))
 +                              & (TFD_QUEUE_SIZE_MAX - 1),
 +                      iwl_read_prph(bus(trans), SCD_QUEUE_WRPTR(cnt)));
                return 1;
        }
  
@@@ -485,7 -485,6 +485,7 @@@ static int lbs_cfg_set_channel(struct w
  static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
        struct cmd_header *resp)
  {
 +      struct cfg80211_bss *bss;
        struct cmd_ds_802_11_scan_rsp *scanresp = (void *)resp;
        int bsssize;
        const u8 *pos;
                                     LBS_SCAN_RSSI_TO_MBM(rssi)/100);
  
                        if (channel &&
 -                          !(channel->flags & IEEE80211_CHAN_DISABLED))
 -                              cfg80211_inform_bss(wiphy, channel,
 +                          !(channel->flags & IEEE80211_CHAN_DISABLED)) {
 +                              bss = cfg80211_inform_bss(wiphy, channel,
-                                       bssid, le64_to_cpu(*(__le64 *)tsfdesc),
+                                       bssid, get_unaligned_le64(tsfdesc),
                                        capa, intvl, ie, ielen,
                                        LBS_SCAN_RSSI_TO_MBM(rssi),
                                        GFP_KERNEL);
 +                              cfg80211_put_bss(bss);
 +                      }
                } else
                        lbs_deb_scan("scan response: missing BSS channel IE\n");
  
@@@ -1723,7 -1720,6 +1723,7 @@@ static void lbs_join_post(struct lbs_pr
                   2 + 2 +                      /* atim */
                   2 + 8];                      /* extended rates */
        u8 *fake = fake_ie;
 +      struct cfg80211_bss *bss;
  
        lbs_deb_enter(LBS_DEB_CFG80211);
  
        *fake++ = 0x6c;
        lbs_deb_hex(LBS_DEB_CFG80211, "IE", fake_ie, fake - fake_ie);
  
 -      cfg80211_inform_bss(priv->wdev->wiphy,
 -                          params->channel,
 -                          bssid,
 -                          0,
 -                          capability,
 -                          params->beacon_interval,
 -                          fake_ie, fake - fake_ie,
 -                          0, GFP_KERNEL);
 +      bss = cfg80211_inform_bss(priv->wdev->wiphy,
 +                                params->channel,
 +                                bssid,
 +                                0,
 +                                capability,
 +                                params->beacon_interval,
 +                                fake_ie, fake - fake_ie,
 +                                0, GFP_KERNEL);
 +      cfg80211_put_bss(bss);
  
        memcpy(priv->wdev->ssid, params->ssid, params->ssid_len);
        priv->wdev->ssid_len = params->ssid_len;
@@@ -21,7 -21,7 +21,7 @@@
  
  #include <linux/hardirq.h>
  #include <linux/interrupt.h>
 -#include <linux/moduleparam.h>
 +#include <linux/module.h>
  #include <linux/firmware.h>
  #include <linux/jiffies.h>
  #include <linux/list.h>
@@@ -995,6 -995,7 +995,7 @@@ static int if_spi_host_to_card(struct l
                spin_unlock_irqrestore(&card->buffer_lock, flags);
                break;
        default:
+               kfree(packet);
                netdev_err(priv->dev, "can't transfer buffer of type %d\n",
                           type);
                err = -EINVAL;
@@@ -1290,6 -1291,7 +1291,6 @@@ static struct spi_driver libertas_spi_d
        .remove = __devexit_p(libertas_spi_remove),
        .driver = {
                .name   = "libertas_spi",
 -              .bus    = &spi_bus_type,
                .owner  = THIS_MODULE,
                .pm     = &if_spi_pm_ops,
        },
@@@ -819,8 -819,10 +819,10 @@@ mwifiex_scan_setup_scan_config(struct m
                        wildcard_ssid_tlv->header.len = cpu_to_le16(
                                (u16) (ssid_len + sizeof(wildcard_ssid_tlv->
                                                         max_ssid_length)));
-                       wildcard_ssid_tlv->max_ssid_length =
-                               user_scan_in->ssid_list[ssid_idx].max_len;
+                       /* max_ssid_length = 0 tells firmware to perform
+                          specific scan for the SSID filled */
+                       wildcard_ssid_tlv->max_ssid_length = 0;
  
                        memcpy(wildcard_ssid_tlv->ssid,
                               user_scan_in->ssid_list[ssid_idx].ssid,
@@@ -1535,6 -1537,11 +1537,6 @@@ done
        return 0;
  }
  
 -static void mwifiex_free_bss_priv(struct cfg80211_bss *bss)
 -{
 -      kfree(bss->priv);
 -}
 -
  /*
   * This function handles the command response of scan.
   *
@@@ -1760,7 -1767,7 +1762,7 @@@ int mwifiex_ret_802_11_scan(struct mwif
                                              cap_info_bitmap, beacon_period,
                                              ie_buf, ie_len, rssi, GFP_KERNEL);
                                *(u8 *)bss->priv = band;
 -                              bss->free_priv = mwifiex_free_bss_priv;
 +                              cfg80211_put_bss(bss);
  
                                if (priv->media_connected && !memcmp(bssid,
                                        priv->curr_bss_params.bss_descriptor
@@@ -581,11 -581,13 +581,9 @@@ static void p54spi_op_stop(struct ieee8
        struct p54s_priv *priv = dev->priv;
        unsigned long flags;
  
 -      if (mutex_lock_interruptible(&priv->mutex)) {
 -              /* FIXME: how to handle this error? */
 -              return;
 -      }
 -
 +      mutex_lock(&priv->mutex);
        WARN_ON(priv->fw_state != FW_STATE_READY);
  
-       cancel_work_sync(&priv->work);
        p54spi_power_off(priv);
        spin_lock_irqsave(&priv->tx_lock, flags);
        INIT_LIST_HEAD(&priv->tx_pending);
  
        priv->fw_state = FW_STATE_OFF;
        mutex_unlock(&priv->mutex);
+       cancel_work_sync(&priv->work);
  }
  
  static int __devinit p54spi_probe(struct spi_device *spi)
        init_completion(&priv->fw_comp);
        INIT_LIST_HEAD(&priv->tx_pending);
        mutex_init(&priv->mutex);
+       spin_lock_init(&priv->tx_lock);
        SET_IEEE80211_DEV(hw, &spi->dev);
        priv->common.open = p54spi_op_start;
        priv->common.stop = p54spi_op_stop;
@@@ -699,6 -704,7 +700,6 @@@ static int __devexit p54spi_remove(stru
  static struct spi_driver p54spi_driver = {
        .driver = {
                .name           = "p54spi",
 -              .bus            = &spi_bus_type,
                .owner          = THIS_MODULE,
        },
  
@@@ -778,7 -778,7 +778,7 @@@ prism54_get_essid(struct net_device *nd
                dwrq->flags = 0;
                dwrq->length = 0;
        }
-       essid->octets[essid->length] = '\0';
+       essid->octets[dwrq->length] = '\0';
        memcpy(extra, essid->octets, dwrq->length);
        kfree(essid);
  
@@@ -2493,7 -2493,323 +2493,7 @@@ prism54_set_mac_address(struct net_devi
        return ret;
  }
  
 -/* Note: currently, use hostapd ioctl from the Host AP driver for WPA
 - * support. This is to be replaced with Linux wireless extensions once they
 - * get WPA support. */
 -
 -/* Note II: please leave all this together as it will be easier to remove later,
 - * once wireless extensions add WPA support -mcgrof */
 -
 -/* PRISM54_HOSTAPD ioctl() cmd: */
 -enum {
 -      PRISM2_SET_ENCRYPTION = 6,
 -      PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12,
 -      PRISM2_HOSTAPD_MLME = 13,
 -      PRISM2_HOSTAPD_SCAN_REQ = 14,
 -};
 -
  #define PRISM54_SET_WPA                       SIOCIWFIRSTPRIV+12
 -#define PRISM54_HOSTAPD                       SIOCIWFIRSTPRIV+25
 -#define PRISM54_DROP_UNENCRYPTED      SIOCIWFIRSTPRIV+26
 -
 -#define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024
 -#define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
 -      offsetof(struct prism2_hostapd_param, u.generic_elem.data)
 -
 -/* Maximum length for algorithm names (-1 for nul termination)
 - * used in ioctl() */
 -#define HOSTAP_CRYPT_ALG_NAME_LEN 16
 -
 -struct prism2_hostapd_param {
 -      u32 cmd;
 -      u8 sta_addr[ETH_ALEN];
 -      union {
 -             struct {
 -                     u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN];
 -                     u32 flags;
 -                     u32 err;
 -                     u8 idx;
 -                     u8 seq[8]; /* sequence counter (set: RX, get: TX) */
 -                     u16 key_len;
 -                     u8 key[0];
 -                     } crypt;
 -               struct {
 -                       u8 len;
 -                       u8 data[0];
 -               } generic_elem;
 -               struct {
 -#define MLME_STA_DEAUTH 0
 -#define MLME_STA_DISASSOC 1
 -                       u16 cmd;
 -                       u16 reason_code;
 -               } mlme;
 -               struct {
 -                       u8 ssid_len;
 -                       u8 ssid[32];
 -               } scan_req;
 -       } u;
 -};
 -
 -
 -static int
 -prism2_ioctl_set_encryption(struct net_device *dev,
 -      struct prism2_hostapd_param *param,
 -      int param_len)
 -{
 -      islpci_private *priv = netdev_priv(dev);
 -      int rvalue = 0, force = 0;
 -      int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0;
 -      union oid_res_t r;
 -
 -      /* with the new API, it's impossible to get a NULL pointer.
 -       * New version of iwconfig set the IW_ENCODE_NOKEY flag
 -       * when no key is given, but older versions don't. */
 -
 -      if (param->u.crypt.key_len > 0) {
 -              /* we have a key to set */
 -              int index = param->u.crypt.idx;
 -              int current_index;
 -              struct obj_key key = { DOT11_PRIV_TKIP, 0, "" };
 -
 -              /* get the current key index */
 -              rvalue = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r);
 -              current_index = r.u;
 -              /* Verify that the key is not marked as invalid */
 -              if (!(param->u.crypt.flags & IW_ENCODE_NOKEY)) {
 -                      key.length = param->u.crypt.key_len > sizeof (param->u.crypt.key) ?
 -                          sizeof (param->u.crypt.key) : param->u.crypt.key_len;
 -                      memcpy(key.key, param->u.crypt.key, key.length);
 -                      if (key.length == 32)
 -                              /* we want WPA-PSK */
 -                              key.type = DOT11_PRIV_TKIP;
 -                      if ((index < 0) || (index > 3))
 -                              /* no index provided use the current one */
 -                              index = current_index;
 -
 -                      /* now send the key to the card  */
 -                      rvalue |=
 -                          mgt_set_request(priv, DOT11_OID_DEFKEYX, index,
 -                                          &key);
 -              }
 -              /*
 -               * If a valid key is set, encryption should be enabled
 -               * (user may turn it off later).
 -               * This is also how "iwconfig ethX key on" works
 -               */
 -              if ((index == current_index) && (key.length > 0))
 -                      force = 1;
 -      } else {
 -              int index = (param->u.crypt.flags & IW_ENCODE_INDEX) - 1;
 -              if ((index >= 0) && (index <= 3)) {
 -                      /* we want to set the key index */
 -                      rvalue |=
 -                          mgt_set_request(priv, DOT11_OID_DEFKEYID, 0,
 -                                          &index);
 -              } else {
 -                      if (!(param->u.crypt.flags & IW_ENCODE_MODE)) {
 -                              /* we cannot do anything. Complain. */
 -                              return -EINVAL;
 -                      }
 -              }
 -      }
 -      /* now read the flags */
 -      if (param->u.crypt.flags & IW_ENCODE_DISABLED) {
 -              /* Encoding disabled,
 -               * authen = DOT11_AUTH_OS;
 -               * invoke = 0;
 -               * exunencrypt = 0; */
 -      }
 -      if (param->u.crypt.flags & IW_ENCODE_OPEN)
 -              /* Encode but accept non-encoded packets. No auth */
 -              invoke = 1;
 -      if ((param->u.crypt.flags & IW_ENCODE_RESTRICTED) || force) {
 -              /* Refuse non-encoded packets. Auth */
 -              authen = DOT11_AUTH_BOTH;
 -              invoke = 1;
 -              exunencrypt = 1;
 -      }
 -      /* do the change if requested  */
 -      if ((param->u.crypt.flags & IW_ENCODE_MODE) || force) {
 -              rvalue |=
 -                  mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen);
 -              rvalue |=
 -                  mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &invoke);
 -              rvalue |=
 -                  mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0,
 -                                  &exunencrypt);
 -      }
 -      return rvalue;
 -}
 -
 -static int
 -prism2_ioctl_set_generic_element(struct net_device *ndev,
 -      struct prism2_hostapd_param *param,
 -      int param_len)
 -{
 -       islpci_private *priv = netdev_priv(ndev);
 -       int max_len, len, alen, ret=0;
 -       struct obj_attachment *attach;
 -
 -       len = param->u.generic_elem.len;
 -       max_len = param_len - PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN;
 -       if (max_len < 0 || max_len < len)
 -               return -EINVAL;
 -
 -       alen = sizeof(*attach) + len;
 -       attach = kzalloc(alen, GFP_KERNEL);
 -       if (attach == NULL)
 -               return -ENOMEM;
 -
 -#define WLAN_FC_TYPE_MGMT 0
 -#define WLAN_FC_STYPE_ASSOC_REQ 0
 -#define WLAN_FC_STYPE_REASSOC_REQ 2
 -
 -       /* Note: endianness is covered by mgt_set_varlen */
 -
 -       attach->type = (WLAN_FC_TYPE_MGMT << 2) |
 -               (WLAN_FC_STYPE_ASSOC_REQ << 4);
 -       attach->id = -1;
 -       attach->size = len;
 -       memcpy(attach->data, param->u.generic_elem.data, len);
 -
 -       ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, len);
 -
 -       if (ret == 0) {
 -               attach->type = (WLAN_FC_TYPE_MGMT << 2) |
 -                       (WLAN_FC_STYPE_REASSOC_REQ << 4);
 -
 -             ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, len);
 -
 -             if (ret == 0)
 -                     printk(KERN_DEBUG "%s: WPA IE Attachment was set\n",
 -                                     ndev->name);
 -       }
 -
 -       kfree(attach);
 -       return ret;
 -
 -}
 -
 -static int
 -prism2_ioctl_mlme(struct net_device *dev, struct prism2_hostapd_param *param)
 -{
 -      return -EOPNOTSUPP;
 -}
 -
 -static int
 -prism2_ioctl_scan_req(struct net_device *ndev,
 -                     struct prism2_hostapd_param *param)
 -{
 -      islpci_private *priv = netdev_priv(ndev);
 -      struct iw_request_info info;
 -      int i, rvalue;
 -      struct obj_bsslist *bsslist;
 -      u32 noise = 0;
 -      char *extra = "";
 -      char *current_ev = "foo";
 -      union oid_res_t r;
 -
 -      if (islpci_get_state(priv) < PRV_STATE_INIT) {
 -              /* device is not ready, fail gently */
 -              return 0;
 -      }
 -
 -      /* first get the noise value. We will use it to report the link quality */
 -      rvalue = mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r);
 -      noise = r.u;
 -
 -      /* Ask the device for a list of known bss. We can report at most
 -       * IW_MAX_AP=64 to the range struct. But the device won't repport anything
 -       * if you change the value of IWMAX_BSS=24.
 -       */
 -      rvalue |= mgt_get_request(priv, DOT11_OID_BSSLIST, 0, NULL, &r);
 -      bsslist = r.ptr;
 -
 -      info.cmd = PRISM54_HOSTAPD;
 -      info.flags = 0;
 -
 -      /* ok now, scan the list and translate its info */
 -      for (i = 0; i < min(IW_MAX_AP, (int) bsslist->nr); i++)
 -              current_ev = prism54_translate_bss(ndev, &info, current_ev,
 -                                                 extra + IW_SCAN_MAX_DATA,
 -                                                 &(bsslist->bsslist[i]),
 -                                                 noise);
 -      kfree(bsslist);
 -
 -      return rvalue;
 -}
 -
 -static int
 -prism54_hostapd(struct net_device *ndev, struct iw_point *p)
 -{
 -       struct prism2_hostapd_param *param;
 -       int ret = 0;
 -       u32 uwrq;
 -
 -       printk(KERN_DEBUG "prism54_hostapd - len=%d\n", p->length);
 -       if (p->length < sizeof(struct prism2_hostapd_param) ||
 -           p->length > PRISM2_HOSTAPD_MAX_BUF_SIZE || !p->pointer)
 -               return -EINVAL;
 -
 -      param = memdup_user(p->pointer, p->length);
 -      if (IS_ERR(param))
 -              return PTR_ERR(param);
 -
 -       switch (param->cmd) {
 -       case PRISM2_SET_ENCRYPTION:
 -             printk(KERN_DEBUG "%s: Caught WPA supplicant set encryption request\n",
 -                             ndev->name);
 -               ret = prism2_ioctl_set_encryption(ndev, param, p->length);
 -               break;
 -       case PRISM2_HOSTAPD_SET_GENERIC_ELEMENT:
 -             printk(KERN_DEBUG "%s: Caught WPA supplicant set WPA IE request\n",
 -                             ndev->name);
 -               ret = prism2_ioctl_set_generic_element(ndev, param,
 -                                                      p->length);
 -               break;
 -       case PRISM2_HOSTAPD_MLME:
 -             printk(KERN_DEBUG "%s: Caught WPA supplicant MLME request\n",
 -                             ndev->name);
 -               ret = prism2_ioctl_mlme(ndev, param);
 -               break;
 -       case PRISM2_HOSTAPD_SCAN_REQ:
 -             printk(KERN_DEBUG "%s: Caught WPA supplicant scan request\n",
 -                             ndev->name);
 -               ret = prism2_ioctl_scan_req(ndev, param);
 -               break;
 -      case PRISM54_SET_WPA:
 -             printk(KERN_DEBUG "%s: Caught WPA supplicant wpa init request\n",
 -                             ndev->name);
 -             uwrq = 1;
 -             ret = prism54_set_wpa(ndev, NULL, &uwrq, NULL);
 -             break;
 -      case PRISM54_DROP_UNENCRYPTED:
 -             printk(KERN_DEBUG "%s: Caught WPA drop unencrypted request\n",
 -                             ndev->name);
 -#if 0
 -             uwrq = 0x01;
 -             mgt_set(priv, DOT11_OID_EXUNENCRYPTED, &uwrq);
 -             down_write(&priv->mib_sem);
 -             mgt_commit(priv);
 -             up_write(&priv->mib_sem);
 -#endif
 -             /* Not necessary, as set_wpa does it, should we just do it here though? */
 -             ret = 0;
 -             break;
 -       default:
 -             printk(KERN_DEBUG "%s: Caught a WPA supplicant request that is not supported\n",
 -                             ndev->name);
 -               ret = -EOPNOTSUPP;
 -               break;
 -       }
 -
 -       if (ret == 0 && copy_to_user(p->pointer, param, p->length))
 -               ret = -EFAULT;
 -
 -       kfree(param);
 -
 -       return ret;
 -}
  
  static int
  prism54_set_wpa(struct net_device *ndev, struct iw_request_info *info,
@@@ -2907,3 -3223,20 +2907,3 @@@ const struct iw_handler_def prism54_han
        .private_args = (struct iw_priv_args *) prism54_private_args,
        .get_wireless_stats = prism54_get_wireless_stats,
  };
 -
 -/* For wpa_supplicant */
 -
 -int
 -prism54_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
 -{
 -      struct iwreq *wrq = (struct iwreq *) rq;
 -      int ret = -1;
 -      switch (cmd) {
 -              case PRISM54_HOSTAPD:
 -              if (!capable(CAP_NET_ADMIN))
 -                      return -EPERM;
 -              ret = prism54_hostapd(ndev, &wrq->u.data);
 -              return ret;
 -      }
 -      return -EOPNOTSUPP;
 -}
@@@ -1203,10 -1203,8 +1203,10 @@@ void rt2800_config_filter(struct rt2x00
                           !(filter_flags & FIF_CONTROL));
        rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_PSPOLL,
                           !(filter_flags & FIF_PSPOLL));
 -      rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BA, 1);
 -      rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BAR, 0);
 +      rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BA,
 +                         !(filter_flags & FIF_CONTROL));
 +      rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_BAR,
 +                         !(filter_flags & FIF_CONTROL));
        rt2x00_set_field32(&reg, RX_FILTER_CFG_DROP_CNTL,
                           !(filter_flags & FIF_CONTROL));
        rt2800_register_write(rt2x00dev, RX_FILTER_CFG, reg);
@@@ -3773,7 -3771,7 +3773,7 @@@ static void rt2800_efuse_read(struct rt
        /* Apparently the data is read from end to start */
        rt2800_register_read_lock(rt2x00dev, EFUSE_DATA3, &reg);
        /* The returned value is in CPU order, but eeprom is le */
-       rt2x00dev->eeprom[i] = cpu_to_le32(reg);
+       *(u32 *)&rt2x00dev->eeprom[i] = cpu_to_le32(reg);
        rt2800_register_read_lock(rt2x00dev, EFUSE_DATA2, &reg);
        *(u32 *)&rt2x00dev->eeprom[i + 2] = cpu_to_le32(reg);
        rt2800_register_read_lock(rt2x00dev, EFUSE_DATA1, &reg);
@@@ -27,7 -27,6 +27,7 @@@
   *
   *****************************************************************************/
  
 +#include <linux/export.h>
  #include "wifi.h"
  #include "base.h"
  #include "ps.h"
@@@ -395,7 -394,7 +395,7 @@@ void rtl_lps_enter(struct ieee80211_hw 
        if (mac->link_state != MAC80211_LINKED)
                return;
  
-       spin_lock(&rtlpriv->locks.lps_lock);
+       spin_lock_irq(&rtlpriv->locks.lps_lock);
  
        /* Idle for a while if we connect to AP a while ago. */
        if (mac->cnt_after_linked >= 2) {
                }
        }
  
-       spin_unlock(&rtlpriv->locks.lps_lock);
+       spin_unlock_irq(&rtlpriv->locks.lps_lock);
  }
  
  /*Leave the leisure power save mode.*/
@@@ -416,8 -415,9 +416,9 @@@ void rtl_lps_leave(struct ieee80211_hw 
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       unsigned long flags;
  
-       spin_lock(&rtlpriv->locks.lps_lock);
+       spin_lock_irqsave(&rtlpriv->locks.lps_lock, flags);
  
        if (ppsc->fwctrl_lps) {
                if (ppsc->dot11_psmode != EACTIVE) {
                        rtl_lps_set_psmode(hw, EACTIVE);
                }
        }
-       spin_unlock(&rtlpriv->locks.lps_lock);
+       spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flags);
  }
  
  /* For sw LPS*/
@@@ -539,9 -539,9 +540,9 @@@ void rtl_swlps_rf_awake(struct ieee8021
                RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
        }
  
-       spin_lock(&rtlpriv->locks.lps_lock);
+       spin_lock_irq(&rtlpriv->locks.lps_lock);
        rtl_ps_set_rf_state(hw, ERFON, RF_CHANGE_BY_PS);
-       spin_unlock(&rtlpriv->locks.lps_lock);
+       spin_unlock_irq(&rtlpriv->locks.lps_lock);
  }
  
  void rtl_swlps_rfon_wq_callback(void *data)
@@@ -574,9 -574,9 +575,9 @@@ void rtl_swlps_rf_sleep(struct ieee8021
        if (rtlpriv->link_info.busytraffic)
                return;
  
-       spin_lock(&rtlpriv->locks.lps_lock);
+       spin_lock_irq(&rtlpriv->locks.lps_lock);
        rtl_ps_set_rf_state(hw, ERFSLEEP, RF_CHANGE_BY_PS);
-       spin_unlock(&rtlpriv->locks.lps_lock);
+       spin_unlock_irq(&rtlpriv->locks.lps_lock);
  
        if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM &&
                !RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) {
diff --combined net/mac80211/agg-tx.c
@@@ -15,7 -15,6 +15,7 @@@
  
  #include <linux/ieee80211.h>
  #include <linux/slab.h>
 +#include <linux/export.h>
  #include <net/mac80211.h>
  #include "ieee80211_i.h"
  #include "driver-ops.h"
@@@ -78,8 -77,7 +78,8 @@@ static void ieee80211_send_addba_reques
        memcpy(mgmt->da, da, ETH_ALEN);
        memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
        if (sdata->vif.type == NL80211_IFTYPE_AP ||
 -          sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
 +          sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
 +          sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
                memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
        else if (sdata->vif.type == NL80211_IFTYPE_STATION)
                memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
@@@ -162,6 -160,12 +162,12 @@@ int ___ieee80211_stop_tx_ba_session(str
                return -ENOENT;
        }
  
+       /* if we're already stopping ignore any new requests to stop */
+       if (test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
+               spin_unlock_bh(&sta->lock);
+               return -EALREADY;
+       }
        if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) {
                /* not even started yet! */
                ieee80211_assign_tid_tx(sta, tid, NULL);
                return 0;
        }
  
+       set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state);
        spin_unlock_bh(&sta->lock);
  
  #ifdef CONFIG_MAC80211_HT_DEBUG
               sta->sta.addr, tid);
  #endif /* CONFIG_MAC80211_HT_DEBUG */
  
-       set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state);
        del_timer_sync(&tid_tx->addba_resp_timer);
 +      del_timer_sync(&tid_tx->session_timer);
  
        /*
         * After this packets are no longer handed right through
         */
        clear_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state);
  
+       /*
+        * There might be a few packets being processed right now (on
+        * another CPU) that have already gotten past the aggregation
+        * check when it was still OPERATIONAL and consequently have
+        * IEEE80211_TX_CTL_AMPDU set. In that case, this code might
+        * call into the driver at the same time or even before the
+        * TX paths calls into it, which could confuse the driver.
+        *
+        * Wait for all currently running TX paths to finish before
+        * telling the driver. New packets will not go through since
+        * the aggregation session is no longer OPERATIONAL.
+        */
+       synchronize_net();
        tid_tx->stop_initiator = initiator;
        tid_tx->tx_stop = tx;
  
@@@ -350,28 -367,6 +370,28 @@@ void ieee80211_tx_ba_session_handle_sta
                                     tid_tx->timeout);
  }
  
 +/*
 + * After accepting the AddBA Response we activated a timer,
 + * resetting it after each frame that we send.
 + */
 +static void sta_tx_agg_session_timer_expired(unsigned long data)
 +{
 +      /* not an elegant detour, but there is no choice as the timer passes
 +       * only one argument, and various sta_info are needed here, so init
 +       * flow in sta_info_create gives the TID as data, while the timer_to_id
 +       * array gives the sta through container_of */
 +      u8 *ptid = (u8 *)data;
 +      u8 *timer_to_id = ptid - *ptid;
 +      struct sta_info *sta = container_of(timer_to_id, struct sta_info,
 +                                       timer_to_tid[0]);
 +
 +#ifdef CONFIG_MAC80211_HT_DEBUG
 +      printk(KERN_DEBUG "tx session timer expired on tid %d\n", (u16)*ptid);
 +#endif
 +
 +      ieee80211_stop_tx_ba_session(&sta->sta, *ptid);
 +}
 +
  int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
                                  u16 timeout)
  {
               pubsta->addr, tid);
  #endif /* CONFIG_MAC80211_HT_DEBUG */
  
 -      /*
 -       * The aggregation code is not prepared to handle
 -       * anything but STA/AP due to the BSSID handling.
 -       * IBSS could work in the code but isn't supported
 -       * by drivers or the standard.
 -       */
        if (sdata->vif.type != NL80211_IFTYPE_STATION &&
 +          sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
            sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
            sdata->vif.type != NL80211_IFTYPE_AP)
                return -EINVAL;
  
        tid_tx->timeout = timeout;
  
 -      /* Tx timer */
 +      /* response timer */
        tid_tx->addba_resp_timer.function = sta_addba_resp_timer_expired;
        tid_tx->addba_resp_timer.data = (unsigned long)&sta->timer_to_tid[tid];
        init_timer(&tid_tx->addba_resp_timer);
  
 +      /* tx timer */
 +      tid_tx->session_timer.function = sta_tx_agg_session_timer_expired;
 +      tid_tx->session_timer.data = (unsigned long)&sta->timer_to_tid[tid];
 +      init_timer(&tid_tx->session_timer);
 +
        /* assign a dialog token */
        sta->ampdu_mlme.dialog_token_allocator++;
        tid_tx->dialog_token = sta->ampdu_mlme.dialog_token_allocator;
@@@ -555,7 -550,7 +575,7 @@@ void ieee80211_start_tx_ba_cb(struct ie
        }
  
        mutex_lock(&local->sta_mtx);
 -      sta = sta_info_get(sdata, ra);
 +      sta = sta_info_get_bss(sdata, ra);
        if (!sta) {
                mutex_unlock(&local->sta_mtx);
  #ifdef CONFIG_MAC80211_HT_DEBUG
@@@ -684,7 -679,7 +704,7 @@@ void ieee80211_stop_tx_ba_cb(struct iee
  
        mutex_lock(&local->sta_mtx);
  
 -      sta = sta_info_get(sdata, ra);
 +      sta = sta_info_get_bss(sdata, ra);
        if (!sta) {
  #ifdef CONFIG_MAC80211_HT_DEBUG
                printk(KERN_DEBUG "Could not find station: %pM\n", ra);
@@@ -781,11 -776,27 +801,27 @@@ void ieee80211_process_addba_resp(struc
                goto out;
        }
  
-       del_timer(&tid_tx->addba_resp_timer);
+       del_timer_sync(&tid_tx->addba_resp_timer);
  
  #ifdef CONFIG_MAC80211_HT_DEBUG
        printk(KERN_DEBUG "switched off addBA timer for tid %d\n", tid);
  #endif
+       /*
+        * addba_resp_timer may have fired before we got here, and
+        * caused WANT_STOP to be set. If the stop then was already
+        * processed further, STOPPING might be set.
+        */
+       if (test_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state) ||
+           test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
+ #ifdef CONFIG_MAC80211_HT_DEBUG
+               printk(KERN_DEBUG
+                      "got addBA resp for tid %d but we already gave up\n",
+                      tid);
+ #endif
+               goto out;
+       }
        /*
         * IEEE 802.11-2007 7.3.1.14:
         * In an ADDBA Response frame, when the Status Code field
                        ieee80211_agg_tx_operational(local, sta, tid);
  
                sta->ampdu_mlme.addba_req_num[tid] = 0;
 +
 +              if (tid_tx->timeout)
 +                      mod_timer(&tid_tx->session_timer,
 +                                TU_TO_EXP_TIME(tid_tx->timeout));
 +
        } else {
                ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR,
                                                true);
@@@ -63,10 -63,10 +63,10 @@@ static ssize_t sta_flags_read(struct fi
        test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : ""
  
        int res = scnprintf(buf, sizeof(buf),
 -                          "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
 +                          "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
                            TEST(AUTH), TEST(ASSOC), TEST(PS_STA),
                            TEST(PS_DRIVER), TEST(AUTHORIZED),
 -                          TEST(SHORT_PREAMBLE), TEST(ASSOC_AP),
 +                          TEST(SHORT_PREAMBLE),
                            TEST(WME), TEST(WDS), TEST(CLEAR_PS_FILT),
                            TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL),
                            TEST(UAPSD), TEST(SP), TEST(TDLS_PEER),
@@@ -274,9 -274,9 +274,9 @@@ static ssize_t sta_ht_capa_read(struct 
  
                PRINT_HT_CAP((htc->cap & BIT(10)), "HT Delayed Block Ack");
  
-               PRINT_HT_CAP((htc->cap & BIT(11)), "Max AMSDU length: "
-                            "3839 bytes");
                PRINT_HT_CAP(!(htc->cap & BIT(11)), "Max AMSDU length: "
+                            "3839 bytes");
+               PRINT_HT_CAP((htc->cap & BIT(11)), "Max AMSDU length: "
                             "7935 bytes");
  
                /*
diff --combined net/mac80211/main.c
@@@ -92,9 -92,50 +92,9 @@@ static void ieee80211_reconfig_filter(s
        ieee80211_configure_filter(local);
  }
  
 -/*
 - * Returns true if we are logically configured to be on
 - * the operating channel AND the hardware-conf is currently
 - * configured on the operating channel.  Compares channel-type
 - * as well.
 - */
 -bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local)
 -{
 -      struct ieee80211_channel *chan, *scan_chan;
 -      enum nl80211_channel_type channel_type;
 -
 -      /* This logic needs to match logic in ieee80211_hw_config */
 -      if (local->scan_channel) {
 -              chan = local->scan_channel;
 -              /* If scanning on oper channel, use whatever channel-type
 -               * is currently in use.
 -               */
 -              if (chan == local->oper_channel)
 -                      channel_type = local->_oper_channel_type;
 -              else
 -                      channel_type = NL80211_CHAN_NO_HT;
 -      } else if (local->tmp_channel) {
 -              chan = scan_chan = local->tmp_channel;
 -              channel_type = local->tmp_channel_type;
 -      } else {
 -              chan = local->oper_channel;
 -              channel_type = local->_oper_channel_type;
 -      }
 -
 -      if (chan != local->oper_channel ||
 -          channel_type != local->_oper_channel_type)
 -              return false;
 -
 -      /* Check current hardware-config against oper_channel. */
 -      if ((local->oper_channel != local->hw.conf.channel) ||
 -          (local->_oper_channel_type != local->hw.conf.channel_type))
 -              return false;
 -
 -      return true;
 -}
 -
  int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
  {
 -      struct ieee80211_channel *chan, *scan_chan;
 +      struct ieee80211_channel *chan;
        int ret = 0;
        int power;
        enum nl80211_channel_type channel_type;
  
        might_sleep();
  
 -      scan_chan = local->scan_channel;
 -
        /* If this off-channel logic ever changes,  ieee80211_on_oper_channel
         * may need to change as well.
         */
        offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL;
 -      if (scan_chan) {
 -              chan = scan_chan;
 +      if (local->scan_channel) {
 +              chan = local->scan_channel;
                /* If scanning on oper channel, use whatever channel-type
                 * is currently in use.
                 */
                else
                        channel_type = NL80211_CHAN_NO_HT;
        } else if (local->tmp_channel) {
 -              chan = scan_chan = local->tmp_channel;
 +              chan = local->tmp_channel;
                channel_type = local->tmp_channel_type;
        } else {
                chan = local->oper_channel;
@@@ -517,19 -560,6 +517,19 @@@ ieee80211_default_mgmt_stypes[NUM_NL802
        },
  };
  
 +static const struct ieee80211_ht_cap mac80211_ht_capa_mod_mask = {
 +      .ampdu_params_info = IEEE80211_HT_AMPDU_PARM_FACTOR |
 +                           IEEE80211_HT_AMPDU_PARM_DENSITY,
 +
 +      .cap_info = cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
 +                              IEEE80211_HT_CAP_MAX_AMSDU |
 +                              IEEE80211_HT_CAP_SGI_40),
 +      .mcs = {
 +              .rx_mask = { 0xff, 0xff, 0xff, 0xff, 0xff,
 +                           0xff, 0xff, 0xff, 0xff, 0xff, },
 +      },
 +};
 +
  struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
                                        const struct ieee80211_ops *ops)
  {
  
        wiphy->flags |= WIPHY_FLAG_NETNS_OK |
                        WIPHY_FLAG_4ADDR_AP |
 -                      WIPHY_FLAG_4ADDR_STATION;
 +                      WIPHY_FLAG_4ADDR_STATION |
 +                      WIPHY_FLAG_REPORTS_OBSS |
 +                      WIPHY_FLAG_OFFCHAN_TX |
 +                      WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
 +
 +      wiphy->features = NL80211_FEATURE_SK_TX_STATUS;
  
        if (!ops->set_key)
                wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
  
        local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN);
  
 -      BUG_ON(!ops->tx);
 +      BUG_ON(!ops->tx && !ops->tx_frags);
        BUG_ON(!ops->start);
        BUG_ON(!ops->stop);
        BUG_ON(!ops->config);
        local->user_power_level = -1;
        local->uapsd_queues = IEEE80211_DEFAULT_UAPSD_QUEUES;
        local->uapsd_max_sp_len = IEEE80211_DEFAULT_MAX_SP_LEN;
 +      wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask;
  
        INIT_LIST_HEAD(&local->interfaces);
  
        INIT_WORK(&local->sched_scan_stopped_work,
                  ieee80211_sched_scan_stopped_work);
  
 +      spin_lock_init(&local->ack_status_lock);
 +      idr_init(&local->ack_status_frames);
 +      /* preallocate at least one entry */
 +      idr_pre_get(&local->ack_status_frames, GFP_KERNEL);
 +
        sta_info_init(local);
  
        for (i = 0; i < IEEE80211_MAX_QUEUES; i++) {
@@@ -738,6 -757,12 +738,12 @@@ int ieee80211_register_hw(struct ieee80
        if (!local->int_scan_req)
                return -ENOMEM;
  
+       for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+               if (!local->hw.wiphy->bands[band])
+                       continue;
+               local->int_scan_req->rates[band] = (u32) -1;
+       }
        /* if low-level driver supports AP, we also support VLAN */
        if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) {
                hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN);
@@@ -1026,13 -1051,6 +1032,13 @@@ void ieee80211_unregister_hw(struct iee
  }
  EXPORT_SYMBOL(ieee80211_unregister_hw);
  
 +static int ieee80211_free_ack_frame(int id, void *p, void *data)
 +{
 +      WARN_ONCE(1, "Have pending ack frames!\n");
 +      kfree_skb(p);
 +      return 0;
 +}
 +
  void ieee80211_free_hw(struct ieee80211_hw *hw)
  {
        struct ieee80211_local *local = hw_to_local(hw);
        if (local->wiphy_ciphers_allocated)
                kfree(local->hw.wiphy->cipher_suites);
  
 +      idr_for_each(&local->ack_status_frames,
 +                   ieee80211_free_ack_frame, NULL);
 +      idr_destroy(&local->ack_status_frames);
 +
        wiphy_free(local->hw.wiphy);
  }
  EXPORT_SYMBOL(ieee80211_free_hw);
diff --combined net/mac80211/mlme.c
  #include <linux/skbuff.h>
  #include <linux/if_arp.h>
  #include <linux/etherdevice.h>
 +#include <linux/moduleparam.h>
  #include <linux/rtnetlink.h>
  #include <linux/pm_qos.h>
  #include <linux/crc32.h>
  #include <linux/slab.h>
 +#include <linux/export.h>
  #include <net/mac80211.h>
  #include <asm/unaligned.h>
  
@@@ -209,7 -207,6 +209,7 @@@ static u32 ieee80211_enable_ht(struct i
                channel_type = NL80211_CHAN_HT20;
  
                if (!(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) &&
 +                  !ieee80111_cfg_override_disables_ht40(sdata) &&
                    (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) &&
                    (hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) {
                        switch(hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
@@@ -1121,8 -1118,6 +1121,8 @@@ static void ieee80211_set_disassoc(stru
  
        /* on the next assoc, re-program HT parameters */
        sdata->ht_opmode_valid = false;
 +      memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa));
 +      memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask));
  
        local->power_constr_level = 0;
  
@@@ -1362,6 -1357,9 +1362,6 @@@ static void __ieee80211_connection_loss
        ieee80211_set_disassoc(sdata, true, true);
        mutex_unlock(&ifmgd->mtx);
  
 -      mutex_lock(&local->mtx);
 -      ieee80211_recalc_idle(local);
 -      mutex_unlock(&local->mtx);
        /*
         * must be outside lock due to cfg80211,
         * but that's not a problem.
                                       IEEE80211_STYPE_DEAUTH,
                                       WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
                                       NULL, true);
 +
 +      mutex_lock(&local->mtx);
 +      ieee80211_recalc_idle(local);
 +      mutex_unlock(&local->mtx);
  }
  
  void ieee80211_beacon_connection_loss_work(struct work_struct *work)
@@@ -1472,47 -1466,6 +1472,47 @@@ ieee80211_rx_mgmt_disassoc(struct ieee8
        return RX_MGMT_CFG80211_DISASSOC;
  }
  
 +static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
 +                              u8 *supp_rates, unsigned int supp_rates_len,
 +                              u32 *rates, u32 *basic_rates,
 +                              bool *have_higher_than_11mbit,
 +                              int *min_rate, int *min_rate_index)
 +{
 +      int i, j;
 +
 +      for (i = 0; i < supp_rates_len; i++) {
 +              int rate = (supp_rates[i] & 0x7f) * 5;
 +              bool is_basic = !!(supp_rates[i] & 0x80);
 +
 +              if (rate > 110)
 +                      *have_higher_than_11mbit = true;
 +
 +              /*
 +               * BSS_MEMBERSHIP_SELECTOR_HT_PHY is defined in 802.11n-2009
 +               * 7.3.2.2 as a magic value instead of a rate. Hence, skip it.
 +               *
 +               * Note: Even through the membership selector and the basic
 +               *       rate flag share the same bit, they are not exactly
 +               *       the same.
 +               */
 +              if (!!(supp_rates[i] & 0x80) &&
 +                  (supp_rates[i] & 0x7f) == BSS_MEMBERSHIP_SELECTOR_HT_PHY)
 +                      continue;
 +
 +              for (j = 0; j < sband->n_bitrates; j++) {
 +                      if (sband->bitrates[j].bitrate == rate) {
 +                              *rates |= BIT(j);
 +                              if (is_basic)
 +                                      *basic_rates |= BIT(j);
 +                              if (rate < *min_rate) {
 +                                      *min_rate = rate;
 +                                      *min_rate_index = j;
 +                              }
 +                              break;
 +                      }
 +              }
 +      }
 +}
  
  static bool ieee80211_assoc_success(struct ieee80211_work *wk,
                                    struct ieee80211_mgmt *mgmt, size_t len)
        struct ieee802_11_elems elems;
        struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
        u32 changed = 0;
 -      int i, j, err;
 +      int err;
        bool have_higher_than_11mbit = false;
        u16 ap_ht_cap_flags;
        int min_rate = INT_MAX, min_rate_index = -1;
  
        set_sta_flag(sta, WLAN_STA_AUTH);
        set_sta_flag(sta, WLAN_STA_ASSOC);
 -      set_sta_flag(sta, WLAN_STA_ASSOC_AP);
        if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))
                set_sta_flag(sta, WLAN_STA_AUTHORIZED);
  
        basic_rates = 0;
        sband = local->hw.wiphy->bands[wk->chan->band];
  
 -      for (i = 0; i < elems.supp_rates_len; i++) {
 -              int rate = (elems.supp_rates[i] & 0x7f) * 5;
 -              bool is_basic = !!(elems.supp_rates[i] & 0x80);
 -
 -              if (rate > 110)
 -                      have_higher_than_11mbit = true;
 -
 -              for (j = 0; j < sband->n_bitrates; j++) {
 -                      if (sband->bitrates[j].bitrate == rate) {
 -                              rates |= BIT(j);
 -                              if (is_basic)
 -                                      basic_rates |= BIT(j);
 -                              if (rate < min_rate) {
 -                                      min_rate = rate;
 -                                      min_rate_index = j;
 -                              }
 -                              break;
 -                      }
 -              }
 -      }
 +      ieee80211_get_rates(sband, elems.supp_rates, elems.supp_rates_len,
 +                          &rates, &basic_rates, &have_higher_than_11mbit,
 +                          &min_rate, &min_rate_index);
  
 -      for (i = 0; i < elems.ext_supp_rates_len; i++) {
 -              int rate = (elems.ext_supp_rates[i] & 0x7f) * 5;
 -              bool is_basic = !!(elems.ext_supp_rates[i] & 0x80);
 -
 -              if (rate > 110)
 -                      have_higher_than_11mbit = true;
 -
 -              for (j = 0; j < sband->n_bitrates; j++) {
 -                      if (sband->bitrates[j].bitrate == rate) {
 -                              rates |= BIT(j);
 -                              if (is_basic)
 -                                      basic_rates |= BIT(j);
 -                              if (rate < min_rate) {
 -                                      min_rate = rate;
 -                                      min_rate_index = j;
 -                              }
 -                              break;
 -                      }
 -              }
 -      }
 +      ieee80211_get_rates(sband, elems.ext_supp_rates,
 +                          elems.ext_supp_rates_len, &rates, &basic_rates,
 +                          &have_higher_than_11mbit,
 +                          &min_rate, &min_rate_index);
  
        /*
         * some buggy APs don't advertise basic_rates. use the lowest
                sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
  
        if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
 -              ieee80211_ht_cap_ie_to_sta_ht_cap(sband,
 +              ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
                                elems.ht_cap_elem, &sta->sta.ht_cap);
  
        ap_ht_cap_flags = sta->sta.ht_cap.cap;
@@@ -1985,7 -1972,7 +1985,7 @@@ static void ieee80211_rx_mgmt_beacon(st
  
                sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
  
 -              ieee80211_ht_cap_ie_to_sta_ht_cap(sband,
 +              ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
                                elems.ht_cap_elem, &sta->sta.ht_cap);
  
                ap_ht_cap_flags = sta->sta.ht_cap.cap;
@@@ -2139,6 -2126,9 +2139,6 @@@ static void ieee80211_sta_connection_lo
  
        ieee80211_set_disassoc(sdata, true, true);
        mutex_unlock(&ifmgd->mtx);
 -      mutex_lock(&local->mtx);
 -      ieee80211_recalc_idle(local);
 -      mutex_unlock(&local->mtx);
        /*
         * must be outside lock due to cfg80211,
         * but that's not a problem.
        ieee80211_send_deauth_disassoc(sdata, bssid,
                        IEEE80211_STYPE_DEAUTH, reason,
                        NULL, true);
 +
 +      mutex_lock(&local->mtx);
 +      ieee80211_recalc_idle(local);
 +      mutex_unlock(&local->mtx);
 +
        mutex_lock(&ifmgd->mtx);
  }
  
@@@ -2301,6 -2286,7 +2301,7 @@@ void ieee80211_sta_quiesce(struct ieee8
  
        cancel_work_sync(&ifmgd->request_smps_work);
  
+       cancel_work_sync(&ifmgd->monitor_work);
        cancel_work_sync(&ifmgd->beacon_connection_loss_work);
        if (del_timer_sync(&ifmgd->timer))
                set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running);
        if (del_timer_sync(&ifmgd->chswitch_timer))
                set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running);
  
-       cancel_work_sync(&ifmgd->monitor_work);
        /* these will just be re-established on connection */
        del_timer_sync(&ifmgd->conn_mon_timer);
        del_timer_sync(&ifmgd->bcn_mon_timer);
@@@ -2645,13 -2630,6 +2645,13 @@@ int ieee80211_mgd_assoc(struct ieee8021
                        ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
  
  
 +      if (req->flags & ASSOC_REQ_DISABLE_HT)
 +              ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
 +
 +      memcpy(&ifmgd->ht_capa, &req->ht_capa, sizeof(ifmgd->ht_capa));
 +      memcpy(&ifmgd->ht_capa_mask, &req->ht_capa_mask,
 +             sizeof(ifmgd->ht_capa_mask));
 +
        if (req->ie && req->ie_len) {
                memcpy(wk->ie, req->ie, req->ie_len);
                wk->ie_len = req->ie_len;
diff --combined net/mac80211/rx.c
@@@ -16,7 -16,6 +16,7 @@@
  #include <linux/netdevice.h>
  #include <linux/etherdevice.h>
  #include <linux/rcupdate.h>
 +#include <linux/export.h>
  #include <net/mac80211.h>
  #include <net/ieee80211_radiotap.h>
  
@@@ -141,8 -140,9 +141,9 @@@ ieee80211_add_rx_radiotap_header(struc
        pos++;
  
        /* IEEE80211_RADIOTAP_RATE */
-       if (status->flag & RX_FLAG_HT) {
+       if (!rate || status->flag & RX_FLAG_HT) {
                /*
+                * Without rate information don't add it. If we have,
                 * MCS information is a separate field in radiotap,
                 * added below. The byte here is needed as padding
                 * for the channel though, so initialise it to 0.
        else if (status->flag & RX_FLAG_HT)
                put_unaligned_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ,
                                   pos);
-       else if (rate->flags & IEEE80211_RATE_ERP_G)
+       else if (rate && rate->flags & IEEE80211_RATE_ERP_G)
                put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ,
                                   pos);
-       else
+       else if (rate)
                put_unaligned_le16(IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ,
                                   pos);
+       else
+               put_unaligned_le16(IEEE80211_CHAN_2GHZ, pos);
        pos += 2;
  
        /* IEEE80211_RADIOTAP_DBM_ANTSIGNAL */
@@@ -745,11 -747,10 +748,11 @@@ static void ieee80211_rx_reorder_ampdu(
        struct ieee80211_local *local = rx->local;
        struct ieee80211_hw *hw = &local->hw;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
 +      struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
        struct sta_info *sta = rx->sta;
        struct tid_ampdu_rx *tid_agg_rx;
        u16 sc;
 -      int tid;
 +      u8 tid, ack_policy;
  
        if (!ieee80211_is_data_qos(hdr->frame_control))
                goto dont_reorder;
        if (!sta)
                goto dont_reorder;
  
 +      ack_policy = *ieee80211_get_qos_ctl(hdr) &
 +                   IEEE80211_QOS_CTL_ACK_POLICY_MASK;
        tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
  
        tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
        if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC)))
                goto dont_reorder;
  
 +      /* not part of a BA session */
 +      if (ack_policy != IEEE80211_QOS_CTL_ACK_POLICY_BLOCKACK &&
 +          ack_policy != IEEE80211_QOS_CTL_ACK_POLICY_NORMAL)
 +              goto dont_reorder;
 +
 +      /* not actually part of this BA session */
 +      if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
 +              goto dont_reorder;
 +
        /* new, potentially un-ordered, ampdu frame - process it */
  
        /* reset session timer */
@@@ -867,13 -857,6 +870,13 @@@ ieee80211_rx_h_check(struct ieee80211_r
                            rx->sdata->control_port_protocol)
                                return RX_CONTINUE;
                }
 +
 +              if (rx->sdata->vif.type == NL80211_IFTYPE_AP &&
 +                  cfg80211_rx_spurious_frame(rx->sdata->dev,
 +                                             hdr->addr2,
 +                                             GFP_ATOMIC))
 +                      return RX_DROP_UNUSABLE;
 +
                return RX_DROP_MONITOR;
        }
  
@@@ -1343,20 -1326,15 +1346,20 @@@ ieee80211_rx_h_sta_process(struct ieee8
  
                /*
                 * If we receive a 4-addr nullfunc frame from a STA
 -               * that was not moved to a 4-addr STA vlan yet, drop
 -               * the frame to the monitor interface, to make sure
 -               * that hostapd sees it
 +               * that was not moved to a 4-addr STA vlan yet send
 +               * the event to userspace and for older hostapd drop
 +               * the frame to the monitor interface.
                 */
                if (ieee80211_has_a4(hdr->frame_control) &&
                    (rx->sdata->vif.type == NL80211_IFTYPE_AP ||
                     (rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
 -                    !rx->sdata->u.vlan.sta)))
 +                    !rx->sdata->u.vlan.sta))) {
 +                      if (!test_and_set_sta_flag(sta, WLAN_STA_4ADDR_EVENT))
 +                              cfg80211_rx_unexpected_4addr_frame(
 +                                      rx->sdata->dev, sta->sta.addr,
 +                                      GFP_ATOMIC);
                        return RX_DROP_MONITOR;
 +              }
                /*
                 * Update counter and free packet here to avoid
                 * counting this as a dropped packed.
@@@ -1892,16 -1870,13 +1895,16 @@@ ieee80211_rx_h_amsdu(struct ieee80211_r
  static ieee80211_rx_result
  ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
  {
 -      struct ieee80211_hdr *hdr;
 +      struct ieee80211_hdr *fwd_hdr, *hdr;
 +      struct ieee80211_tx_info *info;
        struct ieee80211s_hdr *mesh_hdr;
 -      unsigned int hdrlen;
        struct sk_buff *skb = rx->skb, *fwd_skb;
        struct ieee80211_local *local = rx->local;
        struct ieee80211_sub_if_data *sdata = rx->sdata;
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
 +      struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
 +      __le16 reason = cpu_to_le16(WLAN_REASON_MESH_PATH_NOFORWARD);
 +      u16 q, hdrlen;
  
        hdr = (struct ieee80211_hdr *) skb->data;
        hdrlen = ieee80211_hdrlen(hdr->frame_control);
                return RX_CONTINUE;
  
        if (!mesh_hdr->ttl)
 -              /* illegal frame */
                return RX_DROP_MONITOR;
  
 -      if (ieee80211_queue_stopped(&local->hw, skb_get_queue_mapping(skb))) {
 -              IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
 -                                              dropped_frames_congestion);
 -              return RX_DROP_MONITOR;
 -      }
 -
        if (mesh_hdr->flags & MESH_FLAGS_AE) {
                struct mesh_path *mppath;
                char *proxied_addr;
            compare_ether_addr(sdata->vif.addr, hdr->addr3) == 0)
                return RX_CONTINUE;
  
 -      mesh_hdr->ttl--;
 +      q = ieee80211_select_queue_80211(local, skb, hdr);
 +      if (ieee80211_queue_stopped(&local->hw, q)) {
 +              IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_congestion);
 +              return RX_DROP_MONITOR;
 +      }
 +      skb_set_queue_mapping(skb, q);
  
 -      if (status->rx_flags & IEEE80211_RX_RA_MATCH) {
 -              if (!mesh_hdr->ttl)
 -                      IEEE80211_IFSTA_MESH_CTR_INC(&rx->sdata->u.mesh,
 -                                                   dropped_frames_ttl);
 -              else {
 -                      struct ieee80211_hdr *fwd_hdr;
 -                      struct ieee80211_tx_info *info;
 -
 -                      fwd_skb = skb_copy(skb, GFP_ATOMIC);
 -
 -                      if (!fwd_skb && net_ratelimit())
 -                              printk(KERN_DEBUG "%s: failed to clone mesh frame\n",
 -                                                 sdata->name);
 -                      if (!fwd_skb)
 -                              goto out;
 -
 -                      fwd_hdr =  (struct ieee80211_hdr *) fwd_skb->data;
 -                      memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN);
 -                      info = IEEE80211_SKB_CB(fwd_skb);
 -                      memset(info, 0, sizeof(*info));
 -                      info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
 -                      info->control.vif = &rx->sdata->vif;
 -                      if (is_multicast_ether_addr(fwd_hdr->addr1)) {
 -                              IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
 -                                                              fwded_mcast);
 -                              skb_set_queue_mapping(fwd_skb,
 -                                      ieee80211_select_queue(sdata, fwd_skb));
 -                              ieee80211_set_qos_hdr(sdata, fwd_skb);
 -                      } else {
 -                              int err;
 -                              /*
 -                               * Save TA to addr1 to send TA a path error if a
 -                               * suitable next hop is not found
 -                               */
 -                              memcpy(fwd_hdr->addr1, fwd_hdr->addr2,
 -                                              ETH_ALEN);
 -                              err = mesh_nexthop_lookup(fwd_skb, sdata);
 -                              /* Failed to immediately resolve next hop:
 -                               * fwded frame was dropped or will be added
 -                               * later to the pending skb queue.  */
 -                              if (err)
 -                                      return RX_DROP_MONITOR;
 -
 -                              IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
 -                                                              fwded_unicast);
 -                      }
 -                      IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
 -                                                   fwded_frames);
 -                      ieee80211_add_pending_skb(local, fwd_skb);
 -              }
 +      if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
 +              goto out;
 +
 +      if (!--mesh_hdr->ttl) {
 +              IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_ttl);
 +              return RX_DROP_MONITOR;
 +      }
 +
 +      fwd_skb = skb_copy(skb, GFP_ATOMIC);
 +      if (!fwd_skb) {
 +              if (net_ratelimit())
 +                      printk(KERN_DEBUG "%s: failed to clone mesh frame\n",
 +                                      sdata->name);
 +              goto out;
 +      }
 +
 +      fwd_hdr =  (struct ieee80211_hdr *) fwd_skb->data;
 +      info = IEEE80211_SKB_CB(fwd_skb);
 +      memset(info, 0, sizeof(*info));
 +      info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
 +      info->control.vif = &rx->sdata->vif;
 +      info->control.jiffies = jiffies;
 +      if (is_multicast_ether_addr(fwd_hdr->addr1)) {
 +              IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_mcast);
 +              memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN);
 +      } else if (!mesh_nexthop_lookup(fwd_skb, sdata)) {
 +              IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_unicast);
 +      } else {
 +              /* unable to resolve next hop */
 +              mesh_path_error_tx(ifmsh->mshcfg.element_ttl, fwd_hdr->addr3,
 +                                  0, reason, fwd_hdr->addr2, sdata);
 +              IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route);
 +              return RX_DROP_MONITOR;
        }
  
 +      IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_frames);
 +      ieee80211_add_pending_skb(local, fwd_skb);
   out:
        if (is_multicast_ether_addr(hdr->addr1) ||
            sdata->dev->flags & IFF_PROMISC)
@@@ -2021,17 -2013,12 +2024,17 @@@ ieee80211_rx_h_data(struct ieee80211_rx
                return RX_DROP_MONITOR;
  
        /*
 -       * Allow the cooked monitor interface of an AP to see 4-addr frames so
 -       * that a 4-addr station can be detected and moved into a separate VLAN
 +       * Send unexpected-4addr-frame event to hostapd. For older versions,
 +       * also drop the frame to cooked monitor interfaces.
         */
        if (ieee80211_has_a4(hdr->frame_control) &&
 -          sdata->vif.type == NL80211_IFTYPE_AP)
 +          sdata->vif.type == NL80211_IFTYPE_AP) {
 +              if (rx->sta &&
 +                  !test_and_set_sta_flag(rx->sta, WLAN_STA_4ADDR_EVENT))
 +                      cfg80211_rx_unexpected_4addr_frame(
 +                              rx->sdata->dev, rx->sta->sta.addr, GFP_ATOMIC);
                return RX_DROP_MONITOR;
 +      }
  
        err = __ieee80211_data_to_8023(rx, &port_control);
        if (unlikely(err))
@@@ -2186,18 -2173,6 +2189,18 @@@ ieee80211_rx_h_mgmt_check(struct ieee80
        if (!ieee80211_is_mgmt(mgmt->frame_control))
                return RX_DROP_MONITOR;
  
 +      if (rx->sdata->vif.type == NL80211_IFTYPE_AP &&
 +          ieee80211_is_beacon(mgmt->frame_control) &&
 +          !(rx->flags & IEEE80211_RX_BEACON_REPORTED)) {
 +              struct ieee80211_rx_status *status;
 +
 +              status = IEEE80211_SKB_RXCB(rx->skb);
 +              cfg80211_report_obss_beacon(rx->local->hw.wiphy,
 +                                          rx->skb->data, rx->skb->len,
 +                                          status->freq, GFP_ATOMIC);
 +              rx->flags |= IEEE80211_RX_BEACON_REPORTED;
 +      }
 +
        if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
                return RX_DROP_MONITOR;
  
@@@ -2231,8 -2206,13 +2234,8 @@@ ieee80211_rx_h_action(struct ieee80211_
  
        switch (mgmt->u.action.category) {
        case WLAN_CATEGORY_BACK:
 -              /*
 -               * The aggregation code is not prepared to handle
 -               * anything but STA/AP due to the BSSID handling;
 -               * IBSS could work in the code but isn't supported
 -               * by drivers or the standard.
 -               */
                if (sdata->vif.type != NL80211_IFTYPE_STATION &&
 +                  sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
                    sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
                    sdata->vif.type != NL80211_IFTYPE_AP)
                        break;
@@@ -2512,10 -2492,6 +2515,10 @@@ static void ieee80211_rx_cooked_monitor
                goto out_free_skb;
        rx->flags |= IEEE80211_RX_CMNTR;
  
 +      /* If there are no cooked monitor interfaces, just free the SKB */
 +      if (!local->cooked_mntrs)
 +              goto out_free_skb;
 +
        if (skb_headroom(skb) < sizeof(*rthdr) &&
            pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC))
                goto out_free_skb;
diff --combined net/mac80211/status.c
@@@ -9,7 -9,6 +9,7 @@@
   * published by the Free Software Foundation.
   */
  
 +#include <linux/export.h>
  #include <net/mac80211.h>
  #include "ieee80211_i.h"
  #include "rate.h"
@@@ -260,7 -259,7 +260,7 @@@ static void ieee80211_add_tx_radiotap_h
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
        struct ieee80211_radiotap_header *rthdr;
        unsigned char *pos;
-       __le16 txflags;
+       u16 txflags;
  
        rthdr = (struct ieee80211_radiotap_header *) skb_push(skb, rtap_len);
  
        txflags = 0;
        if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
            !is_multicast_ether_addr(hdr->addr1))
-               txflags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL);
+               txflags |= IEEE80211_RADIOTAP_F_TX_FAIL;
  
        if ((info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
            (info->status.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT))
-               txflags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS);
+               txflags |= IEEE80211_RADIOTAP_F_TX_CTS;
        else if (info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
-               txflags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS);
+               txflags |= IEEE80211_RADIOTAP_F_TX_RTS;
  
        put_unaligned_le16(txflags, pos);
        pos += 2;
@@@ -517,54 -516,27 +517,54 @@@ void ieee80211_tx_status(struct ieee802
        }
  
        if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) {
 -              struct ieee80211_work *wk;
                u64 cookie = (unsigned long)skb;
  
 -              rcu_read_lock();
 -              list_for_each_entry_rcu(wk, &local->work_list, list) {
 -                      if (wk->type != IEEE80211_WORK_OFFCHANNEL_TX)
 -                              continue;
 -                      if (wk->offchan_tx.frame != skb)
 -                              continue;
 -                      wk->offchan_tx.status = true;
 -                      break;
 -              }
 -              rcu_read_unlock();
 -              if (local->hw_roc_skb_for_status == skb) {
 -                      cookie = local->hw_roc_cookie ^ 2;
 -                      local->hw_roc_skb_for_status = NULL;
 +              if (ieee80211_is_nullfunc(hdr->frame_control) ||
 +                  ieee80211_is_qos_nullfunc(hdr->frame_control)) {
 +                      bool acked = info->flags & IEEE80211_TX_STAT_ACK;
 +                      cfg80211_probe_status(skb->dev, hdr->addr1,
 +                                            cookie, acked, GFP_ATOMIC);
 +              } else {
 +                      struct ieee80211_work *wk;
 +
 +                      rcu_read_lock();
 +                      list_for_each_entry_rcu(wk, &local->work_list, list) {
 +                              if (wk->type != IEEE80211_WORK_OFFCHANNEL_TX)
 +                                      continue;
 +                              if (wk->offchan_tx.frame != skb)
 +                                      continue;
 +                              wk->offchan_tx.status = true;
 +                              break;
 +                      }
 +                      rcu_read_unlock();
 +                      if (local->hw_roc_skb_for_status == skb) {
 +                              cookie = local->hw_roc_cookie ^ 2;
 +                              local->hw_roc_skb_for_status = NULL;
 +                      }
 +
 +                      cfg80211_mgmt_tx_status(
 +                              skb->dev, cookie, skb->data, skb->len,
 +                              !!(info->flags & IEEE80211_TX_STAT_ACK),
 +                              GFP_ATOMIC);
                }
 +      }
  
 -              cfg80211_mgmt_tx_status(
 -                      skb->dev, cookie, skb->data, skb->len,
 -                      !!(info->flags & IEEE80211_TX_STAT_ACK), GFP_ATOMIC);
 +      if (unlikely(info->ack_frame_id)) {
 +              struct sk_buff *ack_skb;
 +              unsigned long flags;
 +
 +              spin_lock_irqsave(&local->ack_status_lock, flags);
 +              ack_skb = idr_find(&local->ack_status_frames,
 +                                 info->ack_frame_id);
 +              if (ack_skb)
 +                      idr_remove(&local->ack_status_frames,
 +                                 info->ack_frame_id);
 +              spin_unlock_irqrestore(&local->ack_status_lock, flags);
 +
 +              /* consumes ack_skb */
 +              if (ack_skb)
 +                      skb_complete_wifi_ack(ack_skb,
 +                              info->flags & IEEE80211_TX_STAT_ACK);
        }
  
        /* this was a transmitted frame, but now we want to reuse it */
@@@ -637,29 -609,3 +637,29 @@@ void ieee80211_report_low_ack(struct ie
                                    num_packets, GFP_ATOMIC);
  }
  EXPORT_SYMBOL(ieee80211_report_low_ack);
 +
 +void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb)
 +{
 +      struct ieee80211_local *local = hw_to_local(hw);
 +      struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 +
 +      if (unlikely(info->ack_frame_id)) {
 +              struct sk_buff *ack_skb;
 +              unsigned long flags;
 +
 +              spin_lock_irqsave(&local->ack_status_lock, flags);
 +              ack_skb = idr_find(&local->ack_status_frames,
 +                                 info->ack_frame_id);
 +              if (ack_skb)
 +                      idr_remove(&local->ack_status_frames,
 +                                 info->ack_frame_id);
 +              spin_unlock_irqrestore(&local->ack_status_lock, flags);
 +
 +              /* consumes ack_skb */
 +              if (ack_skb)
 +                      dev_kfree_skb_any(ack_skb);
 +      }
 +
 +      dev_kfree_skb_any(skb);
 +}
 +EXPORT_SYMBOL(ieee80211_free_txskb);
diff --combined net/mac80211/util.c
  
  #include <net/mac80211.h>
  #include <linux/netdevice.h>
 +#include <linux/export.h>
  #include <linux/types.h>
  #include <linux/slab.h>
  #include <linux/skbuff.h>
  #include <linux/etherdevice.h>
  #include <linux/if_arp.h>
  #include <linux/bitmap.h>
 +#include <linux/crc32.h>
  #include <net/net_namespace.h>
  #include <net/cfg80211.h>
  #include <net/rtnetlink.h>
@@@ -97,13 -95,13 +97,13 @@@ u8 *ieee80211_get_bssid(struct ieee8021
  
  void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx)
  {
 -      struct sk_buff *skb = tx->skb;
 +      struct sk_buff *skb;
        struct ieee80211_hdr *hdr;
  
 -      do {
 +      skb_queue_walk(&tx->skbs, skb) {
                hdr = (struct ieee80211_hdr *) skb->data;
                hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
 -      } while ((skb = skb->next));
 +      }
  }
  
  int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
@@@ -565,172 -563,6 +565,172 @@@ void ieee80211_queue_delayed_work(struc
  }
  EXPORT_SYMBOL(ieee80211_queue_delayed_work);
  
 +u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
 +                             struct ieee802_11_elems *elems,
 +                             u64 filter, u32 crc)
 +{
 +      size_t left = len;
 +      u8 *pos = start;
 +      bool calc_crc = filter != 0;
 +
 +      memset(elems, 0, sizeof(*elems));
 +      elems->ie_start = start;
 +      elems->total_len = len;
 +
 +      while (left >= 2) {
 +              u8 id, elen;
 +
 +              id = *pos++;
 +              elen = *pos++;
 +              left -= 2;
 +
 +              if (elen > left)
 +                      break;
 +
 +              if (calc_crc && id < 64 && (filter & (1ULL << id)))
 +                      crc = crc32_be(crc, pos - 2, elen + 2);
 +
 +              switch (id) {
 +              case WLAN_EID_SSID:
 +                      elems->ssid = pos;
 +                      elems->ssid_len = elen;
 +                      break;
 +              case WLAN_EID_SUPP_RATES:
 +                      elems->supp_rates = pos;
 +                      elems->supp_rates_len = elen;
 +                      break;
 +              case WLAN_EID_FH_PARAMS:
 +                      elems->fh_params = pos;
 +                      elems->fh_params_len = elen;
 +                      break;
 +              case WLAN_EID_DS_PARAMS:
 +                      elems->ds_params = pos;
 +                      elems->ds_params_len = elen;
 +                      break;
 +              case WLAN_EID_CF_PARAMS:
 +                      elems->cf_params = pos;
 +                      elems->cf_params_len = elen;
 +                      break;
 +              case WLAN_EID_TIM:
 +                      if (elen >= sizeof(struct ieee80211_tim_ie)) {
 +                              elems->tim = (void *)pos;
 +                              elems->tim_len = elen;
 +                      }
 +                      break;
 +              case WLAN_EID_IBSS_PARAMS:
 +                      elems->ibss_params = pos;
 +                      elems->ibss_params_len = elen;
 +                      break;
 +              case WLAN_EID_CHALLENGE:
 +                      elems->challenge = pos;
 +                      elems->challenge_len = elen;
 +                      break;
 +              case WLAN_EID_VENDOR_SPECIFIC:
 +                      if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 &&
 +                          pos[2] == 0xf2) {
 +                              /* Microsoft OUI (00:50:F2) */
 +
 +                              if (calc_crc)
 +                                      crc = crc32_be(crc, pos - 2, elen + 2);
 +
 +                              if (pos[3] == 1) {
 +                                      /* OUI Type 1 - WPA IE */
 +                                      elems->wpa = pos;
 +                                      elems->wpa_len = elen;
 +                              } else if (elen >= 5 && pos[3] == 2) {
 +                                      /* OUI Type 2 - WMM IE */
 +                                      if (pos[4] == 0) {
 +                                              elems->wmm_info = pos;
 +                                              elems->wmm_info_len = elen;
 +                                      } else if (pos[4] == 1) {
 +                                              elems->wmm_param = pos;
 +                                              elems->wmm_param_len = elen;
 +                                      }
 +                              }
 +                      }
 +                      break;
 +              case WLAN_EID_RSN:
 +                      elems->rsn = pos;
 +                      elems->rsn_len = elen;
 +                      break;
 +              case WLAN_EID_ERP_INFO:
 +                      elems->erp_info = pos;
 +                      elems->erp_info_len = elen;
 +                      break;
 +              case WLAN_EID_EXT_SUPP_RATES:
 +                      elems->ext_supp_rates = pos;
 +                      elems->ext_supp_rates_len = elen;
 +                      break;
 +              case WLAN_EID_HT_CAPABILITY:
 +                      if (elen >= sizeof(struct ieee80211_ht_cap))
 +                              elems->ht_cap_elem = (void *)pos;
 +                      break;
 +              case WLAN_EID_HT_INFORMATION:
 +                      if (elen >= sizeof(struct ieee80211_ht_info))
 +                              elems->ht_info_elem = (void *)pos;
 +                      break;
 +              case WLAN_EID_MESH_ID:
 +                      elems->mesh_id = pos;
 +                      elems->mesh_id_len = elen;
 +                      break;
 +              case WLAN_EID_MESH_CONFIG:
 +                      if (elen >= sizeof(struct ieee80211_meshconf_ie))
 +                              elems->mesh_config = (void *)pos;
 +                      break;
 +              case WLAN_EID_PEER_MGMT:
 +                      elems->peering = pos;
 +                      elems->peering_len = elen;
 +                      break;
 +              case WLAN_EID_PREQ:
 +                      elems->preq = pos;
 +                      elems->preq_len = elen;
 +                      break;
 +              case WLAN_EID_PREP:
 +                      elems->prep = pos;
 +                      elems->prep_len = elen;
 +                      break;
 +              case WLAN_EID_PERR:
 +                      elems->perr = pos;
 +                      elems->perr_len = elen;
 +                      break;
 +              case WLAN_EID_RANN:
 +                      if (elen >= sizeof(struct ieee80211_rann_ie))
 +                              elems->rann = (void *)pos;
 +                      break;
 +              case WLAN_EID_CHANNEL_SWITCH:
 +                      elems->ch_switch_elem = pos;
 +                      elems->ch_switch_elem_len = elen;
 +                      break;
 +              case WLAN_EID_QUIET:
 +                      if (!elems->quiet_elem) {
 +                              elems->quiet_elem = pos;
 +                              elems->quiet_elem_len = elen;
 +                      }
 +                      elems->num_of_quiet_elem++;
 +                      break;
 +              case WLAN_EID_COUNTRY:
 +                      elems->country_elem = pos;
 +                      elems->country_elem_len = elen;
 +                      break;
 +              case WLAN_EID_PWR_CONSTRAINT:
 +                      elems->pwr_constr_elem = pos;
 +                      elems->pwr_constr_elem_len = elen;
 +                      break;
 +              case WLAN_EID_TIMEOUT_INTERVAL:
 +                      elems->timeout_int = pos;
 +                      elems->timeout_int_len = elen;
 +                      break;
 +              default:
 +                      break;
 +              }
 +
 +              left -= elen;
 +              pos += elen;
 +      }
 +
 +      return crc;
 +}
 +
  void ieee802_11_parse_elems(u8 *start, size_t len,
                            struct ieee802_11_elems *elems)
  {
@@@ -979,9 -811,23 +979,9 @@@ int ieee80211_build_preq_ies(struct iee
                offset = noffset;
        }
  
 -      if (sband->ht_cap.ht_supported) {
 -              u16 cap = sband->ht_cap.cap;
 -              __le16 tmp;
 -
 -              *pos++ = WLAN_EID_HT_CAPABILITY;
 -              *pos++ = sizeof(struct ieee80211_ht_cap);
 -              memset(pos, 0, sizeof(struct ieee80211_ht_cap));
 -              tmp = cpu_to_le16(cap);
 -              memcpy(pos, &tmp, sizeof(u16));
 -              pos += sizeof(u16);
 -              *pos++ = sband->ht_cap.ampdu_factor |
 -                       (sband->ht_cap.ampdu_density <<
 -                              IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
 -              memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
 -              pos += sizeof(sband->ht_cap.mcs);
 -              pos += 2 + 4 + 1; /* ext info, BF cap, antsel */
 -      }
 +      if (sband->ht_cap.ht_supported)
 +              pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap,
 +                                              sband->ht_cap.cap);
  
        /*
         * If adding more here, adjust code in main.c
@@@ -1034,6 -880,8 +1034,8 @@@ struct sk_buff *ieee80211_build_probe_r
        skb = ieee80211_probereq_get(&local->hw, &sdata->vif,
                                     ssid, ssid_len,
                                     buf, buf_len);
+       if (!skb)
+               goto out;
  
        if (dst) {
                mgmt = (struct ieee80211_mgmt *) skb->data;
        }
  
        IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+  out:
        kfree(buf);
  
        return skb;
@@@ -1175,7 -1025,7 +1179,7 @@@ int ieee80211_reconfig(struct ieee80211
                if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
                    sdata->vif.type != NL80211_IFTYPE_MONITOR &&
                    ieee80211_sdata_running(sdata))
 -                      res = drv_add_interface(local, &sdata->vif);
 +                      res = drv_add_interface(local, sdata);
        }
  
        /* add STAs back */
                                             struct ieee80211_sub_if_data,
                                             u.ap);
  
-                       memset(&sta->sta.drv_priv, 0, hw->sta_data_size);
                        WARN_ON(drv_sta_add(local, sdata, &sta->sta));
                }
        }
                          BSS_CHANGED_BEACON_INT |
                          BSS_CHANGED_BSSID |
                          BSS_CHANGED_CQM |
 -                        BSS_CHANGED_QOS;
 +                        BSS_CHANGED_QOS |
 +                        BSS_CHANGED_IDLE;
  
                switch (sdata->vif.type) {
                case NL80211_IFTYPE_STATION:
                        /* fall through */
                case NL80211_IFTYPE_AP:
                        changed |= BSS_CHANGED_SSID;
 +
 +                      if (sdata->vif.type == NL80211_IFTYPE_AP)
 +                              changed |= BSS_CHANGED_AP_PROBE_RESP;
 +
                        /* fall through */
                case NL80211_IFTYPE_MESH_POINT:
                        changed |= BSS_CHANGED_BEACON |
                }
        }
  
 +      ieee80211_recalc_ps(local, -1);
 +
        /*
         * Clear the WLAN_STA_BLOCK_BA flag so new aggregation
         * sessions can be established after a resume.
@@@ -1523,103 -1365,6 +1526,103 @@@ void ieee80211_disable_rssi_reports(str
  }
  EXPORT_SYMBOL(ieee80211_disable_rssi_reports);
  
 +u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
 +                            u16 cap)
 +{
 +      __le16 tmp;
 +
 +      *pos++ = WLAN_EID_HT_CAPABILITY;
 +      *pos++ = sizeof(struct ieee80211_ht_cap);
 +      memset(pos, 0, sizeof(struct ieee80211_ht_cap));
 +
 +      /* capability flags */
 +      tmp = cpu_to_le16(cap);
 +      memcpy(pos, &tmp, sizeof(u16));
 +      pos += sizeof(u16);
 +
 +      /* AMPDU parameters */
 +      *pos++ = ht_cap->ampdu_factor |
 +               (ht_cap->ampdu_density <<
 +                      IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
 +
 +      /* MCS set */
 +      memcpy(pos, &ht_cap->mcs, sizeof(ht_cap->mcs));
 +      pos += sizeof(ht_cap->mcs);
 +
 +      /* extended capabilities */
 +      pos += sizeof(__le16);
 +
 +      /* BF capabilities */
 +      pos += sizeof(__le32);
 +
 +      /* antenna selection */
 +      pos += sizeof(u8);
 +
 +      return pos;
 +}
 +
 +u8 *ieee80211_ie_build_ht_info(u8 *pos,
 +                             struct ieee80211_sta_ht_cap *ht_cap,
 +                             struct ieee80211_channel *channel,
 +                             enum nl80211_channel_type channel_type)
 +{
 +      struct ieee80211_ht_info *ht_info;
 +      /* Build HT Information */
 +      *pos++ = WLAN_EID_HT_INFORMATION;
 +      *pos++ = sizeof(struct ieee80211_ht_info);
 +      ht_info = (struct ieee80211_ht_info *)pos;
 +      ht_info->control_chan =
 +                      ieee80211_frequency_to_channel(channel->center_freq);
 +      switch (channel_type) {
 +      case NL80211_CHAN_HT40MINUS:
 +              ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
 +              break;
 +      case NL80211_CHAN_HT40PLUS:
 +              ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
 +              break;
 +      case NL80211_CHAN_HT20:
 +      default:
 +              ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_NONE;
 +              break;
 +      }
 +      if (ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
 +              ht_info->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY;
 +      ht_info->operation_mode = 0x0000;
 +      ht_info->stbc_param = 0x0000;
 +
 +      /* It seems that Basic MCS set and Supported MCS set
 +         are identical for the first 10 bytes */
 +      memset(&ht_info->basic_set, 0, 16);
 +      memcpy(&ht_info->basic_set, &ht_cap->mcs, 10);
 +
 +      return pos + sizeof(struct ieee80211_ht_info);
 +}
 +
 +enum nl80211_channel_type
 +ieee80211_ht_info_to_channel_type(struct ieee80211_ht_info *ht_info)
 +{
 +      enum nl80211_channel_type channel_type;
 +
 +      if (!ht_info)
 +              return NL80211_CHAN_NO_HT;
 +
 +      switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
 +      case IEEE80211_HT_PARAM_CHA_SEC_NONE:
 +              channel_type = NL80211_CHAN_HT20;
 +              break;
 +      case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
 +              channel_type = NL80211_CHAN_HT40PLUS;
 +              break;
 +      case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
 +              channel_type = NL80211_CHAN_HT40MINUS;
 +              break;
 +      default:
 +              channel_type = NL80211_CHAN_NO_HT;
 +      }
 +
 +      return channel_type;
 +}
 +
  int ieee80211_add_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb)
  {
        struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
diff --combined net/wireless/nl80211.c
@@@ -89,8 -89,8 +89,8 @@@ static const struct nla_policy nl80211_
        [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
        [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
  
-       [NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN },
-       [NL80211_ATTR_PREV_BSSID] = { .type = NLA_BINARY, .len = ETH_ALEN },
+       [NL80211_ATTR_MAC] = { .len = ETH_ALEN },
+       [NL80211_ATTR_PREV_BSSID] = { .len = ETH_ALEN },
  
        [NL80211_ATTR_KEY] = { .type = NLA_NESTED, },
        [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY,
@@@ -98,7 -98,7 +98,7 @@@
        [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 },
        [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
        [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
 -      [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 },
 +      [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 },
        [NL80211_ATTR_KEY_TYPE] = { .type = NLA_U32 },
  
        [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 },
        [NL80211_ATTR_TDLS_OPERATION] = { .type = NLA_U8 },
        [NL80211_ATTR_TDLS_SUPPORT] = { .type = NLA_FLAG },
        [NL80211_ATTR_TDLS_EXTERNAL_SETUP] = { .type = NLA_FLAG },
 +      [NL80211_ATTR_DONT_WAIT_FOR_ACK] = { .type = NLA_FLAG },
 +      [NL80211_ATTR_PROBE_RESP] = { .type = NLA_BINARY,
 +                                    .len = IEEE80211_MAX_DATA_LEN },
 +      [NL80211_ATTR_DFS_REGION] = { .type = NLA_U8 },
 +      [NL80211_ATTR_DISABLE_HT] = { .type = NLA_FLAG },
 +      [NL80211_ATTR_HT_CAPABILITY_MASK] = {
 +              .len = NL80211_HT_CAPABILITY_LEN
 +      },
 +      [NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 },
  };
  
  /* policy for the key attributes */
@@@ -212,7 -203,7 +212,7 @@@ static const struct nla_policy nl80211_
        [NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN },
        [NL80211_KEY_IDX] = { .type = NLA_U8 },
        [NL80211_KEY_CIPHER] = { .type = NLA_U32 },
 -      [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 },
 +      [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 },
        [NL80211_KEY_DEFAULT] = { .type = NLA_FLAG },
        [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG },
        [NL80211_KEY_TYPE] = { .type = NLA_U32 },
@@@ -767,10 -758,6 +767,10 @@@ static int nl80211_send_wiphy(struct sk
        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX,
                    dev->wiphy.available_antennas_rx);
  
 +      if (dev->wiphy.flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD)
 +              NLA_PUT_U32(msg, NL80211_ATTR_PROBE_RESP_OFFLOAD,
 +                          dev->wiphy.probe_resp_offload);
 +
        if ((dev->wiphy.available_antennas_tx ||
             dev->wiphy.available_antennas_rx) && dev->ops->get_antenna) {
                u32 tx_ant = 0, rx_ant = 0;
        CMD(set_pmksa, SET_PMKSA);
        CMD(del_pmksa, DEL_PMKSA);
        CMD(flush_pmksa, FLUSH_PMKSA);
 -      CMD(remain_on_channel, REMAIN_ON_CHANNEL);
 +      if (dev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL)
 +              CMD(remain_on_channel, REMAIN_ON_CHANNEL);
        CMD(set_bitrate_mask, SET_TX_BITRATE_MASK);
        CMD(mgmt_tx, FRAME);
        CMD(mgmt_tx_cancel_wait, FRAME_WAIT_CANCEL);
        }
        if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
                CMD(sched_scan_start, START_SCHED_SCAN);
 +      CMD(probe_client, PROBE_CLIENT);
 +      CMD(set_noack_map, SET_NOACK_MAP);
 +      if (dev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS) {
 +              i++;
 +              NLA_PUT_U32(msg, i, NL80211_CMD_REGISTER_BEACONS);
 +      }
 +
 +#ifdef CONFIG_NL80211_TESTMODE
 +      CMD(testmode_cmd, TESTMODE);
 +#endif
  
  #undef CMD
  
  
        nla_nest_end(msg, nl_cmds);
  
 -      if (dev->ops->remain_on_channel)
 +      if (dev->ops->remain_on_channel &&
 +          dev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL)
                NLA_PUT_U32(msg, NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION,
                            dev->wiphy.max_remain_on_channel_duration);
  
 -      if (dev->ops->mgmt_tx_cancel_wait)
 +      if (dev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX)
                NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK);
  
        if (mgmt_stypes) {
        if (nl80211_put_iface_combinations(&dev->wiphy, msg))
                goto nla_put_failure;
  
 +      if (dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME)
 +              NLA_PUT_U32(msg, NL80211_ATTR_DEVICE_AP_SME,
 +                          dev->wiphy.ap_sme_capa);
 +
 +      NLA_PUT_U32(msg, NL80211_ATTR_FEATURE_FLAGS, dev->wiphy.features);
 +
 +      if (dev->wiphy.ht_capa_mod_mask)
 +              NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY_MASK,
 +                      sizeof(*dev->wiphy.ht_capa_mod_mask),
 +                      dev->wiphy.ht_capa_mod_mask);
 +
        return genlmsg_end(msg, hdr);
  
   nla_put_failure:
@@@ -1761,23 -1725,6 +1761,23 @@@ static int nl80211_del_interface(struc
        return rdev->ops->del_virtual_intf(&rdev->wiphy, dev);
  }
  
 +static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info)
 +{
 +      struct cfg80211_registered_device *rdev = info->user_ptr[0];
 +      struct net_device *dev = info->user_ptr[1];
 +      u16 noack_map;
 +
 +      if (!info->attrs[NL80211_ATTR_NOACK_MAP])
 +              return -EINVAL;
 +
 +      if (!rdev->ops->set_noack_map)
 +              return -EOPNOTSUPP;
 +
 +      noack_map = nla_get_u16(info->attrs[NL80211_ATTR_NOACK_MAP]);
 +
 +      return rdev->ops->set_noack_map(&rdev->wiphy, dev, noack_map);
 +}
 +
  struct get_key_cookie {
        struct sk_buff *msg;
        int error;
@@@ -2208,13 -2155,6 +2208,13 @@@ static int nl80211_addset_beacon(struc
                        nla_len(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]);
        }
  
 +      if (info->attrs[NL80211_ATTR_PROBE_RESP]) {
 +              params.probe_resp =
 +                      nla_data(info->attrs[NL80211_ATTR_PROBE_RESP]);
 +              params.probe_resp_len =
 +                      nla_len(info->attrs[NL80211_ATTR_PROBE_RESP]);
 +      }
 +
        err = call(&rdev->wiphy, dev, &params);
        if (!err && params.interval)
                wdev->beacon_interval = params.interval;
@@@ -2513,34 -2453,26 +2513,34 @@@ static int nl80211_get_station(struct s
  /*
   * Get vlan interface making sure it is running and on the right wiphy.
   */
 -static int get_vlan(struct genl_info *info,
 -                  struct cfg80211_registered_device *rdev,
 -                  struct net_device **vlan)
 +static struct net_device *get_vlan(struct genl_info *info,
 +                                 struct cfg80211_registered_device *rdev)
  {
        struct nlattr *vlanattr = info->attrs[NL80211_ATTR_STA_VLAN];
 -      *vlan = NULL;
 -
 -      if (vlanattr) {
 -              *vlan = dev_get_by_index(genl_info_net(info),
 -                                       nla_get_u32(vlanattr));
 -              if (!*vlan)
 -                      return -ENODEV;
 -              if (!(*vlan)->ieee80211_ptr)
 -                      return -EINVAL;
 -              if ((*vlan)->ieee80211_ptr->wiphy != &rdev->wiphy)
 -                      return -EINVAL;
 -              if (!netif_running(*vlan))
 -                      return -ENETDOWN;
 +      struct net_device *v;
 +      int ret;
 +
 +      if (!vlanattr)
 +              return NULL;
 +
 +      v = dev_get_by_index(genl_info_net(info), nla_get_u32(vlanattr));
 +      if (!v)
 +              return ERR_PTR(-ENODEV);
 +
 +      if (!v->ieee80211_ptr || v->ieee80211_ptr->wiphy != &rdev->wiphy) {
 +              ret = -EINVAL;
 +              goto error;
        }
 -      return 0;
 +
 +      if (!netif_running(v)) {
 +              ret = -ENETDOWN;
 +              goto error;
 +      }
 +
 +      return v;
 + error:
 +      dev_put(v);
 +      return ERR_PTR(ret);
  }
  
  static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
                params.plink_state =
                    nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_STATE]);
  
 -      err = get_vlan(info, rdev, &params.vlan);
 -      if (err)
 -              goto out;
 +      params.vlan = get_vlan(info, rdev);
 +      if (IS_ERR(params.vlan))
 +              return PTR_ERR(params.vlan);
  
        /* validate settings */
        err = 0;
@@@ -2760,9 -2692,9 +2760,9 @@@ static int nl80211_new_station(struct s
              (rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP)))
                return -EINVAL;
  
 -      err = get_vlan(info, rdev, &params.vlan);
 -      if (err)
 -              goto out;
 +      params.vlan = get_vlan(info, rdev);
 +      if (IS_ERR(params.vlan))
 +              return PTR_ERR(params.vlan);
  
        /* validate settings */
        err = 0;
@@@ -3195,8 -3127,6 +3195,8 @@@ static int nl80211_get_mesh_config(stru
                        cur_params.dot11MeshHWMPactivePathTimeout);
        NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
                        cur_params.dot11MeshHWMPpreqMinInterval);
 +      NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
 +                      cur_params.dot11MeshHWMPperrMinInterval);
        NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
                        cur_params.dot11MeshHWMPnetDiameterTraversalTime);
        NLA_PUT_U8(msg, NL80211_MESHCONF_HWMP_ROOTMODE,
@@@ -3231,7 -3161,6 +3231,7 @@@ static const struct nla_policy nl80211_
        [NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT] = { .type = NLA_U16 },
        [NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT] = { .type = NLA_U32 },
        [NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL] = { .type = NLA_U16 },
 +      [NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL] = { .type = NLA_U16 },
        [NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 },
        [NL80211_MESHCONF_HWMP_ROOTMODE] = { .type = NLA_U8 },
        [NL80211_MESHCONF_HWMP_RANN_INTERVAL] = { .type = NLA_U16 },
@@@ -3306,9 -3235,6 +3306,9 @@@ do {
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPpreqMinInterval,
                        mask, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
                        nla_get_u16);
 +      FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPperrMinInterval,
 +                      mask, NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
 +                      nla_get_u16);
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
                        dot11MeshHWMPnetDiameterTraversalTime,
                        mask, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
@@@ -3431,9 -3357,6 +3431,9 @@@ static int nl80211_get_reg(struct sk_bu
  
        NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2,
                cfg80211_regdomain->alpha2);
 +      if (cfg80211_regdomain->dfs_region)
 +              NLA_PUT_U8(msg, NL80211_ATTR_DFS_REGION,
 +                         cfg80211_regdomain->dfs_region);
  
        nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES);
        if (!nl_reg_rules)
@@@ -3492,7 -3415,6 +3492,7 @@@ static int nl80211_set_reg(struct sk_bu
        char *alpha2 = NULL;
        int rem_reg_rules = 0, r = 0;
        u32 num_rules = 0, rule_idx = 0, size_of_regd;
 +      u8 dfs_region = 0;
        struct ieee80211_regdomain *rd = NULL;
  
        if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
  
        alpha2 = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
  
 +      if (info->attrs[NL80211_ATTR_DFS_REGION])
 +              dfs_region = nla_get_u8(info->attrs[NL80211_ATTR_DFS_REGION]);
 +
        nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],
                        rem_reg_rules) {
                num_rules++;
        rd->alpha2[0] = alpha2[0];
        rd->alpha2[1] = alpha2[1];
  
 +      /*
 +       * Disable DFS master mode if the DFS region was
 +       * not supported or known on this kernel.
 +       */
 +      if (reg_supported_dfs_region(dfs_region))
 +              rd->dfs_region = dfs_region;
 +
        nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],
                        rem_reg_rules) {
                nla_parse(tb, NL80211_REG_RULE_ATTR_MAX,
@@@ -4447,9 -4359,6 +4447,9 @@@ static int nl80211_associate(struct sk_
        const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL;
        int err, ssid_len, ie_len = 0;
        bool use_mfp = false;
 +      u32 flags = 0;
 +      struct ieee80211_ht_cap *ht_capa = NULL;
 +      struct ieee80211_ht_cap *ht_capa_mask = NULL;
  
        if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
                return -EINVAL;
        if (info->attrs[NL80211_ATTR_PREV_BSSID])
                prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]);
  
 +      if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT]))
 +              flags |= ASSOC_REQ_DISABLE_HT;
 +
 +      if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
 +              ht_capa_mask =
 +                      nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]);
 +
 +      if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
 +              if (!ht_capa_mask)
 +                      return -EINVAL;
 +              ht_capa = nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
 +      }
 +
        err = nl80211_crypto_settings(rdev, info, &crypto, 1);
        if (!err)
                err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid,
                                          ssid, ssid_len, ie, ie_len, use_mfp,
 -                                        &crypto);
 +                                        &crypto, flags, ht_capa,
 +                                        ht_capa_mask);
  
        return err;
  }
@@@ -5001,22 -4896,6 +5001,22 @@@ static int nl80211_connect(struct sk_bu
                        return PTR_ERR(connkeys);
        }
  
 +      if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT]))
 +              connect.flags |= ASSOC_REQ_DISABLE_HT;
 +
 +      if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
 +              memcpy(&connect.ht_capa_mask,
 +                     nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]),
 +                     sizeof(connect.ht_capa_mask));
 +
 +      if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
 +              if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
 +                      return -EINVAL;
 +              memcpy(&connect.ht_capa,
 +                     nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]),
 +                     sizeof(connect.ht_capa));
 +      }
 +
        err = cfg80211_connect(rdev, dev, &connect, connkeys);
        if (err)
                kfree(connkeys);
@@@ -5204,8 -5083,7 +5204,8 @@@ static int nl80211_remain_on_channel(st
            duration > rdev->wiphy.max_remain_on_channel_duration)
                return -EINVAL;
  
 -      if (!rdev->ops->remain_on_channel)
 +      if (!rdev->ops->remain_on_channel ||
 +          !(rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL))
                return -EOPNOTSUPP;
  
        if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
@@@ -5393,13 -5271,12 +5393,13 @@@ static int nl80211_tx_mgmt(struct sk_bu
        bool channel_type_valid = false;
        u32 freq;
        int err;
 -      void *hdr;
 +      void *hdr = NULL;
        u64 cookie;
 -      struct sk_buff *msg;
 +      struct sk_buff *msg = NULL;
        unsigned int wait = 0;
 -      bool offchan;
 -      bool no_cck;
 +      bool offchan, no_cck, dont_wait_for_ack;
 +
 +      dont_wait_for_ack = info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK];
  
        if (!info->attrs[NL80211_ATTR_FRAME] ||
            !info->attrs[NL80211_ATTR_WIPHY_FREQ])
                return -EOPNOTSUPP;
  
        if (info->attrs[NL80211_ATTR_DURATION]) {
 -              if (!rdev->ops->mgmt_tx_cancel_wait)
 +              if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
                        return -EINVAL;
                wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
        }
  
        offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK];
  
 +      if (offchan && !(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
 +              return -EINVAL;
 +
        no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
  
        freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
        if (chan == NULL)
                return -EINVAL;
  
 -      msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 -      if (!msg)
 -              return -ENOMEM;
 +      if (!dont_wait_for_ack) {
 +              msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 +              if (!msg)
 +                      return -ENOMEM;
  
 -      hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
 -                           NL80211_CMD_FRAME);
 +              hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
 +                                   NL80211_CMD_FRAME);
  
 -      if (IS_ERR(hdr)) {
 -              err = PTR_ERR(hdr);
 -              goto free_msg;
 +              if (IS_ERR(hdr)) {
 +                      err = PTR_ERR(hdr);
 +                      goto free_msg;
 +              }
        }
 +
        err = cfg80211_mlme_mgmt_tx(rdev, dev, chan, offchan, channel_type,
                                    channel_type_valid, wait,
                                    nla_data(info->attrs[NL80211_ATTR_FRAME]),
                                    nla_len(info->attrs[NL80211_ATTR_FRAME]),
 -                                  no_cck, &cookie);
 +                                  no_cck, dont_wait_for_ack, &cookie);
        if (err)
                goto free_msg;
  
 -      NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
 +      if (msg) {
 +              NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
  
 -      genlmsg_end(msg, hdr);
 -      return genlmsg_reply(msg, info);
 +              genlmsg_end(msg, hdr);
 +              return genlmsg_reply(msg, info);
 +      }
 +
 +      return 0;
  
   nla_put_failure:
        err = -ENOBUFS;
@@@ -5673,11 -5540,6 +5673,11 @@@ static int nl80211_join_mesh(struct sk_
        setup.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]);
        setup.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
  
 +      if (info->attrs[NL80211_ATTR_MCAST_RATE] &&
 +          !nl80211_parse_mcast_rate(rdev, setup.mcast_rate,
 +                          nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE])))
 +                      return -EINVAL;
 +
        if (info->attrs[NL80211_ATTR_MESH_SETUP]) {
                /* parse additional setup parameters if given */
                err = nl80211_parse_mesh_setup(info, &setup);
@@@ -5970,91 -5832,6 +5970,91 @@@ static int nl80211_set_rekey_data(struc
        return err;
  }
  
 +static int nl80211_register_unexpected_frame(struct sk_buff *skb,
 +                                           struct genl_info *info)
 +{
 +      struct net_device *dev = info->user_ptr[1];
 +      struct wireless_dev *wdev = dev->ieee80211_ptr;
 +
 +      if (wdev->iftype != NL80211_IFTYPE_AP &&
 +          wdev->iftype != NL80211_IFTYPE_P2P_GO)
 +              return -EINVAL;
 +
 +      if (wdev->ap_unexpected_nlpid)
 +              return -EBUSY;
 +
 +      wdev->ap_unexpected_nlpid = info->snd_pid;
 +      return 0;
 +}
 +
 +static int nl80211_probe_client(struct sk_buff *skb,
 +                              struct genl_info *info)
 +{
 +      struct cfg80211_registered_device *rdev = info->user_ptr[0];
 +      struct net_device *dev = info->user_ptr[1];
 +      struct wireless_dev *wdev = dev->ieee80211_ptr;
 +      struct sk_buff *msg;
 +      void *hdr;
 +      const u8 *addr;
 +      u64 cookie;
 +      int err;
 +
 +      if (wdev->iftype != NL80211_IFTYPE_AP &&
 +          wdev->iftype != NL80211_IFTYPE_P2P_GO)
 +              return -EOPNOTSUPP;
 +
 +      if (!info->attrs[NL80211_ATTR_MAC])
 +              return -EINVAL;
 +
 +      if (!rdev->ops->probe_client)
 +              return -EOPNOTSUPP;
 +
 +      msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 +      if (!msg)
 +              return -ENOMEM;
 +
 +      hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
 +                           NL80211_CMD_PROBE_CLIENT);
 +
 +      if (IS_ERR(hdr)) {
 +              err = PTR_ERR(hdr);
 +              goto free_msg;
 +      }
 +
 +      addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
 +
 +      err = rdev->ops->probe_client(&rdev->wiphy, dev, addr, &cookie);
 +      if (err)
 +              goto free_msg;
 +
 +      NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
 +
 +      genlmsg_end(msg, hdr);
 +
 +      return genlmsg_reply(msg, info);
 +
 + nla_put_failure:
 +      err = -ENOBUFS;
 + free_msg:
 +      nlmsg_free(msg);
 +      return err;
 +}
 +
 +static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info)
 +{
 +      struct cfg80211_registered_device *rdev = info->user_ptr[0];
 +
 +      if (!(rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS))
 +              return -EOPNOTSUPP;
 +
 +      if (rdev->ap_beacons_nlpid)
 +              return -EBUSY;
 +
 +      rdev->ap_beacons_nlpid = info->snd_pid;
 +
 +      return 0;
 +}
 +
  #define NL80211_FLAG_NEED_WIPHY               0x01
  #define NL80211_FLAG_NEED_NETDEV      0x02
  #define NL80211_FLAG_NEED_RTNL                0x04
@@@ -6610,39 -6387,6 +6610,39 @@@ static struct genl_ops nl80211_ops[] = 
                .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
                                  NL80211_FLAG_NEED_RTNL,
        },
 +      {
 +              .cmd = NL80211_CMD_UNEXPECTED_FRAME,
 +              .doit = nl80211_register_unexpected_frame,
 +              .policy = nl80211_policy,
 +              .flags = GENL_ADMIN_PERM,
 +              .internal_flags = NL80211_FLAG_NEED_NETDEV |
 +                                NL80211_FLAG_NEED_RTNL,
 +      },
 +      {
 +              .cmd = NL80211_CMD_PROBE_CLIENT,
 +              .doit = nl80211_probe_client,
 +              .policy = nl80211_policy,
 +              .flags = GENL_ADMIN_PERM,
 +              .internal_flags = NL80211_FLAG_NEED_NETDEV |
 +                                NL80211_FLAG_NEED_RTNL,
 +      },
 +      {
 +              .cmd = NL80211_CMD_REGISTER_BEACONS,
 +              .doit = nl80211_register_beacons,
 +              .policy = nl80211_policy,
 +              .flags = GENL_ADMIN_PERM,
 +              .internal_flags = NL80211_FLAG_NEED_WIPHY |
 +                                NL80211_FLAG_NEED_RTNL,
 +      },
 +      {
 +              .cmd = NL80211_CMD_SET_NOACK_MAP,
 +              .doit = nl80211_set_noack_map,
 +              .policy = nl80211_policy,
 +              .flags = GENL_ADMIN_PERM,
 +              .internal_flags = NL80211_FLAG_NEED_NETDEV |
 +                                NL80211_FLAG_NEED_RTNL,
 +      },
 +
  };
  
  static struct genl_multicast_group nl80211_mlme_mcgrp = {
@@@ -6895,7 -6639,10 +6895,7 @@@ void nl80211_send_reg_change_event(stru
        if (wiphy_idx_valid(request->wiphy_idx))
                NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, request->wiphy_idx);
  
 -      if (genlmsg_end(msg, hdr) < 0) {
 -              nlmsg_free(msg);
 -              return;
 -      }
 +      genlmsg_end(msg, hdr);
  
        rcu_read_lock();
        genlmsg_multicast_allns(msg, 0, nl80211_regulatory_mcgrp.id,
@@@ -6931,7 -6678,10 +6931,7 @@@ static void nl80211_send_mlme_event(str
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
        NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf);
  
 -      if (genlmsg_end(msg, hdr) < 0) {
 -              nlmsg_free(msg);
 -              return;
 -      }
 +      genlmsg_end(msg, hdr);
  
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@@ -7012,7 -6762,10 +7012,7 @@@ static void nl80211_send_mlme_timeout(s
        NLA_PUT_FLAG(msg, NL80211_ATTR_TIMED_OUT);
        NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
  
 -      if (genlmsg_end(msg, hdr) < 0) {
 -              nlmsg_free(msg);
 -              return;
 -      }
 +      genlmsg_end(msg, hdr);
  
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@@ -7068,7 -6821,10 +7068,7 @@@ void nl80211_send_connect_result(struc
        if (resp_ie)
                NLA_PUT(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie);
  
 -      if (genlmsg_end(msg, hdr) < 0) {
 -              nlmsg_free(msg);
 -              return;
 -      }
 +      genlmsg_end(msg, hdr);
  
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@@ -7106,7 -6862,10 +7106,7 @@@ void nl80211_send_roamed(struct cfg8021
        if (resp_ie)
                NLA_PUT(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie);
  
 -      if (genlmsg_end(msg, hdr) < 0) {
 -              nlmsg_free(msg);
 -              return;
 -      }
 +      genlmsg_end(msg, hdr);
  
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@@ -7144,7 -6903,10 +7144,7 @@@ void nl80211_send_disconnected(struct c
        if (ie)
                NLA_PUT(msg, NL80211_ATTR_IE, ie_len, ie);
  
 -      if (genlmsg_end(msg, hdr) < 0) {
 -              nlmsg_free(msg);
 -              return;
 -      }
 +      genlmsg_end(msg, hdr);
  
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, GFP_KERNEL);
@@@ -7177,7 -6939,10 +7177,7 @@@ void nl80211_send_ibss_bssid(struct cfg
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
        NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid);
  
 -      if (genlmsg_end(msg, hdr) < 0) {
 -              nlmsg_free(msg);
 -              return;
 -      }
 +      genlmsg_end(msg, hdr);
  
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@@ -7212,7 -6977,10 +7212,7 @@@ void nl80211_send_new_peer_candidate(st
        if (ie_len && ie)
                NLA_PUT(msg, NL80211_ATTR_IE, ie_len , ie);
  
 -      if (genlmsg_end(msg, hdr) < 0) {
 -              nlmsg_free(msg);
 -              return;
 -      }
 +      genlmsg_end(msg, hdr);
  
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@@ -7251,7 -7019,10 +7251,7 @@@ void nl80211_michael_mic_failure(struc
        if (tsc)
                NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, 6, tsc);
  
 -      if (genlmsg_end(msg, hdr) < 0) {
 -              nlmsg_free(msg);
 -              return;
 -      }
 +      genlmsg_end(msg, hdr);
  
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@@ -7302,7 -7073,10 +7302,7 @@@ void nl80211_send_beacon_hint_event(str
                goto nla_put_failure;
        nla_nest_end(msg, nl_freq);
  
 -      if (genlmsg_end(msg, hdr) < 0) {
 -              nlmsg_free(msg);
 -              return;
 -      }
 +      genlmsg_end(msg, hdr);
  
        rcu_read_lock();
        genlmsg_multicast_allns(msg, 0, nl80211_regulatory_mcgrp.id,
@@@ -7345,7 -7119,10 +7345,7 @@@ static void nl80211_send_remain_on_chan
        if (cmd == NL80211_CMD_REMAIN_ON_CHANNEL)
                NLA_PUT_U32(msg, NL80211_ATTR_DURATION, duration);
  
 -      if (genlmsg_end(msg, hdr) < 0) {
 -              nlmsg_free(msg);
 -              return;
 -      }
 +      genlmsg_end(msg, hdr);
  
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@@ -7416,7 -7193,10 +7416,7 @@@ void nl80211_send_sta_del_event(struct 
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
        NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
  
 -      if (genlmsg_end(msg, hdr) < 0) {
 -              nlmsg_free(msg);
 -              return;
 -      }
 +      genlmsg_end(msg, hdr);
  
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
        nlmsg_free(msg);
  }
  
 +static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd,
 +                                     const u8 *addr, gfp_t gfp)
 +{
 +      struct wireless_dev *wdev = dev->ieee80211_ptr;
 +      struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
 +      struct sk_buff *msg;
 +      void *hdr;
 +      int err;
 +      u32 nlpid = ACCESS_ONCE(wdev->ap_unexpected_nlpid);
 +
 +      if (!nlpid)
 +              return false;
 +
 +      msg = nlmsg_new(100, gfp);
 +      if (!msg)
 +              return true;
 +
 +      hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
 +      if (!hdr) {
 +              nlmsg_free(msg);
 +              return true;
 +      }
 +
 +      NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
 +      NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
 +      NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
 +
 +      err = genlmsg_end(msg, hdr);
 +      if (err < 0) {
 +              nlmsg_free(msg);
 +              return true;
 +      }
 +
 +      genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlpid);
 +      return true;
 +
 + nla_put_failure:
 +      genlmsg_cancel(msg, hdr);
 +      nlmsg_free(msg);
 +      return true;
 +}
 +
 +bool nl80211_unexpected_frame(struct net_device *dev, const u8 *addr, gfp_t gfp)
 +{
 +      return __nl80211_unexpected_frame(dev, NL80211_CMD_UNEXPECTED_FRAME,
 +                                        addr, gfp);
 +}
 +
 +bool nl80211_unexpected_4addr_frame(struct net_device *dev,
 +                                  const u8 *addr, gfp_t gfp)
 +{
 +      return __nl80211_unexpected_frame(dev,
 +                                        NL80211_CMD_UNEXPECTED_4ADDR_FRAME,
 +                                        addr, gfp);
 +}
 +
  int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
                      struct net_device *netdev, u32 nlpid,
                      int freq, const u8 *buf, size_t len, gfp_t gfp)
  {
        struct sk_buff *msg;
        void *hdr;
 -      int err;
  
        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
        if (!msg)
        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
        NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf);
  
 -      err = genlmsg_end(msg, hdr);
 -      if (err < 0) {
 -              nlmsg_free(msg);
 -              return err;
 -      }
 +      genlmsg_end(msg, hdr);
  
 -      err = genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlpid);
 -      if (err < 0)
 -              return err;
 -      return 0;
 +      return genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlpid);
  
   nla_put_failure:
        genlmsg_cancel(msg, hdr);
@@@ -7540,7 -7272,10 +7540,7 @@@ void nl80211_send_mgmt_tx_status(struc
        if (ack)
                NLA_PUT_FLAG(msg, NL80211_ATTR_ACK);
  
 -      if (genlmsg_end(msg, hdr) < 0) {
 -              nlmsg_free(msg);
 -              return;
 -      }
 +      genlmsg_end(msg, hdr);
  
        genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp);
        return;
@@@ -7582,7 -7317,10 +7582,7 @@@ nl80211_send_cqm_rssi_notify(struct cfg
  
        nla_nest_end(msg, pinfoattr);
  
 -      if (genlmsg_end(msg, hdr) < 0) {
 -              nlmsg_free(msg);
 -              return;
 -      }
 +      genlmsg_end(msg, hdr);
  
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@@ -7624,7 -7362,10 +7624,7 @@@ void nl80211_gtk_rekey_notify(struct cf
  
        nla_nest_end(msg, rekey_attr);
  
 -      if (genlmsg_end(msg, hdr) < 0) {
 -              nlmsg_free(msg);
 -              return;
 -      }
 +      genlmsg_end(msg, hdr);
  
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@@ -7667,7 -7408,10 +7667,7 @@@ void nl80211_pmksa_candidate_notify(str
  
        nla_nest_end(msg, attr);
  
 -      if (genlmsg_end(msg, hdr) < 0) {
 -              nlmsg_free(msg);
 -              return;
 -      }
 +      genlmsg_end(msg, hdr);
  
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@@ -7709,45 -7453,7 +7709,45 @@@ nl80211_send_cqm_pktloss_notify(struct 
  
        nla_nest_end(msg, pinfoattr);
  
 -      if (genlmsg_end(msg, hdr) < 0) {
 +      genlmsg_end(msg, hdr);
 +
 +      genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
 +                              nl80211_mlme_mcgrp.id, gfp);
 +      return;
 +
 + nla_put_failure:
 +      genlmsg_cancel(msg, hdr);
 +      nlmsg_free(msg);
 +}
 +
 +void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
 +                         u64 cookie, bool acked, gfp_t gfp)
 +{
 +      struct wireless_dev *wdev = dev->ieee80211_ptr;
 +      struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
 +      struct sk_buff *msg;
 +      void *hdr;
 +      int err;
 +
 +      msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
 +      if (!msg)
 +              return;
 +
 +      hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PROBE_CLIENT);
 +      if (!hdr) {
 +              nlmsg_free(msg);
 +              return;
 +      }
 +
 +      NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
 +      NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
 +      NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
 +      NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
 +      if (acked)
 +              NLA_PUT_FLAG(msg, NL80211_ATTR_ACK);
 +
 +      err = genlmsg_end(msg, hdr);
 +      if (err < 0) {
                nlmsg_free(msg);
                return;
        }
        genlmsg_cancel(msg, hdr);
        nlmsg_free(msg);
  }
 +EXPORT_SYMBOL(cfg80211_probe_status);
 +
 +void cfg80211_report_obss_beacon(struct wiphy *wiphy,
 +                               const u8 *frame, size_t len,
 +                               int freq, gfp_t gfp)
 +{
 +      struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
 +      struct sk_buff *msg;
 +      void *hdr;
 +      u32 nlpid = ACCESS_ONCE(rdev->ap_beacons_nlpid);
 +
 +      if (!nlpid)
 +              return;
 +
 +      msg = nlmsg_new(len + 100, gfp);
 +      if (!msg)
 +              return;
 +
 +      hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
 +      if (!hdr) {
 +              nlmsg_free(msg);
 +              return;
 +      }
 +
 +      NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
 +      if (freq)
 +              NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
 +      NLA_PUT(msg, NL80211_ATTR_FRAME, len, frame);
 +
 +      genlmsg_end(msg, hdr);
 +
 +      genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlpid);
 +      return;
 +
 + nla_put_failure:
 +      genlmsg_cancel(msg, hdr);
 +      nlmsg_free(msg);
 +}
 +EXPORT_SYMBOL(cfg80211_report_obss_beacon);
  
  static int nl80211_netlink_notify(struct notifier_block * nb,
                                  unsigned long state,
  
        rcu_read_lock();
  
 -      list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list)
 +      list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) {
                list_for_each_entry_rcu(wdev, &rdev->netdev_list, list)
                        cfg80211_mlme_unregister_socket(wdev, notify->pid);
 +              if (rdev->ap_beacons_nlpid == notify->pid)
 +                      rdev->ap_beacons_nlpid = 0;
 +      }
  
        rcu_read_unlock();
  
diff --combined net/wireless/reg.c
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  
  #include <linux/kernel.h>
 +#include <linux/export.h>
  #include <linux/slab.h>
  #include <linux/list.h>
  #include <linux/random.h>
  #include <linux/ctype.h>
  #include <linux/nl80211.h>
  #include <linux/platform_device.h>
 +#include <linux/moduleparam.h>
  #include <net/cfg80211.h>
  #include "core.h"
  #include "reg.h"
  #define REG_DBG_PRINT(args...)
  #endif
  
+ static struct regulatory_request core_request_world = {
+       .initiator = NL80211_REGDOM_SET_BY_CORE,
+       .alpha2[0] = '0',
+       .alpha2[1] = '0',
+       .intersect = false,
+       .processed = true,
+       .country_ie_env = ENVIRON_ANY,
+ };
  /* Receipt of information from last regulatory request */
- static struct regulatory_request *last_request;
+ static struct regulatory_request *last_request = &core_request_world;
  
  /* To trigger userspace events */
  static struct platform_device *reg_pdev;
@@@ -150,7 -157,7 +159,7 @@@ static char user_alpha2[2]
  module_param(ieee80211_regdom, charp, 0444);
  MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
  
- static void reset_regdomains(void)
+ static void reset_regdomains(bool full_reset)
  {
        /* avoid freeing static information or freeing something twice */
        if (cfg80211_regdomain == cfg80211_world_regdom)
  
        cfg80211_world_regdom = &world_regdom;
        cfg80211_regdomain = NULL;
+       if (!full_reset)
+               return;
+       if (last_request != &core_request_world)
+               kfree(last_request);
+       last_request = &core_request_world;
  }
  
  /*
@@@ -175,7 -189,7 +191,7 @@@ static void update_world_regdomain(cons
  {
        BUG_ON(!last_request);
  
-       reset_regdomains();
+       reset_regdomains(false);
  
        cfg80211_world_regdom = rd;
        cfg80211_regdomain = rd;
@@@ -1123,8 -1137,6 +1139,8 @@@ static void wiphy_update_regulatory(str
        if (ignore_reg_update(wiphy, initiator))
                return;
  
 +      last_request->dfs_region = cfg80211_regdomain->dfs_region;
 +
        for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
                if (wiphy->bands[band])
                        handle_band(wiphy, band, initiator);
@@@ -1409,7 -1421,8 +1425,8 @@@ static int __regulatory_hint(struct wip
        }
  
  new_request:
-       kfree(last_request);
+       if (last_request != &core_request_world)
+               kfree(last_request);
  
        last_request = pending_request;
        last_request->intersect = intersect;
@@@ -1579,9 -1592,6 +1596,6 @@@ static int regulatory_hint_core(const c
  {
        struct regulatory_request *request;
  
-       kfree(last_request);
-       last_request = NULL;
        request = kzalloc(sizeof(struct regulatory_request),
                          GFP_KERNEL);
        if (!request)
@@@ -1779,7 -1789,7 +1793,7 @@@ static void restore_regulatory_settings
        mutex_lock(&cfg80211_mutex);
        mutex_lock(&reg_mutex);
  
-       reset_regdomains();
+       reset_regdomains(true);
        restore_alpha2(alpha2, reset_user);
  
        /*
@@@ -1950,42 -1960,6 +1964,42 @@@ static void print_rd_rules(const struc
        }
  }
  
 +bool reg_supported_dfs_region(u8 dfs_region)
 +{
 +      switch (dfs_region) {
 +      case NL80211_DFS_UNSET:
 +      case NL80211_DFS_FCC:
 +      case NL80211_DFS_ETSI:
 +      case NL80211_DFS_JP:
 +              return true;
 +      default:
 +              REG_DBG_PRINT("Ignoring uknown DFS master region: %d\n",
 +                            dfs_region);
 +              return false;
 +      }
 +}
 +
 +static void print_dfs_region(u8 dfs_region)
 +{
 +      if (!dfs_region)
 +              return;
 +
 +      switch (dfs_region) {
 +      case NL80211_DFS_FCC:
 +              pr_info(" DFS Master region FCC");
 +              break;
 +      case NL80211_DFS_ETSI:
 +              pr_info(" DFS Master region ETSI");
 +              break;
 +      case NL80211_DFS_JP:
 +              pr_info(" DFS Master region JP");
 +              break;
 +      default:
 +              pr_info(" DFS Master region Uknown");
 +              break;
 +      }
 +}
 +
  static void print_regdomain(const struct ieee80211_regdomain *rd)
  {
  
                        pr_info("Regulatory domain changed to country: %c%c\n",
                                rd->alpha2[0], rd->alpha2[1]);
        }
 +      print_dfs_region(rd->dfs_region);
        print_rd_rules(rd);
  }
  
@@@ -2076,12 -2049,18 +2090,18 @@@ static int __set_regdom(const struct ie
        }
  
        request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);
+       if (!request_wiphy &&
+           (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER ||
+            last_request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)) {
+               schedule_delayed_work(&reg_timeout, 0);
+               return -ENODEV;
+       }
  
        if (!last_request->intersect) {
                int r;
  
                if (last_request->initiator != NL80211_REGDOM_SET_BY_DRIVER) {
-                       reset_regdomains();
+                       reset_regdomains(false);
                        cfg80211_regdomain = rd;
                        return 0;
                }
                if (r)
                        return r;
  
-               reset_regdomains();
+               reset_regdomains(false);
                cfg80211_regdomain = rd;
                return 0;
        }
  
                rd = NULL;
  
-               reset_regdomains();
+               reset_regdomains(false);
                cfg80211_regdomain = intersected_rd;
  
                return 0;
        kfree(rd);
        rd = NULL;
  
-       reset_regdomains();
+       reset_regdomains(false);
        cfg80211_regdomain = intersected_rd;
  
        return 0;
@@@ -2300,9 -2279,9 +2320,9 @@@ void /* __init_or_exit */ regulatory_ex
        mutex_lock(&cfg80211_mutex);
        mutex_lock(&reg_mutex);
  
-       reset_regdomains();
+       reset_regdomains(true);
  
-       kfree(last_request);
+       dev_set_uevent_suppress(&reg_pdev->dev, true);
  
        platform_device_unregister(reg_pdev);