Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless
authorJohn W. Linville <linville@tuxdriver.com>
Fri, 6 Dec 2013 14:50:45 +0000 (09:50 -0500)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 6 Dec 2013 14:50:45 +0000 (09:50 -0500)
Conflicts:
drivers/net/wireless/brcm80211/Kconfig
net/mac80211/util.c

19 files changed:
1  2 
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/wcn36xx/smd.c
drivers/net/wireless/brcm80211/Kconfig
drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
drivers/net/wireless/mac80211_hwsim.c
net/mac80211/cfg.c
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/main.c
net/mac80211/mesh.c
net/mac80211/mlme.c
net/mac80211/rc80211_minstrel_ht.c
net/mac80211/rx.c
net/mac80211/scan.c
net/mac80211/util.c
net/wireless/core.c
net/wireless/ibss.c
net/wireless/nl80211.c

index fe3537f6ec5838aead7c6489fa06afa35d80e64f,8918035da3a3510c04ad45e106cebd3d267ad6e8..779d38a98a0e82c4a2e64cf676afef01fcbd1d59
@@@ -17,7 -17,6 +17,7 @@@
  #include <linux/io.h>
  #include <linux/slab.h>
  #include <linux/module.h>
 +#include <linux/time.h>
  #include <asm/unaligned.h>
  
  #include "hw.h"
@@@ -147,10 -146,9 +147,9 @@@ static void ath9k_hw_set_clockrate(stru
        else
                clockrate = ATH9K_CLOCK_RATE_5GHZ_OFDM;
  
-       if (IS_CHAN_HT40(chan))
-               clockrate *= 2;
-       if (ah->curchan) {
+       if (chan) {
+               if (IS_CHAN_HT40(chan))
+                       clockrate *= 2;
                if (IS_CHAN_HALF_RATE(chan))
                        clockrate /= 2;
                if (IS_CHAN_QUARTER_RATE(chan))
@@@ -455,6 -453,7 +454,6 @@@ static void ath9k_hw_init_config(struc
        }
  
        ah->config.rx_intr_mitigation = true;
 -      ah->config.pcieSerDesWrite = true;
  
        /*
         * We need this for PCI devices only (Cardbus, PCI, miniPCI)
@@@ -1502,9 -1501,8 +1501,9 @@@ static bool ath9k_hw_channel_change(str
        int r;
  
        if (pCap->hw_caps & ATH9K_HW_CAP_FCC_BAND_SWITCH) {
 -              band_switch = IS_CHAN_5GHZ(ah->curchan) != IS_CHAN_5GHZ(chan);
 -              mode_diff = (chan->channelFlags != ah->curchan->channelFlags);
 +              u32 flags_diff = chan->channelFlags ^ ah->curchan->channelFlags;
 +              band_switch = !!(flags_diff & CHANNEL_5GHZ);
 +              mode_diff = !!(flags_diff & ~CHANNEL_HT);
        }
  
        for (qnum = 0; qnum < AR_NUM_QCU; qnum++) {
@@@ -1816,7 -1814,7 +1815,7 @@@ static int ath9k_hw_do_fastcc(struct at
         * If cross-band fcc is not supoprted, bail out if channelFlags differ.
         */
        if (!(pCap->hw_caps & ATH9K_HW_CAP_FCC_BAND_SWITCH) &&
 -          chan->channelFlags != ah->curchan->channelFlags)
 +          ((chan->channelFlags ^ ah->curchan->channelFlags) & ~CHANNEL_HT))
                goto fail;
  
        if (!ath9k_hw_check_alive(ah))
@@@ -1857,12 -1855,10 +1856,12 @@@ int ath9k_hw_reset(struct ath_hw *ah, s
                   struct ath9k_hw_cal_data *caldata, bool fastcc)
  {
        struct ath_common *common = ath9k_hw_common(ah);
 +      struct timespec ts;
        u32 saveLedState;
        u32 saveDefAntenna;
        u32 macStaId1;
        u64 tsf = 0;
 +      s64 usec = 0;
        int r;
        bool start_mci_reset = false;
        bool save_fullsleep = ah->chip_fullsleep;
  
        macStaId1 = REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_BASE_RATE_11B;
  
 -      /* For chips on which RTC reset is done, save TSF before it gets cleared */
 -      if (AR_SREV_9100(ah) ||
 -          (AR_SREV_9280(ah) && ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL)))
 -              tsf = ath9k_hw_gettsf64(ah);
 +      /* Save TSF before chip reset, a cold reset clears it */
 +      tsf = ath9k_hw_gettsf64(ah);
 +      getrawmonotonic(&ts);
 +      usec = ts.tv_sec * 1000 + ts.tv_nsec / 1000;
  
        saveLedState = REG_READ(ah, AR_CFG_LED) &
                (AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL |
        }
  
        /* Restore TSF */
 -      if (tsf)
 -              ath9k_hw_settsf64(ah, tsf);
 +      getrawmonotonic(&ts);
 +      usec = ts.tv_sec * 1000 + ts.tv_nsec / 1000 - usec;
 +      ath9k_hw_settsf64(ah, tsf + usec);
  
        if (AR_SREV_9280_20_OR_LATER(ah))
                REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE);
index ddb5b2f7a4b0710c3d48a2d9463447e927bf1e13,366339421d4f1c924e4e1e69c34ce88bce9ab028..823631cdb872bc8799229a9d91388d377a5511fc
@@@ -115,22 -115,6 +115,22 @@@ static void wcn36xx_smd_set_sta_ht_para
        }
  }
  
 +static void wcn36xx_smd_set_sta_default_ht_params(
 +              struct wcn36xx_hal_config_sta_params *sta_params)
 +{
 +      sta_params->ht_capable = 1;
 +      sta_params->tx_channel_width_set = 1;
 +      sta_params->lsig_txop_protection = 1;
 +      sta_params->max_ampdu_size = 3;
 +      sta_params->max_ampdu_density = 5;
 +      sta_params->max_amsdu_size = 0;
 +      sta_params->sgi_20Mhz = 1;
 +      sta_params->sgi_40mhz = 1;
 +      sta_params->green_field_capable = 1;
 +      sta_params->delayed_ba_support = 0;
 +      sta_params->dsss_cck_mode_40mhz = 1;
 +}
 +
  static void wcn36xx_smd_set_sta_params(struct wcn36xx *wcn,
                struct ieee80211_vif *vif,
                struct ieee80211_sta *sta,
                        sizeof(priv_sta->supported_rates));
        } else {
                wcn36xx_set_default_rates(&sta_params->supported_rates);
 +              wcn36xx_smd_set_sta_default_ht_params(sta_params);
        }
  }
  
@@@ -1855,7 -1838,7 +1855,7 @@@ out
  int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index)
  {
        struct wcn36xx_hal_trigger_ba_req_msg msg_body;
 -      struct wcn36xx_hal_trigget_ba_req_candidate *candidate;
 +      struct wcn36xx_hal_trigger_ba_req_candidate *candidate;
        int ret = 0;
  
        mutex_lock(&wcn->hal_mutex);
        msg_body.header.len += sizeof(*candidate);
        PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
  
 -      candidate = (struct wcn36xx_hal_trigget_ba_req_candidate *)
 +      candidate = (struct wcn36xx_hal_trigger_ba_req_candidate *)
                (wcn->hal_buf + sizeof(msg_body));
        candidate->sta_index = sta_index;
        candidate->tid_bitmap = 1;
@@@ -2058,13 -2041,20 +2058,20 @@@ static void wcn36xx_smd_rsp_process(str
        case WCN36XX_HAL_DELETE_STA_CONTEXT_IND:
                mutex_lock(&wcn->hal_ind_mutex);
                msg_ind = kmalloc(sizeof(*msg_ind), GFP_KERNEL);
-               msg_ind->msg_len = len;
-               msg_ind->msg = kmalloc(len, GFP_KERNEL);
-               memcpy(msg_ind->msg, buf, len);
-               list_add_tail(&msg_ind->list, &wcn->hal_ind_queue);
-               queue_work(wcn->hal_ind_wq, &wcn->hal_ind_work);
-               wcn36xx_dbg(WCN36XX_DBG_HAL, "indication arrived\n");
+               if (msg_ind) {
+                       msg_ind->msg_len = len;
+                       msg_ind->msg = kmalloc(len, GFP_KERNEL);
+                       memcpy(msg_ind->msg, buf, len);
+                       list_add_tail(&msg_ind->list, &wcn->hal_ind_queue);
+                       queue_work(wcn->hal_ind_wq, &wcn->hal_ind_work);
+                       wcn36xx_dbg(WCN36XX_DBG_HAL, "indication arrived\n");
+               }
                mutex_unlock(&wcn->hal_ind_mutex);
+               if (msg_ind)
+                       break;
+               /* FIXME: Do something smarter then just printing an error. */
+               wcn36xx_err("Run out of memory while handling SMD_EVENT (%d)\n",
+                           msg_header->msg_type);
                break;
        default:
                wcn36xx_err("SMD_EVENT (%d) not supported\n",
index 57918579d55ddd52ce2c1ebc9d4e8d2989c7370d,54e36fcb39542e8361dfdc019134f3ba1538de8f..fcfed6b99a62d6e16e66634df2df85198cbb64da
@@@ -4,10 -4,13 +4,12 @@@ config BRCMUTI
  config BRCMSMAC
        tristate "Broadcom IEEE802.11n PCIe SoftMAC WLAN driver"
        depends on MAC80211
 -      depends on BCMA
 +      depends on BCMA_POSSIBLE
 +      select BCMA
+       select NEW_LEDS if BCMA_DRIVER_GPIO
+       select LEDS_CLASS if BCMA_DRIVER_GPIO
        select BRCMUTIL
        select FW_LOADER
 -      select CRC_CCITT
 -      select CRC8
        select CORDIC
        ---help---
          This module adds support for PCIe wireless adapters based on Broadcom
index 225493aec72d494ab4f99356c278868237a15f0a,abc9ceca70f3630251ad077fe307f05a8a979adc..a511c27122b8c01da665a586675fb10a74a19bfc
@@@ -109,6 -109,8 +109,8 @@@ static inline int brcmf_sdioh_f0_write_
                                        brcmf_err("Disable F2 failed:%d\n",
                                                  err_ret);
                        }
+               } else {
+                       err_ret = -ENOENT;
                }
        } else if ((regaddr == SDIO_CCCR_ABORT) ||
                   (regaddr == SDIO_CCCR_IENx)) {
@@@ -156,21 -158,10 +158,21 @@@ int brcmf_sdioh_request_byte(struct brc
                }
        }
  
 -      if (err_ret)
 -              brcmf_err("Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",
 -                        rw ? "write" : "read", func, regaddr, *byte, err_ret);
 -
 +      if (err_ret) {
 +              /*
 +               * SleepCSR register access can fail when
 +               * waking up the device so reduce this noise
 +               * in the logs.
 +               */
 +              if (regaddr != SBSDIO_FUNC1_SLEEPCSR)
 +                      brcmf_err("Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",
 +                                rw ? "write" : "read", func, regaddr, *byte,
 +                                err_ret);
 +              else
 +                      brcmf_dbg(SDIO, "Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",
 +                                rw ? "write" : "read", func, regaddr, *byte,
 +                                err_ret);
 +      }
        return err_ret;
  }
  
@@@ -278,9 -269,6 +280,9 @@@ static int brcmf_sdioh_enablefuncs(stru
  int brcmf_sdioh_attach(struct brcmf_sdio_dev *sdiodev)
  {
        int err_ret = 0;
 +      struct mmc_host *host;
 +      struct sdio_func *func;
 +      uint max_blocks;
  
        brcmf_dbg(SDIO, "\n");
  
  
        brcmf_sdioh_enablefuncs(sdiodev);
  
 +      /*
 +       * determine host related variables after brcmf_sdio_probe()
 +       * as func->cur_blksize is properly set and F2 init has been
 +       * completed successfully.
 +       */
 +      func = sdiodev->func[2];
 +      host = func->card->host;
 +      sdiodev->sg_support = host->max_segs > 1;
 +      max_blocks = min_t(uint, host->max_blk_count, 511u);
 +      sdiodev->max_request_size = min_t(uint, host->max_req_size,
 +                                        max_blocks * func->cur_blksize);
 +      sdiodev->max_segment_count = min_t(uint, host->max_segs,
 +                                         SG_MAX_SINGLE_ALLOC);
 +      sdiodev->max_segment_size = host->max_seg_size;
  out:
        sdio_release_host(sdiodev->func[1]);
        brcmf_dbg(SDIO, "Done\n");
@@@ -344,6 -318,8 +346,6 @@@ static int brcmf_ops_sdio_probe(struct 
        int err;
        struct brcmf_sdio_dev *sdiodev;
        struct brcmf_bus *bus_if;
 -      struct mmc_host *host;
 -      uint max_blocks;
  
        brcmf_dbg(SDIO, "Enter\n");
        brcmf_dbg(SDIO, "Class=%x\n", func->class);
                goto fail;
        }
  
 -      /*
 -       * determine host related variables after brcmf_sdio_probe()
 -       * as func->cur_blksize is properly set and F2 init has been
 -       * completed successfully.
 -       */
 -      host = func->card->host;
 -      sdiodev->sg_support = host->max_segs > 1;
 -      max_blocks = min_t(uint, host->max_blk_count, 511u);
 -      sdiodev->max_request_size = min_t(uint, host->max_req_size,
 -                                        max_blocks * func->cur_blksize);
 -      sdiodev->max_segment_count = min_t(uint, host->max_segs,
 -                                         SG_MAX_SINGLE_ALLOC);
 -      sdiodev->max_segment_size = host->max_seg_size;
        brcmf_dbg(SDIO, "F2 init completed...\n");
        return 0;
  
index 3f9a4c9ad77a1d67ca53a0d6962800a20bff6391,c72438bb2fafd24b8e59f416d4e4311752dce941..9c0cc8ded0216de43d09300dbed19cfa9fe2e3b3
@@@ -159,7 -159,7 +159,7 @@@ static const struct ieee80211_regdomai
        .reg_rules = {
                REG_RULE(2412-10, 2462+10, 40, 0, 20, 0),
                REG_RULE(5725-10, 5850+10, 40, 0, 30,
 -                      NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS),
 +                       NL80211_RRF_NO_IR),
        }
  };
  
@@@ -353,6 -353,7 +353,6 @@@ struct mac80211_hwsim_data 
        } ps;
        bool ps_poll_pending;
        struct dentry *debugfs;
 -      struct dentry *debugfs_ps;
  
        struct sk_buff_head pending;    /* packets pending */
        /*
         * radio can be in more then one group.
         */
        u64 group;
 -      struct dentry *debugfs_group;
  
        int power_level;
  
@@@ -381,6 -383,14 +381,14 @@@ struct hwsim_radiotap_hdr 
        __le16 rt_chbitmask;
  } __packed;
  
+ struct hwsim_radiotap_ack_hdr {
+       struct ieee80211_radiotap_header hdr;
+       u8 rt_flags;
+       u8 pad;
+       __le16 rt_channel;
+       __le16 rt_chbitmask;
+ } __packed;
  /* MAC80211_HWSIM netlinf family */
  static struct genl_family hwsim_genl_family = {
        .id = GENL_ID_GENERATE,
@@@ -498,7 -508,7 +506,7 @@@ static void mac80211_hwsim_monitor_ack(
                                       const u8 *addr)
  {
        struct sk_buff *skb;
-       struct hwsim_radiotap_hdr *hdr;
+       struct hwsim_radiotap_ack_hdr *hdr;
        u16 flags;
        struct ieee80211_hdr *hdr11;
  
        if (skb == NULL)
                return;
  
-       hdr = (struct hwsim_radiotap_hdr *) skb_put(skb, sizeof(*hdr));
+       hdr = (struct hwsim_radiotap_ack_hdr *) skb_put(skb, sizeof(*hdr));
        hdr->hdr.it_version = PKTHDR_RADIOTAP_VERSION;
        hdr->hdr.it_pad = 0;
        hdr->hdr.it_len = cpu_to_le16(sizeof(*hdr));
        hdr->hdr.it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
                                          (1 << IEEE80211_RADIOTAP_CHANNEL));
        hdr->rt_flags = 0;
-       hdr->rt_rate = 0;
+       hdr->pad = 0;
        hdr->rt_channel = cpu_to_le16(chan->center_freq);
        flags = IEEE80211_CHAN_2GHZ;
        hdr->rt_chbitmask = cpu_to_le16(flags);
@@@ -1228,7 -1238,7 +1236,7 @@@ static void mac80211_hwsim_bss_info_cha
                                              HRTIMER_MODE_REL);
                } else if (!info->enable_beacon) {
                        unsigned int count = 0;
-                       ieee80211_iterate_active_interfaces(
+                       ieee80211_iterate_active_interfaces_atomic(
                                data->hw, IEEE80211_IFACE_ITER_NORMAL,
                                mac80211_hwsim_bcn_en_iter, &count);
                        wiphy_debug(hw->wiphy, "  beaconing vifs remaining: %u",
@@@ -1483,7 -1493,7 +1491,7 @@@ static void hw_scan_work(struct work_st
                    req->channels[hwsim->scan_chan_idx]->center_freq);
  
        hwsim->tmp_chan = req->channels[hwsim->scan_chan_idx];
 -      if (hwsim->tmp_chan->flags & IEEE80211_CHAN_PASSIVE_SCAN ||
 +      if (hwsim->tmp_chan->flags & IEEE80211_CHAN_NO_IR ||
            !req->n_ssids) {
                dwell = 120;
        } else {
@@@ -1732,7 -1742,9 +1740,7 @@@ static void mac80211_hwsim_free(void
        spin_unlock_bh(&hwsim_radio_lock);
  
        list_for_each_entry_safe(data, tmpdata, &tmplist, list) {
 -              debugfs_remove(data->debugfs_group);
 -              debugfs_remove(data->debugfs_ps);
 -              debugfs_remove(data->debugfs);
 +              debugfs_remove_recursive(data->debugfs);
                ieee80211_unregister_hw(data->hw);
                device_release_driver(data->dev);
                device_unregister(data->dev);
@@@ -1889,17 -1901,6 +1897,17 @@@ static int hwsim_fops_ps_write(void *da
  DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_ps, hwsim_fops_ps_read, hwsim_fops_ps_write,
                        "%llu\n");
  
 +static int hwsim_write_simulate_radar(void *dat, u64 val)
 +{
 +      struct mac80211_hwsim_data *data = dat;
 +
 +      ieee80211_radar_detected(data->hw);
 +
 +      return 0;
 +}
 +
 +DEFINE_SIMPLE_ATTRIBUTE(hwsim_simulate_radar, NULL,
 +                      hwsim_write_simulate_radar, "%llu\n");
  
  static int hwsim_fops_group_read(void *dat, u64 *val)
  {
@@@ -2200,28 -2201,11 +2208,28 @@@ static const struct ieee80211_iface_lim
        { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) },
  };
  
 -static struct ieee80211_iface_combination hwsim_if_comb = {
 -      .limits = hwsim_if_limits,
 -      .n_limits = ARRAY_SIZE(hwsim_if_limits),
 -      .max_interfaces = 2048,
 -      .num_different_channels = 1,
 +static const struct ieee80211_iface_limit hwsim_if_dfs_limits[] = {
 +      { .max = 8, .types = BIT(NL80211_IFTYPE_AP) },
 +};
 +
 +static struct ieee80211_iface_combination hwsim_if_comb[] = {
 +      {
 +              .limits = hwsim_if_limits,
 +              .n_limits = ARRAY_SIZE(hwsim_if_limits),
 +              .max_interfaces = 2048,
 +              .num_different_channels = 1,
 +      },
 +      {
 +              .limits = hwsim_if_dfs_limits,
 +              .n_limits = ARRAY_SIZE(hwsim_if_dfs_limits),
 +              .max_interfaces = 8,
 +              .num_different_channels = 1,
 +              .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
 +                                     BIT(NL80211_CHAN_WIDTH_20) |
 +                                     BIT(NL80211_CHAN_WIDTH_40) |
 +                                     BIT(NL80211_CHAN_WIDTH_80) |
 +                                     BIT(NL80211_CHAN_WIDTH_160),
 +      }
  };
  
  static int __init init_mac80211_hwsim(void)
                return -EINVAL;
  
        if (channels > 1) {
 -              hwsim_if_comb.num_different_channels = channels;
 +              hwsim_if_comb[0].num_different_channels = channels;
                mac80211_hwsim_ops.hw_scan = mac80211_hwsim_hw_scan;
                mac80211_hwsim_ops.cancel_hw_scan =
                        mac80211_hwsim_cancel_hw_scan;
                hw->wiphy->n_addresses = 2;
                hw->wiphy->addresses = data->addresses;
  
 -              hw->wiphy->iface_combinations = &hwsim_if_comb;
 -              hw->wiphy->n_iface_combinations = 1;
 +              hw->wiphy->iface_combinations = hwsim_if_comb;
 +              hw->wiphy->n_iface_combinations = ARRAY_SIZE(hwsim_if_comb);
  
                if (channels > 1) {
                        hw->wiphy->max_scan_ssids = 255;
                        hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
                        hw->wiphy->max_remain_on_channel_duration = 1000;
 +                      /* For channels > 1 DFS is not allowed */
 +                      hw->wiphy->n_iface_combinations = 1;
                }
  
                INIT_DELAYED_WORK(&data->roc_done, hw_roc_done);
                            IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
                            IEEE80211_HW_AMPDU_AGGREGATION |
                            IEEE80211_HW_WANT_MONITOR_VIF |
 -                          IEEE80211_HW_QUEUE_CONTROL;
 +                          IEEE80211_HW_QUEUE_CONTROL |
 +                          IEEE80211_HW_SUPPORTS_HT_CCK_RATES;
                if (rctbl)
                        hw->flags |= IEEE80211_HW_SUPPORTS_RC_TABLE;
  
                        sband->vht_cap.cap =
                                IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
                                IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ |
 +                              IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
                                IEEE80211_VHT_CAP_RXLDPC |
                                IEEE80211_VHT_CAP_SHORT_GI_80 |
                                IEEE80211_VHT_CAP_SHORT_GI_160 |
                        break;
                case HWSIM_REGTEST_WORLD_ROAM:
                        if (i == 0) {
 -                              hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
 +                              hw->wiphy->regulatory_flags |=
 +                                      REGULATORY_CUSTOM_REG;
                                wiphy_apply_custom_regulatory(hw->wiphy,
                                        &hwsim_world_regdom_custom_01);
                        }
                        break;
                case HWSIM_REGTEST_CUSTOM_WORLD:
 -                      hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
 +                      hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
                        wiphy_apply_custom_regulatory(hw->wiphy,
                                &hwsim_world_regdom_custom_01);
                        break;
                case HWSIM_REGTEST_CUSTOM_WORLD_2:
                        if (i == 0) {
 -                              hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
 +                              hw->wiphy->regulatory_flags |=
 +                                      REGULATORY_CUSTOM_REG;
                                wiphy_apply_custom_regulatory(hw->wiphy,
                                        &hwsim_world_regdom_custom_01);
                        } else if (i == 1) {
 -                              hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
 +                              hw->wiphy->regulatory_flags |=
 +                                      REGULATORY_CUSTOM_REG;
                                wiphy_apply_custom_regulatory(hw->wiphy,
                                        &hwsim_world_regdom_custom_02);
                        }
                        break;
                case HWSIM_REGTEST_STRICT_ALL:
 -                      hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
 +                      hw->wiphy->regulatory_flags |= REGULATORY_STRICT_REG;
                        break;
                case HWSIM_REGTEST_STRICT_FOLLOW:
                case HWSIM_REGTEST_STRICT_AND_DRIVER_REG:
                        if (i == 0)
 -                              hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
 +                              hw->wiphy->regulatory_flags |=
 +                                      REGULATORY_STRICT_REG;
                        break;
                case HWSIM_REGTEST_ALL:
                        if (i == 0) {
 -                              hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
 +                              hw->wiphy->regulatory_flags |=
 +                                      REGULATORY_CUSTOM_REG;
                                wiphy_apply_custom_regulatory(hw->wiphy,
                                        &hwsim_world_regdom_custom_01);
                        } else if (i == 1) {
 -                              hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
 +                              hw->wiphy->regulatory_flags |=
 +                                      REGULATORY_CUSTOM_REG;
                                wiphy_apply_custom_regulatory(hw->wiphy,
                                        &hwsim_world_regdom_custom_02);
                        } else if (i == 4)
 -                              hw->wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
 +                              hw->wiphy->regulatory_flags |=
 +                                      REGULATORY_STRICT_REG;
                        break;
                default:
                        break;
  
                data->debugfs = debugfs_create_dir("hwsim",
                                                   hw->wiphy->debugfsdir);
 -              data->debugfs_ps = debugfs_create_file("ps", 0666,
 -                                                     data->debugfs, data,
 -                                                     &hwsim_fops_ps);
 -              data->debugfs_group = debugfs_create_file("group", 0666,
 -                                                      data->debugfs, data,
 -                                                      &hwsim_fops_group);
 +              debugfs_create_file("ps", 0666, data->debugfs, data,
 +                                  &hwsim_fops_ps);
 +              debugfs_create_file("group", 0666, data->debugfs, data,
 +                                  &hwsim_fops_group);
 +              if (channels == 1)
 +                      debugfs_create_file("dfs_simulate_radar", 0222,
 +                                          data->debugfs,
 +                                          data, &hwsim_simulate_radar);
  
                tasklet_hrtimer_init(&data->beacon_timer,
                                     mac80211_hwsim_beacon,
 -                                   CLOCK_REALTIME, HRTIMER_MODE_ABS);
 +                                   CLOCK_MONOTONIC_RAW, HRTIMER_MODE_ABS);
  
                list_add_tail(&data->list, &hwsim_radios);
        }
diff --combined net/mac80211/cfg.c
index 754069cbb7568474c7bd87060613ec12facf6d9a,364ce0c5962fd48c85ea23b71b2d1dd463082575..f80e8c4c6bcd303762781ed8a2aa613ff763f5fa
@@@ -133,9 -133,7 +133,9 @@@ static int ieee80211_add_key(struct wip
                             struct key_params *params)
  {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 +      struct ieee80211_local *local = sdata->local;
        struct sta_info *sta = NULL;
 +      const struct ieee80211_cipher_scheme *cs = NULL;
        struct ieee80211_key *key;
        int err;
  
        case WLAN_CIPHER_SUITE_WEP40:
        case WLAN_CIPHER_SUITE_TKIP:
        case WLAN_CIPHER_SUITE_WEP104:
 -              if (IS_ERR(sdata->local->wep_tx_tfm))
 +              if (IS_ERR(local->wep_tx_tfm))
                        return -EINVAL;
                break;
 +      case WLAN_CIPHER_SUITE_CCMP:
 +      case WLAN_CIPHER_SUITE_AES_CMAC:
 +      case WLAN_CIPHER_SUITE_GCMP:
 +              break;
        default:
 +              cs = ieee80211_cs_get(local, params->cipher, sdata->vif.type);
                break;
        }
  
        key = ieee80211_key_alloc(params->cipher, key_idx, params->key_len,
 -                                params->key, params->seq_len, params->seq);
 +                                params->key, params->seq_len, params->seq,
 +                                cs);
        if (IS_ERR(key))
                return PTR_ERR(key);
  
        if (pairwise)
                key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE;
  
 -      mutex_lock(&sdata->local->sta_mtx);
 +      mutex_lock(&local->sta_mtx);
  
        if (mac_addr) {
                if (ieee80211_vif_is_mesh(&sdata->vif))
                break;
        }
  
 +      if (sta)
 +              sta->cipher_scheme = cs;
 +
        err = ieee80211_key_link(key, sdata, sta);
  
   out_unlock:
 -      mutex_unlock(&sdata->local->sta_mtx);
 +      mutex_unlock(&local->sta_mtx);
  
        return err;
  }
@@@ -255,7 -244,7 +255,7 @@@ static int ieee80211_del_key(struct wip
                        goto out_unlock;
  
                if (pairwise)
 -                      key = key_mtx_dereference(local, sta->ptk);
 +                      key = key_mtx_dereference(local, sta->ptk[key_idx]);
                else
                        key = key_mtx_dereference(local, sta->gtk[key_idx]);
        } else
@@@ -302,7 -291,7 +302,7 @@@ static int ieee80211_get_key(struct wip
                        goto out;
  
                if (pairwise)
 -                      key = rcu_dereference(sta->ptk);
 +                      key = rcu_dereference(sta->ptk[key_idx]);
                else if (key_idx < NUM_DEFAULT_KEYS)
                        key = rcu_dereference(sta->gtk[key_idx]);
        } else
@@@ -532,8 -521,8 +532,8 @@@ static void sta_set_sinfo(struct sta_in
                                 STATION_INFO_PEER_PM |
                                 STATION_INFO_NONPEER_PM;
  
 -              sinfo->llid = le16_to_cpu(sta->llid);
 -              sinfo->plid = le16_to_cpu(sta->plid);
 +              sinfo->llid = sta->llid;
 +              sinfo->plid = sta->plid;
                sinfo->plink_state = sta->plink_state;
                if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) {
                        sinfo->filled |= STATION_INFO_T_OFFSET;
@@@ -857,7 -846,7 +857,7 @@@ static int ieee80211_set_probe_resp(str
        if (!resp || !resp_len)
                return 1;
  
 -      old = rtnl_dereference(sdata->u.ap.probe_resp);
 +      old = sdata_dereference(sdata->u.ap.probe_resp, sdata);
  
        new = kzalloc(sizeof(struct probe_resp) + resp_len, GFP_KERNEL);
        if (!new)
@@@ -881,8 -870,7 +881,8 @@@ int ieee80211_assign_beacon(struct ieee
        int size, err;
        u32 changed = BSS_CHANGED_BEACON;
  
 -      old = rtnl_dereference(sdata->u.ap.beacon);
 +      old = sdata_dereference(sdata->u.ap.beacon, sdata);
 +
  
        /* Need to have a beacon head if we don't have one yet */
        if (!params->head && !old)
@@@ -959,7 -947,7 +959,7 @@@ static int ieee80211_start_ap(struct wi
                      BSS_CHANGED_P2P_PS;
        int err;
  
 -      old = rtnl_dereference(sdata->u.ap.beacon);
 +      old = sdata_dereference(sdata->u.ap.beacon, sdata);
        if (old)
                return -EALREADY;
  
         */
        sdata->control_port_protocol = params->crypto.control_port_ethertype;
        sdata->control_port_no_encrypt = params->crypto.control_port_no_encrypt;
 +      sdata->encrypt_headroom = ieee80211_cs_headroom(sdata->local,
 +                                                      &params->crypto,
 +                                                      sdata->vif.type);
 +
        list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) {
                vlan->control_port_protocol =
                        params->crypto.control_port_ethertype;
                vlan->control_port_no_encrypt =
                        params->crypto.control_port_no_encrypt;
 +              vlan->encrypt_headroom =
 +                      ieee80211_cs_headroom(sdata->local,
 +                                            &params->crypto,
 +                                            vlan->vif.type);
        }
  
        sdata->vif.bss_conf.beacon_int = params->beacon_interval;
  
        err = drv_start_ap(sdata->local, sdata);
        if (err) {
 -              old = rtnl_dereference(sdata->u.ap.beacon);
 +              old = sdata_dereference(sdata->u.ap.beacon, sdata);
 +
                if (old)
                        kfree_rcu(old, rcu_head);
                RCU_INIT_POINTER(sdata->u.ap.beacon, NULL);
@@@ -1053,7 -1032,7 +1053,7 @@@ static int ieee80211_change_beacon(stru
        if (sdata->vif.csa_active)
                return -EBUSY;
  
 -      old = rtnl_dereference(sdata->u.ap.beacon);
 +      old = sdata_dereference(sdata->u.ap.beacon, sdata);
        if (!old)
                return -ENOENT;
  
@@@ -1071,18 -1050,15 +1071,18 @@@ static int ieee80211_stop_ap(struct wip
        struct ieee80211_local *local = sdata->local;
        struct beacon_data *old_beacon;
        struct probe_resp *old_probe_resp;
 +      struct cfg80211_chan_def chandef;
  
 -      old_beacon = rtnl_dereference(sdata->u.ap.beacon);
 +      old_beacon = sdata_dereference(sdata->u.ap.beacon, sdata);
        if (!old_beacon)
                return -ENOENT;
 -      old_probe_resp = rtnl_dereference(sdata->u.ap.probe_resp);
 +      old_probe_resp = sdata_dereference(sdata->u.ap.probe_resp, sdata);
  
        /* abort any running channel switch */
        sdata->vif.csa_active = false;
 -      cancel_work_sync(&sdata->csa_finalize_work);
 +      kfree(sdata->u.ap.next_beacon);
 +      sdata->u.ap.next_beacon = NULL;
 +
        cancel_work_sync(&sdata->u.ap.request_smps_work);
  
        /* turn off carrier for this interface and dependent VLANs */
        ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
  
        if (sdata->wdev.cac_started) {
 +              chandef = sdata->vif.bss_conf.chandef;
                cancel_delayed_work_sync(&sdata->dfs_cac_timer_work);
 -              cfg80211_cac_event(sdata->dev, NL80211_RADAR_CAC_ABORTED,
 +              cfg80211_cac_event(sdata->dev, &chandef,
 +                                 NL80211_RADAR_CAC_ABORTED,
                                   GFP_KERNEL);
        }
  
@@@ -1394,7 -1368,7 +1394,7 @@@ static int sta_apply_parameters(struct 
                        changed |=
                              ieee80211_mps_set_sta_local_pm(sta,
                                                             params->local_pm);
-               ieee80211_bss_info_change_notify(sdata, changed);
+               ieee80211_mbss_info_change_notify(sdata, changed);
  #endif
        }
  
@@@ -1979,7 -1953,7 +1979,7 @@@ static int ieee80211_change_bss(struct 
        enum ieee80211_band band;
        u32 changed = 0;
  
 -      if (!rtnl_dereference(sdata->u.ap.beacon))
 +      if (!sdata_dereference(sdata->u.ap.beacon, sdata))
                return -ENOENT;
  
        band = ieee80211_get_sdata_band(sdata);
@@@ -2514,8 -2488,7 +2514,7 @@@ static int ieee80211_set_power_mgmt(str
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
  
-       if (sdata->vif.type != NL80211_IFTYPE_STATION &&
-           sdata->vif.type != NL80211_IFTYPE_MESH_POINT)
+       if (sdata->vif.type != NL80211_IFTYPE_STATION)
                return -EOPNOTSUPP;
  
        if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS))
@@@ -2990,33 -2963,27 +2989,33 @@@ void ieee80211_csa_finalize_work(struc
        struct ieee80211_local *local = sdata->local;
        int err, changed = 0;
  
 +      sdata_lock(sdata);
 +      /* AP might have been stopped while waiting for the lock. */
 +      if (!sdata->vif.csa_active)
 +              goto unlock;
 +
        if (!ieee80211_sdata_running(sdata))
 -              return;
 +              goto unlock;
  
        sdata->radar_required = sdata->csa_radar_required;
 -      err = ieee80211_vif_change_channel(sdata, &local->csa_chandef,
 -                                         &changed);
 +      err = ieee80211_vif_change_channel(sdata, &changed);
        if (WARN_ON(err < 0))
 -              return;
 +              goto unlock;
  
        if (!local->use_chanctx) {
 -              local->_oper_chandef = local->csa_chandef;
 +              local->_oper_chandef = sdata->csa_chandef;
                ieee80211_hw_config(local, 0);
        }
  
        ieee80211_bss_info_change_notify(sdata, changed);
  
 +      sdata->vif.csa_active = false;
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_AP:
                err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon);
                if (err < 0)
 -                      return;
 +                      goto unlock;
 +
                changed |= err;
                kfree(sdata->u.ap.next_beacon);
                sdata->u.ap.next_beacon = NULL;
        case NL80211_IFTYPE_MESH_POINT:
                err = ieee80211_mesh_finish_csa(sdata);
                if (err < 0)
 -                      return;
 +                      goto unlock;
                break;
  #endif
        default:
                WARN_ON(1);
 -              return;
 +              goto unlock;
        }
 -      sdata->vif.csa_active = false;
  
        ieee80211_wake_queues_by_reason(&sdata->local->hw,
                                        IEEE80211_MAX_QUEUE_MAP,
                                        IEEE80211_QUEUE_STOP_REASON_CSA);
  
 -      cfg80211_ch_switch_notify(sdata->dev, &local->csa_chandef);
 +      cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef);
 +
 +unlock:
 +      sdata_unlock(sdata);
  }
  
  static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
        struct ieee80211_if_mesh __maybe_unused *ifmsh;
        int err, num_chanctx;
  
 +      lockdep_assert_held(&sdata->wdev.mtx);
 +
        if (!list_empty(&local->roc_list) || local->scanning)
                return -EBUSY;
  
                    params->chandef.chan->band)
                        return -EINVAL;
  
+               ifmsh->chsw_init = true;
+               if (!ifmsh->pre_value)
+                       ifmsh->pre_value = 1;
+               else
+                       ifmsh->pre_value++;
                err = ieee80211_mesh_csa_beacon(sdata, params, true);
-               if (err < 0)
+               if (err < 0) {
+                       ifmsh->chsw_init = false;
                        return err;
+               }
                break;
  #endif
        default:
                                IEEE80211_MAX_QUEUE_MAP,
                                IEEE80211_QUEUE_STOP_REASON_CSA);
  
 -      local->csa_chandef = params->chandef;
 +      sdata->csa_chandef = params->chandef;
        sdata->vif.csa_active = true;
  
        ieee80211_bss_info_change_notify(sdata, err);
  }
  
  static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
 -                           struct ieee80211_channel *chan, bool offchan,
 -                           unsigned int wait, const u8 *buf, size_t len,
 -                           bool no_cck, bool dont_wait_for_ack, u64 *cookie)
 +                           struct cfg80211_mgmt_tx_params *params,
 +                           u64 *cookie)
  {
        struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
        struct ieee80211_local *local = sdata->local;
        struct sk_buff *skb;
        struct sta_info *sta;
 -      const struct ieee80211_mgmt *mgmt = (void *)buf;
 +      const struct ieee80211_mgmt *mgmt = (void *)params->buf;
        bool need_offchan = false;
        u32 flags;
        int ret;
  
 -      if (dont_wait_for_ack)
 +      if (params->dont_wait_for_ack)
                flags = IEEE80211_TX_CTL_NO_ACK;
        else
                flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX |
                        IEEE80211_TX_CTL_REQ_TX_STATUS;
  
 -      if (no_cck)
 +      if (params->no_cck)
                flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
  
        switch (sdata->vif.type) {
        /* configurations requiring offchan cannot work if no channel has been
         * specified
         */
 -      if (need_offchan && !chan)
 +      if (need_offchan && !params->chan)
                return -EINVAL;
  
        mutex_lock(&local->mtx);
                chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
  
                if (chanctx_conf) {
 -                      need_offchan = chan && (chan != chanctx_conf->def.chan);
 -              } else if (!chan) {
 +                      need_offchan = params->chan &&
 +                                     (params->chan !=
 +                                      chanctx_conf->def.chan);
 +              } else if (!params->chan) {
                        ret = -EINVAL;
                        rcu_read_unlock();
                        goto out_unlock;
                rcu_read_unlock();
        }
  
 -      if (need_offchan && !offchan) {
 +      if (need_offchan && !params->offchan) {
                ret = -EBUSY;
                goto out_unlock;
        }
  
 -      skb = dev_alloc_skb(local->hw.extra_tx_headroom + len);
 +      skb = dev_alloc_skb(local->hw.extra_tx_headroom + params->len);
        if (!skb) {
                ret = -ENOMEM;
                goto out_unlock;
        }
        skb_reserve(skb, local->hw.extra_tx_headroom);
  
 -      memcpy(skb_put(skb, len), buf, len);
 +      memcpy(skb_put(skb, params->len), params->buf, params->len);
  
        IEEE80211_SKB_CB(skb)->flags = flags;
  
                        local->hw.offchannel_tx_hw_queue;
  
        /* This will handle all kinds of coalescing and immediate TX */
 -      ret = ieee80211_start_roc_work(local, sdata, chan,
 -                                     wait, cookie, skb,
 +      ret = ieee80211_start_roc_work(local, sdata, params->chan,
 +                                     params->wait, cookie, skb,
                                       IEEE80211_ROC_TYPE_MGMT_TX);
        if (ret)
                kfree_skb(skb);
diff --combined net/mac80211/ibss.c
index 0f1fb5db4bdb6f557007d7883dced071c2032aa8,27a39de89679b7d3710fea18a65b6d5df6d003d0..2eda7b13124abb7469a8b7b86503de07c0155623
@@@ -550,12 -550,12 +550,12 @@@ int ieee80211_ibss_finish_csa(struct ie
                                        capability);
                /* XXX: should not really modify cfg80211 data */
                if (cbss) {
 -                      cbss->channel = sdata->local->csa_chandef.chan;
 +                      cbss->channel = sdata->csa_chandef.chan;
                        cfg80211_put_bss(sdata->local->hw.wiphy, cbss);
                }
        }
  
 -      ifibss->chandef = sdata->local->csa_chandef;
 +      ifibss->chandef = sdata->csa_chandef;
  
        /* generate the beacon */
        err = ieee80211_ibss_csa_beacon(sdata, NULL);
@@@ -823,6 -823,10 +823,10 @@@ ieee80211_ibss_process_chanswitch(struc
        if (err)
                return false;
  
+       /* channel switch is not supported, disconnect */
+       if (!(sdata->local->hw.wiphy->flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH))
+               goto disconnect;
        params.count = csa_ie.count;
        params.chandef = csa_ie.chandef;
  
                                IEEE80211_MAX_QUEUE_MAP,
                                IEEE80211_QUEUE_STOP_REASON_CSA);
  
 -      sdata->local->csa_chandef = params.chandef;
 +      sdata->csa_chandef = params.chandef;
        sdata->vif.csa_active = true;
  
        ieee80211_bss_info_change_notify(sdata, err);
index 32bae218d6e58b56b802d98955d46fea38935eeb,4aea4e7911135133818e66a1439b111d14e6147e..ed5bf8b4b5c2bfb8d4253a0dbaa15b76aac309dd
@@@ -728,7 -728,6 +728,7 @@@ struct ieee80211_sub_if_data 
        u16 sequence_number;
        __be16 control_port_protocol;
        bool control_port_no_encrypt;
 +      int encrypt_headroom;
  
        struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS];
  
        int csa_counter_offset_beacon;
        int csa_counter_offset_presp;
        bool csa_radar_required;
 +      struct cfg80211_chan_def csa_chandef;
  
        /* used to reconfigure hardware SM PS */
        struct work_struct recalc_smps;
@@@ -813,9 -811,6 +813,9 @@@ static inline void sdata_unlock(struct 
        __release(&sdata->wdev.mtx);
  }
  
 +#define sdata_dereference(p, sdata) \
 +      rcu_dereference_protected(p, lockdep_is_held(&sdata->wdev.mtx))
 +
  static inline void
  sdata_assert_lock(struct ieee80211_sub_if_data *sdata)
  {
@@@ -901,24 -896,6 +901,24 @@@ struct tpt_led_trigger 
  };
  #endif
  
 +/*
 + * struct ieee80211_tx_latency_bin_ranges - Tx latency statistics bins ranges
 + *
 + * Measuring Tx latency statistics. Counts how many Tx frames transmitted in a
 + * certain latency range (in Milliseconds). Each station that uses these
 + * ranges will have bins to count the amount of frames received in that range.
 + * The user can configure the ranges via debugfs.
 + * If ranges is NULL then Tx latency statistics bins are disabled for all
 + * stations.
 + *
 + * @n_ranges: number of ranges that are taken in account
 + * @ranges: the ranges that the user requested or NULL if disabled.
 + */
 +struct ieee80211_tx_latency_bin_ranges {
 +      int n_ranges;
 +      u32 ranges[];
 +};
 +
  /**
   * mac80211 scan flags - currently active scan mode
   *
@@@ -1071,12 -1048,6 +1071,12 @@@ struct ieee80211_local 
        struct timer_list sta_cleanup;
        int sta_generation;
  
 +      /*
 +       * Tx latency statistics parameters for all stations.
 +       * Can enable via debugfs (NULL when disabled).
 +       */
 +      struct ieee80211_tx_latency_bin_ranges __rcu *tx_latency;
 +
        struct sk_buff_head pending[IEEE80211_MAX_QUEUES];
        struct tasklet_struct tx_pending_tasklet;
  
        enum mac80211_scan_state next_scan_state;
        struct delayed_work scan_work;
        struct ieee80211_sub_if_data __rcu *scan_sdata;
 -      struct cfg80211_chan_def csa_chandef;
        /* For backward compatibility only -- do not use */
        struct cfg80211_chan_def _oper_chandef;
  
@@@ -1256,6 -1228,7 +1256,7 @@@ struct ieee80211_csa_ie 
        u8 mode;
        u8 count;
        u8 ttl;
+       u16 pre_value;
  };
  
  /* Parsed Information Elements */
@@@ -1720,7 -1693,6 +1721,7 @@@ int __ieee80211_request_smps_mgd(struc
  int __ieee80211_request_smps_ap(struct ieee80211_sub_if_data *sdata,
                                enum ieee80211_smps_mode smps_mode);
  void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata);
 +void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata);
  
  size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
                          const u8 *ids, int n_ids, size_t offset);
@@@ -1759,6 -1731,7 +1760,6 @@@ ieee80211_vif_change_bandwidth(struct i
  /* NOTE: only use ieee80211_vif_change_channel() for channel switch */
  int __must_check
  ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
 -                           const struct cfg80211_chan_def *chandef,
                             u32 *changed);
  void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata);
  void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata);
@@@ -1769,8 -1742,6 +1770,8 @@@ void ieee80211_recalc_smps_chanctx(stru
                                   struct ieee80211_chanctx *chanctx);
  void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local,
                                    struct ieee80211_chanctx *chanctx);
 +void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
 +                                    struct ieee80211_chanctx *ctx);
  
  void ieee80211_dfs_cac_timer(unsigned long data);
  void ieee80211_dfs_cac_timer_work(struct work_struct *work);
@@@ -1779,15 -1750,6 +1780,15 @@@ void ieee80211_dfs_radar_detected_work(
  int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
                              struct cfg80211_csa_settings *csa_settings);
  
 +bool ieee80211_cs_valid(const struct ieee80211_cipher_scheme *cs);
 +bool ieee80211_cs_list_valid(const struct ieee80211_cipher_scheme *cs, int n);
 +const struct ieee80211_cipher_scheme *
 +ieee80211_cs_get(struct ieee80211_local *local, u32 cipher,
 +               enum nl80211_iftype iftype);
 +int ieee80211_cs_headroom(struct ieee80211_local *local,
 +                        struct cfg80211_crypto_settings *crypto,
 +                        enum nl80211_iftype iftype);
 +
  #ifdef CONFIG_MAC80211_NOINLINE
  #define debug_noinline noinline
  #else
diff --combined net/mac80211/iface.c
index d226751ba63af6c73bf0efcd658465d3aed19b72,36c3a4cbcabf66b2a0864414b3c23ea2896b7c4e..7aa9f9dea9df0af487c25c36d52004179d76b72c
@@@ -401,8 -401,6 +401,8 @@@ int ieee80211_add_virtual_monitor(struc
        snprintf(sdata->name, IFNAMSIZ, "%s-monitor",
                 wiphy_name(local->hw.wiphy));
  
 +      sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;
 +
        ieee80211_set_default_queues(sdata);
  
        ret = drv_add_interface(local, sdata);
@@@ -751,7 -749,6 +751,7 @@@ static void ieee80211_do_stop(struct ie
        u32 hw_reconf_flags = 0;
        int i, flushed;
        struct ps_data *ps;
 +      struct cfg80211_chan_def chandef;
  
        clear_bit(SDATA_STATE_RUNNING, &sdata->state);
  
        cancel_delayed_work_sync(&sdata->dfs_cac_timer_work);
  
        if (sdata->wdev.cac_started) {
 +              chandef = sdata->vif.bss_conf.chandef;
                WARN_ON(local->suspended);
                mutex_lock(&local->iflist_mtx);
                ieee80211_vif_release_channel(sdata);
                mutex_unlock(&local->iflist_mtx);
 -              cfg80211_cac_event(sdata->dev, NL80211_RADAR_CAC_ABORTED,
 +              cfg80211_cac_event(sdata->dev, &chandef,
 +                                 NL80211_RADAR_CAC_ABORTED,
                                   GFP_KERNEL);
        }
  
@@@ -1041,6 -1036,7 +1041,6 @@@ static void ieee80211_set_multicast_lis
   */
  static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata)
  {
 -      int flushed;
        int i;
  
        /* free extra data */
  
        if (ieee80211_vif_is_mesh(&sdata->vif))
                mesh_rmc_free(sdata);
 -
 -      flushed = sta_info_flush(sdata);
 -      WARN_ON(flushed);
  }
  
  static void ieee80211_uninit(struct net_device *dev)
@@@ -1271,7 -1270,6 +1271,7 @@@ static void ieee80211_setup_sdata(struc
  
        sdata->control_port_protocol = cpu_to_be16(ETH_P_PAE);
        sdata->control_port_no_encrypt = false;
 +      sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;
  
        sdata->noack_map = 0;
  
                sdata->vif.bss_conf.bssid = NULL;
                break;
        case NL80211_IFTYPE_AP_VLAN:
-               break;
        case NL80211_IFTYPE_P2P_DEVICE:
                sdata->vif.bss_conf.bssid = sdata->vif.addr;
                break;
@@@ -1688,8 -1685,6 +1687,8 @@@ int ieee80211_if_add(struct ieee80211_l
        sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL;
        sdata->user_power_level = local->user_power_level;
  
 +      sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;
 +
        /* setup type-dependent data */
        ieee80211_setup_sdata(sdata, type);
  
diff --combined net/mac80211/main.c
index 8af75f0eed6ddd2fd9cbd47cc0dd8ae702f0e567,7d1c3ac48ed941866170afdf387def183690d612..fa34cd2344b98b9615a940a00e78363b494bc06c
@@@ -651,14 -651,15 +651,14 @@@ struct ieee80211_hw *ieee80211_alloc_hw
  }
  EXPORT_SYMBOL(ieee80211_alloc_hw);
  
 -int ieee80211_register_hw(struct ieee80211_hw *hw)
 +static int ieee80211_init_cipher_suites(struct ieee80211_local *local)
  {
 -      struct ieee80211_local *local = hw_to_local(hw);
 -      int result, i;
 -      enum ieee80211_band band;
 -      int channels, max_bitrates;
 -      bool supp_ht, supp_vht;
 -      netdev_features_t feature_whitelist;
 -      struct cfg80211_chan_def dflt_chandef = {};
 +      bool have_wep = !(IS_ERR(local->wep_tx_tfm) ||
 +                        IS_ERR(local->wep_rx_tfm));
 +      bool have_mfp = local->hw.flags & IEEE80211_HW_MFP_CAPABLE;
 +      const struct ieee80211_cipher_scheme *cs = local->hw.cipher_schemes;
 +      int n_suites = 0, r = 0, w = 0;
 +      u32 *suites;
        static const u32 cipher_suites[] = {
                /* keep WEP first, it may be removed below */
                WLAN_CIPHER_SUITE_WEP40,
                WLAN_CIPHER_SUITE_AES_CMAC
        };
  
 +      /* Driver specifies the ciphers, we have nothing to do... */
 +      if (local->hw.wiphy->cipher_suites && have_wep)
 +              return 0;
 +
 +      /* Set up cipher suites if driver relies on mac80211 cipher defs */
 +      if (!local->hw.wiphy->cipher_suites && !cs) {
 +              local->hw.wiphy->cipher_suites = cipher_suites;
 +              local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
 +
 +              if (!have_mfp)
 +                      local->hw.wiphy->n_cipher_suites--;
 +
 +              if (!have_wep) {
 +                      local->hw.wiphy->cipher_suites += 2;
 +                      local->hw.wiphy->n_cipher_suites -= 2;
 +              }
 +
 +              return 0;
 +      }
 +
 +      if (!local->hw.wiphy->cipher_suites) {
 +              /*
 +               * Driver specifies cipher schemes only
 +               * We start counting ciphers defined by schemes, TKIP and CCMP
 +               */
 +              n_suites = local->hw.n_cipher_schemes + 2;
 +
 +              /* check if we have WEP40 and WEP104 */
 +              if (have_wep)
 +                      n_suites += 2;
 +
 +              /* check if we have AES_CMAC */
 +              if (have_mfp)
 +                      n_suites++;
 +
 +              suites = kmalloc(sizeof(u32) * n_suites, GFP_KERNEL);
 +              if (!suites)
 +                      return -ENOMEM;
 +
 +              suites[w++] = WLAN_CIPHER_SUITE_CCMP;
 +              suites[w++] = WLAN_CIPHER_SUITE_TKIP;
 +
 +              if (have_wep) {
 +                      suites[w++] = WLAN_CIPHER_SUITE_WEP40;
 +                      suites[w++] = WLAN_CIPHER_SUITE_WEP104;
 +              }
 +
 +              if (have_mfp)
 +                      suites[w++] = WLAN_CIPHER_SUITE_AES_CMAC;
 +
 +              for (r = 0; r < local->hw.n_cipher_schemes; r++)
 +                      suites[w++] = cs[r].cipher;
 +      } else {
 +              /* Driver provides cipher suites, but we need to exclude WEP */
 +              suites = kmemdup(local->hw.wiphy->cipher_suites,
 +                               sizeof(u32) * local->hw.wiphy->n_cipher_suites,
 +                               GFP_KERNEL);
 +              if (!suites)
 +                      return -ENOMEM;
 +
 +              for (r = 0; r < local->hw.wiphy->n_cipher_suites; r++) {
 +                      u32 suite = local->hw.wiphy->cipher_suites[r];
 +
 +                      if (suite == WLAN_CIPHER_SUITE_WEP40 ||
 +                          suite == WLAN_CIPHER_SUITE_WEP104)
 +                              continue;
 +                      suites[w++] = suite;
 +              }
 +      }
 +
 +      local->hw.wiphy->cipher_suites = suites;
 +      local->hw.wiphy->n_cipher_suites = w;
 +      local->wiphy_ciphers_allocated = true;
 +
 +      return 0;
 +}
 +
 +int ieee80211_register_hw(struct ieee80211_hw *hw)
 +{
 +      struct ieee80211_local *local = hw_to_local(hw);
 +      int result, i;
 +      enum ieee80211_band band;
 +      int channels, max_bitrates;
 +      bool supp_ht, supp_vht;
 +      netdev_features_t feature_whitelist;
 +      struct cfg80211_chan_def dflt_chandef = {};
 +
        if (hw->flags & IEEE80211_HW_QUEUE_CONTROL &&
            (local->hw.offchannel_tx_hw_queue == IEEE80211_INVAL_HW_QUEUE ||
             local->hw.offchannel_tx_hw_queue >= local->hw.queues))
        if (local->hw.wiphy->max_scan_ie_len)
                local->hw.wiphy->max_scan_ie_len -= local->scan_ies_len;
  
 -      /* Set up cipher suites unless driver already did */
 -      if (!local->hw.wiphy->cipher_suites) {
 -              local->hw.wiphy->cipher_suites = cipher_suites;
 -              local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
 -              if (!(local->hw.flags & IEEE80211_HW_MFP_CAPABLE))
 -                      local->hw.wiphy->n_cipher_suites--;
 -      }
 -      if (IS_ERR(local->wep_tx_tfm) || IS_ERR(local->wep_rx_tfm)) {
 -              if (local->hw.wiphy->cipher_suites == cipher_suites) {
 -                      local->hw.wiphy->cipher_suites += 2;
 -                      local->hw.wiphy->n_cipher_suites -= 2;
 -              } else {
 -                      u32 *suites;
 -                      int r, w = 0;
 -
 -                      /* Filter out WEP */
 -
 -                      suites = kmemdup(
 -                              local->hw.wiphy->cipher_suites,
 -                              sizeof(u32) * local->hw.wiphy->n_cipher_suites,
 -                              GFP_KERNEL);
 -                      if (!suites) {
 -                              result = -ENOMEM;
 -                              goto fail_wiphy_register;
 -                      }
 -                      for (r = 0; r < local->hw.wiphy->n_cipher_suites; r++) {
 -                              u32 suite = local->hw.wiphy->cipher_suites[r];
 -                              if (suite == WLAN_CIPHER_SUITE_WEP40 ||
 -                                  suite == WLAN_CIPHER_SUITE_WEP104)
 -                                      continue;
 -                              suites[w++] = suite;
 -                      }
 -                      local->hw.wiphy->cipher_suites = suites;
 -                      local->hw.wiphy->n_cipher_suites = w;
 -                      local->wiphy_ciphers_allocated = true;
 -              }
 -      }
 +      WARN_ON(!ieee80211_cs_list_valid(local->hw.cipher_schemes,
 +                                       local->hw.n_cipher_schemes));
 +
 +      result = ieee80211_init_cipher_suites(local);
 +      if (result < 0)
 +              goto fail_wiphy_register;
  
        if (!local->ops->remain_on_channel)
                local->hw.wiphy->max_remain_on_channel_duration = 5000;
                wiphy_debug(local->hw.wiphy, "Failed to initialize wep: %d\n",
                            result);
  
+       local->hw.conf.flags = IEEE80211_CONF_IDLE;
        ieee80211_led_init(local);
  
        rtnl_lock();
@@@ -1102,6 -1049,7 +1104,7 @@@ void ieee80211_unregister_hw(struct iee
  
        cancel_work_sync(&local->restart_work);
        cancel_work_sync(&local->reconfig_filter);
+       flush_work(&local->sched_scan_stopped_work);
  
        ieee80211_clear_tx_pending(local);
        rate_control_deinitialize(local);
@@@ -1142,8 -1090,6 +1145,8 @@@ void ieee80211_free_hw(struct ieee80211
                     ieee80211_free_ack_frame, NULL);
        idr_destroy(&local->ack_status_frames);
  
 +      kfree(rcu_access_pointer(local->tx_latency));
 +
        wiphy_free(local->hw.wiphy);
  }
  EXPORT_SYMBOL(ieee80211_free_hw);
diff --combined net/mac80211/mesh.c
index 330d1f71c0c95380d4adfea250ab0e0bad95c0d8,ba105257d03f1cffc4398f42c52e67b1e8d3eaaa..89df62b2b6896f05a2d3170bce62a40fff23cf8c
@@@ -674,6 -674,8 +674,6 @@@ ieee80211_mesh_build_beacon(struct ieee
        rcu_read_lock();
        csa = rcu_dereference(ifmsh->csa);
        if (csa) {
 -              __le16 pre_value;
 -
                pos = skb_put(skb, 13);
                memset(pos, 0, 13);
                *pos++ = WLAN_EID_CHANNEL_SWITCH;
                          WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT : 0x00;
                put_unaligned_le16(WLAN_REASON_MESH_CHAN, pos);
                pos += 2;
 -              pre_value = cpu_to_le16(ifmsh->pre_value);
 -              memcpy(pos, &pre_value, 2);
 +              put_unaligned_le16(ifmsh->pre_value, pos);
                pos += 2;
        }
        rcu_read_unlock();
@@@ -940,14 -943,19 +940,19 @@@ ieee80211_mesh_process_chnswitch(struc
                 params.chandef.chan->center_freq);
  
        params.block_tx = csa_ie.mode & WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT;
-       if (beacon)
+       if (beacon) {
                ifmsh->chsw_ttl = csa_ie.ttl - 1;
-       else
-               ifmsh->chsw_ttl = 0;
+               if (ifmsh->pre_value >= csa_ie.pre_value)
+                       return false;
+               ifmsh->pre_value = csa_ie.pre_value;
+       }
  
-       if (ifmsh->chsw_ttl > 0)
+       if (ifmsh->chsw_ttl < ifmsh->mshcfg.dot11MeshTTL) {
                if (ieee80211_mesh_csa_beacon(sdata, &params, false) < 0)
                        return false;
+       } else {
+               return false;
+       }
  
        sdata->csa_radar_required = params.radar_required;
  
                                IEEE80211_MAX_QUEUE_MAP,
                                IEEE80211_QUEUE_STOP_REASON_CSA);
  
 -      sdata->local->csa_chandef = params.chandef;
 +      sdata->csa_chandef = params.chandef;
        sdata->vif.csa_active = true;
  
        ieee80211_bss_info_change_notify(sdata, err);
@@@ -1160,7 -1168,6 +1165,6 @@@ static int mesh_fwd_csa_frame(struct ie
        offset_ttl = (len < 42) ? 7 : 10;
        *(pos + offset_ttl) -= 1;
        *(pos + offset_ttl + 1) &= ~WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR;
-       sdata->u.mesh.chsw_ttl = *(pos + offset_ttl);
  
        memcpy(mgmt_fwd, mgmt, len);
        eth_broadcast_addr(mgmt_fwd->da);
@@@ -1179,7 -1186,7 +1183,7 @@@ static void mesh_rx_csa_frame(struct ie
        u16 pre_value;
        bool fwd_csa = true;
        size_t baselen;
-       u8 *pos, ttl;
+       u8 *pos;
  
        if (mgmt->u.action.u.measurement.action_code !=
            WLAN_ACTION_SPCT_CHL_SWITCH)
                           u.action.u.chan_switch.variable);
        ieee802_11_parse_elems(pos, len - baselen, false, &elems);
  
-       ttl = elems.mesh_chansw_params_ie->mesh_ttl;
-       if (!--ttl)
+       ifmsh->chsw_ttl = elems.mesh_chansw_params_ie->mesh_ttl;
+       if (!--ifmsh->chsw_ttl)
                fwd_csa = false;
  
        pre_value = le16_to_cpu(elems.mesh_chansw_params_ie->mesh_pre_value);
diff --combined net/mac80211/mlme.c
index 33bcf8018d8e3873f7719994a990eeed6da65e25,b3a3ce316656ce8406859a3cdc325fa262e024a5..900ead344f5bd526fa5f9a54b438a8cae52012e6
@@@ -330,16 -330,6 +330,16 @@@ static int ieee80211_config_bw(struct i
        if (WARN_ON_ONCE(!sta))
                return -EINVAL;
  
 +      /*
 +       * if bss configuration changed store the new one -
 +       * this may be applicable even if channel is identical
 +       */
 +      ht_opmode = le16_to_cpu(ht_oper->operation_mode);
 +      if (sdata->vif.bss_conf.ht_operation_mode != ht_opmode) {
 +              *changed |= BSS_CHANGED_HT;
 +              sdata->vif.bss_conf.ht_operation_mode = ht_opmode;
 +      }
 +
        chan = sdata->vif.bss_conf.chandef.chan;
        sband = local->hw.wiphy->bands[chan->band];
  
                                         IEEE80211_RC_BW_CHANGED);
        }
  
 -      ht_opmode = le16_to_cpu(ht_oper->operation_mode);
 -
 -      /* if bss configuration changed store the new one */
 -      if (sdata->vif.bss_conf.ht_operation_mode != ht_opmode) {
 -              *changed |= BSS_CHANGED_HT;
 -              sdata->vif.bss_conf.ht_operation_mode = ht_opmode;
 -      }
 -
        return 0;
  }
  
@@@ -716,7 -714,7 +716,7 @@@ static void ieee80211_send_assoc(struc
        }
  
        /* if present, add any custom IEs that go before HT */
 -      if (assoc_data->ie_len && assoc_data->ie) {
 +      if (assoc_data->ie_len) {
                static const u8 before_ht[] = {
                        WLAN_EID_SSID,
                        WLAN_EID_SUPP_RATES,
                                     &assoc_data->ap_vht_cap);
  
        /* if present, add any custom non-vendor IEs that go after HT */
 -      if (assoc_data->ie_len && assoc_data->ie) {
 +      if (assoc_data->ie_len) {
                noffset = ieee80211_ie_split_vendor(assoc_data->ie,
                                                    assoc_data->ie_len,
                                                    offset);
        }
  
        /* add any remaining custom (i.e. vendor specific here) IEs */
 -      if (assoc_data->ie_len && assoc_data->ie) {
 +      if (assoc_data->ie_len) {
                noffset = assoc_data->ie_len;
                pos = skb_put(skb, noffset - offset);
                memcpy(pos, assoc_data->ie + offset, noffset - offset);
@@@ -888,7 -886,8 +888,7 @@@ static void ieee80211_chswitch_work(str
        if (!ifmgd->associated)
                goto out;
  
 -      ret = ieee80211_vif_change_channel(sdata, &local->csa_chandef,
 -                                         &changed);
 +      ret = ieee80211_vif_change_channel(sdata, &changed);
        if (ret) {
                sdata_info(sdata,
                           "vif channel switch failed, disconnecting\n");
        }
  
        if (!local->use_chanctx) {
 -              local->_oper_chandef = local->csa_chandef;
 +              local->_oper_chandef = sdata->csa_chandef;
                /* Call "hw_config" only if doing sw channel switch.
                 * Otherwise update the channel directly
                 */
        }
  
        /* XXX: shouldn't really modify cfg80211-owned data! */
 -      ifmgd->associated->channel = local->csa_chandef.chan;
 +      ifmgd->associated->channel = sdata->csa_chandef.chan;
  
        /* XXX: wait for a beacon first? */
        ieee80211_wake_queues_by_reason(&local->hw,
@@@ -1036,7 -1035,7 +1036,7 @@@ ieee80211_sta_process_chanswitch(struc
        }
        mutex_unlock(&local->chanctx_mtx);
  
 -      local->csa_chandef = csa_ie.chandef;
 +      sdata->csa_chandef = csa_ie.chandef;
  
        if (csa_ie.mode)
                ieee80211_stop_queues_by_reason(&local->hw,
@@@ -1399,12 -1398,10 +1399,12 @@@ void ieee80211_dfs_cac_timer_work(struc
        struct ieee80211_sub_if_data *sdata =
                container_of(delayed_work, struct ieee80211_sub_if_data,
                             dfs_cac_timer_work);
 +      struct cfg80211_chan_def chandef = sdata->vif.bss_conf.chandef;
  
        ieee80211_vif_release_channel(sdata);
 -
 -      cfg80211_cac_event(sdata->dev, NL80211_RADAR_CAC_FINISHED, GFP_KERNEL);
 +      cfg80211_cac_event(sdata->dev, &chandef,
 +                         NL80211_RADAR_CAC_FINISHED,
 +                         GFP_KERNEL);
  }
  
  /* MLME */
@@@ -1748,8 -1745,6 +1748,8 @@@ static void ieee80211_set_disassoc(stru
  
        ifmgd->flags = 0;
        ieee80211_vif_release_channel(sdata);
 +
 +      sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;
  }
  
  void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
@@@ -1915,6 -1910,8 +1915,8 @@@ static void ieee80211_mgd_probe_ap(stru
        if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL)
                already = true;
  
+       ifmgd->flags |= IEEE80211_STA_CONNECTION_POLL;
        mutex_unlock(&sdata->local->mtx);
  
        if (already)
@@@ -4194,8 -4191,6 +4196,8 @@@ int ieee80211_mgd_assoc(struct ieee8021
  
        sdata->control_port_protocol = req->crypto.control_port_ethertype;
        sdata->control_port_no_encrypt = req->crypto.control_port_no_encrypt;
 +      sdata->encrypt_headroom = ieee80211_cs_headroom(local, &req->crypto,
 +                                                      sdata->vif.type);
  
        /* kick off associate process */
  
index b91655a0d8f090867d1bdb9c8d2de2d5a63f5919,4096ff6cc24fe8a5c3505411c5b232e0d800e050..d2ed18d82fe1dd1f55a2f5c13f319920bbb9b887
@@@ -135,7 -135,7 +135,7 @@@ minstrel_ht_update_rates(struct minstre
  static int
  minstrel_ht_get_group_idx(struct ieee80211_tx_rate *rate)
  {
 -      return GROUP_IDX((rate->idx / MCS_GROUP_RATES) + 1,
 +      return GROUP_IDX((rate->idx / 8) + 1,
                         !!(rate->flags & IEEE80211_TX_RC_SHORT_GI),
                         !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH));
  }
@@@ -148,7 -148,7 +148,7 @@@ minstrel_ht_get_stats(struct minstrel_p
  
        if (rate->flags & IEEE80211_TX_RC_MCS) {
                group = minstrel_ht_get_group_idx(rate);
 -              idx = rate->idx % MCS_GROUP_RATES;
 +              idx = rate->idx % 8;
        } else {
                group = MINSTREL_CCK_GROUP;
  
@@@ -226,7 -226,7 +226,7 @@@ minstrel_ht_calc_tp(struct minstrel_ht_
                nsecs = 1000 * mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len);
  
        nsecs += minstrel_mcs_groups[group].duration[rate];
-       tp = 1000000 * ((mr->probability * 1000) / nsecs);
+       tp = 1000000 * ((prob * 1000) / nsecs);
  
        mr->cur_tp = MINSTREL_TRUNC(tp);
  }
@@@ -277,13 -277,15 +277,15 @@@ minstrel_ht_update_stats(struct minstre
                        if (!(mg->supported & BIT(i)))
                                continue;
  
+                       index = MCS_GROUP_RATES * group + i;
                        /* initialize rates selections starting indexes */
                        if (!mg_rates_valid) {
                                mg->max_tp_rate = mg->max_tp_rate2 =
                                        mg->max_prob_rate = i;
                                if (!mi_rates_valid) {
                                        mi->max_tp_rate = mi->max_tp_rate2 =
-                                               mi->max_prob_rate = i;
+                                               mi->max_prob_rate = index;
                                        mi_rates_valid = true;
                                }
                                mg_rates_valid = true;
  
                        mr = &mg->rates[i];
                        mr->retry_updated = false;
-                       index = MCS_GROUP_RATES * group + i;
                        minstrel_calc_rate_ewma(mr);
                        minstrel_ht_calc_tp(mi, group, i);
  
@@@ -636,7 -637,8 +637,7 @@@ minstrel_ht_set_rate(struct minstrel_pr
                idx = mp->cck_rates[index % ARRAY_SIZE(mp->cck_rates)];
                flags = 0;
        } else {
 -              idx = index % MCS_GROUP_RATES +
 -                    (group->streams - 1) * MCS_GROUP_RATES;
 +              idx = index % MCS_GROUP_RATES + (group->streams - 1) * 8;
                flags = IEEE80211_TX_RC_MCS | group->flags;
        }
  
@@@ -700,16 -702,12 +701,16 @@@ minstrel_get_sample_rate(struct minstre
        if (!mi->sample_tries)
                return -1;
  
 -      mg = &mi->groups[mi->sample_group];
 +      sample_group = mi->sample_group;
 +      mg = &mi->groups[sample_group];
        sample_idx = sample_table[mg->column][mg->index];
 +      minstrel_next_sample_idx(mi);
 +
 +      if (!(mg->supported & BIT(sample_idx)))
 +              return -1;
 +
        mr = &mg->rates[sample_idx];
 -      sample_group = mi->sample_group;
        sample_idx += sample_group * MCS_GROUP_RATES;
 -      minstrel_next_sample_idx(mi);
  
        /*
         * Sampling might add some overhead (RTS, no aggregation)
@@@ -820,7 -818,7 +821,7 @@@ minstrel_ht_get_rate(void *priv, struc
        }
  
        rate->idx = sample_idx % MCS_GROUP_RATES +
 -                  (sample_group->streams - 1) * MCS_GROUP_RATES;
 +                  (sample_group->streams - 1) * 8;
        rate->flags = IEEE80211_TX_RC_MCS | sample_group->flags;
  }
  
@@@ -1055,9 -1053,10 +1056,9 @@@ init_sample_table(void
  
        memset(sample_table, 0xff, sizeof(sample_table));
        for (col = 0; col < SAMPLE_COLUMNS; col++) {
 +              prandom_bytes(rnd, sizeof(rnd));
                for (i = 0; i < MCS_GROUP_RATES; i++) {
 -                      get_random_bytes(rnd, sizeof(rnd));
                        new_idx = (i + rnd[i]) % MCS_GROUP_RATES;
 -
                        while (sample_table[col][new_idx] != 0xff)
                                new_idx = (new_idx + 1) % MCS_GROUP_RATES;
  
diff --combined net/mac80211/rx.c
index 30ac6099da06da2e5a0d409e707e0986d224a3b7,2b0debb0422b91d89a0a7982b94726f3b9ceae11..2dfa755227339533d2c105313ba8ab4ea3ba67b5
@@@ -638,27 -638,6 +638,27 @@@ static int ieee80211_get_mmie_keyidx(st
        return le16_to_cpu(mmie->key_id);
  }
  
 +static int iwl80211_get_cs_keyid(const struct ieee80211_cipher_scheme *cs,
 +                               struct sk_buff *skb)
 +{
 +      struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 +      __le16 fc;
 +      int hdrlen;
 +      u8 keyid;
 +
 +      fc = hdr->frame_control;
 +      hdrlen = ieee80211_hdrlen(fc);
 +
 +      if (skb->len < hdrlen + cs->hdr_len)
 +              return -EINVAL;
 +
 +      skb_copy_bits(skb, hdrlen + cs->key_idx_off, &keyid, 1);
 +      keyid &= cs->key_idx_mask;
 +      keyid >>= cs->key_idx_shift;
 +
 +      return keyid;
 +}
 +
  static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
  {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
@@@ -750,7 -729,9 +750,7 @@@ static void ieee80211_release_reorder_f
        lockdep_assert_held(&tid_agg_rx->reorder_lock);
  
        while (ieee80211_sn_less(tid_agg_rx->head_seq_num, head_seq_num)) {
 -              index = ieee80211_sn_sub(tid_agg_rx->head_seq_num,
 -                                       tid_agg_rx->ssn) %
 -                                                      tid_agg_rx->buf_size;
 +              index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;
                ieee80211_release_reorder_frame(sdata, tid_agg_rx, index,
                                                frames);
        }
@@@ -776,7 -757,8 +776,7 @@@ static void ieee80211_sta_reorder_relea
        lockdep_assert_held(&tid_agg_rx->reorder_lock);
  
        /* release the buffer until next missing frame */
 -      index = ieee80211_sn_sub(tid_agg_rx->head_seq_num,
 -                               tid_agg_rx->ssn) % tid_agg_rx->buf_size;
 +      index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;
        if (!tid_agg_rx->reorder_buf[index] &&
            tid_agg_rx->stored_mpdu_num) {
                /*
        } else while (tid_agg_rx->reorder_buf[index]) {
                ieee80211_release_reorder_frame(sdata, tid_agg_rx, index,
                                                frames);
 -              index = ieee80211_sn_sub(tid_agg_rx->head_seq_num,
 -                                       tid_agg_rx->ssn) %
 -                                                      tid_agg_rx->buf_size;
 +              index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;
        }
  
        if (tid_agg_rx->stored_mpdu_num) {
 -              j = index = ieee80211_sn_sub(tid_agg_rx->head_seq_num,
 -                                           tid_agg_rx->ssn) %
 -                                                      tid_agg_rx->buf_size;
 +              j = index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;
  
                for (; j != (index - 1) % tid_agg_rx->buf_size;
                     j = (j + 1) % tid_agg_rx->buf_size) {
@@@ -875,7 -861,8 +875,7 @@@ static bool ieee80211_sta_manage_reorde
  
        /* Now the new frame is always in the range of the reordering buffer */
  
 -      index = ieee80211_sn_sub(mpdu_seq_num,
 -                               tid_agg_rx->ssn) % tid_agg_rx->buf_size;
 +      index = mpdu_seq_num % tid_agg_rx->buf_size;
  
        /* check if we already stored this frame */
        if (tid_agg_rx->reorder_buf[index]) {
@@@ -924,7 -911,8 +924,8 @@@ static void ieee80211_rx_reorder_ampdu(
        u16 sc;
        u8 tid, ack_policy;
  
-       if (!ieee80211_is_data_qos(hdr->frame_control))
+       if (!ieee80211_is_data_qos(hdr->frame_control) ||
+           is_multicast_ether_addr(hdr->addr1))
                goto dont_reorder;
  
        /*
@@@ -1381,7 -1369,6 +1382,7 @@@ ieee80211_rx_h_decrypt(struct ieee80211
        struct ieee80211_key *sta_ptk = NULL;
        int mmie_keyidx = -1;
        __le16 fc;
 +      const struct ieee80211_cipher_scheme *cs = NULL;
  
        /*
         * Key selection 101
  
        /* start without a key */
        rx->key = NULL;
 +      fc = hdr->frame_control;
  
 -      if (rx->sta)
 -              sta_ptk = rcu_dereference(rx->sta->ptk);
 +      if (rx->sta) {
 +              int keyid = rx->sta->ptk_idx;
  
 -      fc = hdr->frame_control;
 +              if (ieee80211_has_protected(fc) && rx->sta->cipher_scheme) {
 +                      cs = rx->sta->cipher_scheme;
 +                      keyid = iwl80211_get_cs_keyid(cs, rx->skb);
 +                      if (unlikely(keyid < 0))
 +                              return RX_DROP_UNUSABLE;
 +              }
 +              sta_ptk = rcu_dereference(rx->sta->ptk[keyid]);
 +      }
  
        if (!ieee80211_has_protected(fc))
                mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb);
                return RX_CONTINUE;
        } else {
                u8 keyid;
 +
                /*
                 * The device doesn't give us the IV so we won't be
                 * able to look up the key. That's ok though, we
  
                hdrlen = ieee80211_hdrlen(fc);
  
 -              if (rx->skb->len < 8 + hdrlen)
 -                      return RX_DROP_UNUSABLE; /* TODO: count this? */
 +              if (cs) {
 +                      keyidx = iwl80211_get_cs_keyid(cs, rx->skb);
  
 -              /*
 -               * no need to call ieee80211_wep_get_keyidx,
 -               * it verifies a bunch of things we've done already
 -               */
 -              skb_copy_bits(rx->skb, hdrlen + 3, &keyid, 1);
 -              keyidx = keyid >> 6;
 +                      if (unlikely(keyidx < 0))
 +                              return RX_DROP_UNUSABLE;
 +              } else {
 +                      if (rx->skb->len < 8 + hdrlen)
 +                              return RX_DROP_UNUSABLE; /* TODO: count this? */
 +                      /*
 +                       * no need to call ieee80211_wep_get_keyidx,
 +                       * it verifies a bunch of things we've done already
 +                       */
 +                      skb_copy_bits(rx->skb, hdrlen + 3, &keyid, 1);
 +                      keyidx = keyid >> 6;
 +              }
  
                /* check per-station GTK first, if multicast packet */
                if (is_multicast_ether_addr(hdr->addr1) && rx->sta)
                result = ieee80211_crypto_aes_cmac_decrypt(rx);
                break;
        default:
 -              /*
 -               * We can reach here only with HW-only algorithms
 -               * but why didn't it decrypt the frame?!
 -               */
 -              return RX_DROP_UNUSABLE;
 +              result = ieee80211_crypto_hw_decrypt(rx);
        }
  
        /* the hdr variable is invalid after the decrypt handlers */
@@@ -2081,6 -2057,7 +2082,6 @@@ ieee80211_rx_h_mesh_fwding(struct ieee8
        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;
        } else {
                /* unable to resolve next hop */
                mesh_path_error_tx(sdata, ifmsh->mshcfg.element_ttl,
 -                                 fwd_hdr->addr3, 0, reason, fwd_hdr->addr2);
 +                                 fwd_hdr->addr3, 0,
 +                                 WLAN_REASON_MESH_PATH_NOFORWARD,
 +                                 fwd_hdr->addr2);
                IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route);
                kfree_skb(fwd_skb);
                return RX_DROP_MONITOR;
diff --combined net/mac80211/scan.c
index c22cbb57b49dd30196899c32902d3876803fbe09,bcc4833d7542b91e1b754ed490d1dedcaee559c1..4d73c46df86262a385ad5fb9a5912c6a8168831e
@@@ -526,7 -526,7 +526,7 @@@ static int __ieee80211_start_scan(struc
                ieee80211_hw_config(local, 0);
  
                if ((req->channels[0]->flags &
 -                   IEEE80211_CHAN_PASSIVE_SCAN) ||
 +                   IEEE80211_CHAN_NO_IR) ||
                    !local->scan_req->n_ssids) {
                        next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
                } else {
@@@ -572,7 -572,7 +572,7 @@@ ieee80211_scan_get_channel_time(struct 
         * TODO: channel switching also consumes quite some time,
         * add that delay as well to get a better estimation
         */
 -      if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)
 +      if (chan->flags & IEEE80211_CHAN_NO_IR)
                return IEEE80211_PASSIVE_CHANNEL_TIME;
        return IEEE80211_PROBE_DELAY + IEEE80211_CHANNEL_TIME;
  }
@@@ -696,7 -696,7 +696,7 @@@ static void ieee80211_scan_state_set_ch
         *
         * In any case, it is not necessary for a passive scan.
         */
 -      if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN ||
 +      if (chan->flags & IEEE80211_CHAN_NO_IR ||
            !local->scan_req->n_ssids) {
                *next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
                local->next_scan_state = SCAN_DECISION;
@@@ -881,7 -881,7 +881,7 @@@ int ieee80211_request_ibss_scan(struct 
                                struct ieee80211_channel *tmp_ch =
                                    &local->hw.wiphy->bands[band]->channels[i];
  
 -                              if (tmp_ch->flags & (IEEE80211_CHAN_NO_IBSS |
 +                              if (tmp_ch->flags & (IEEE80211_CHAN_NO_IR |
                                                     IEEE80211_CHAN_DISABLED))
                                        continue;
  
  
                local->int_scan_req->n_channels = n_ch;
        } else {
 -              if (WARN_ON_ONCE(chan->flags & (IEEE80211_CHAN_NO_IBSS |
 +              if (WARN_ON_ONCE(chan->flags & (IEEE80211_CHAN_NO_IR |
                                                IEEE80211_CHAN_DISABLED)))
                        goto unlock;
  
@@@ -1088,6 -1088,6 +1088,6 @@@ void ieee80211_sched_scan_stopped(struc
  
        trace_api_sched_scan_stopped(local);
  
-       ieee80211_queue_work(&local->hw, &local->sched_scan_stopped_work);
+       schedule_work(&local->sched_scan_stopped_work);
  }
  EXPORT_SYMBOL(ieee80211_sched_scan_stopped);
diff --combined net/mac80211/util.c
index 06265d7f8cc375d47e804623503af3540ec3eb38,9f9b9bd3fd44798e7030fb3a44c46da962cfd7ba..875e172c001c697a72f85941fd0db8ef1b28b86a
@@@ -1804,26 -1804,6 +1804,26 @@@ void ieee80211_recalc_smps(struct ieee8
        mutex_unlock(&local->chanctx_mtx);
  }
  
 +void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata)
 +{
 +      struct ieee80211_local *local = sdata->local;
 +      struct ieee80211_chanctx_conf *chanctx_conf;
 +      struct ieee80211_chanctx *chanctx;
 +
 +      mutex_lock(&local->chanctx_mtx);
 +
 +      chanctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
 +                                      lockdep_is_held(&local->chanctx_mtx));
 +
 +      if (WARN_ON_ONCE(!chanctx_conf))
 +              goto unlock;
 +
 +      chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
 +      ieee80211_recalc_chanctx_min_def(local, chanctx);
 + unlock:
 +      mutex_unlock(&local->chanctx_mtx);
 +}
 +
  static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id)
  {
        int i;
@@@ -2279,17 -2259,14 +2279,17 @@@ u64 ieee80211_calculate_rx_timestamp(st
  void ieee80211_dfs_cac_cancel(struct ieee80211_local *local)
  {
        struct ieee80211_sub_if_data *sdata;
 +      struct cfg80211_chan_def chandef;
  
        mutex_lock(&local->iflist_mtx);
        list_for_each_entry(sdata, &local->interfaces, list) {
                cancel_delayed_work_sync(&sdata->dfs_cac_timer_work);
  
                if (sdata->wdev.cac_started) {
 +                      chandef = sdata->vif.bss_conf.chandef;
                        ieee80211_vif_release_channel(sdata);
                        cfg80211_cac_event(sdata->dev,
 +                                         &chandef,
                                           NL80211_RADAR_CAC_ABORTED,
                                           GFP_KERNEL);
                }
@@@ -2301,17 -2278,15 +2301,15 @@@ void ieee80211_dfs_radar_detected_work(
  {
        struct ieee80211_local *local =
                container_of(work, struct ieee80211_local, radar_detected_work);
-       struct cfg80211_chan_def chandef;
+       struct cfg80211_chan_def chandef = local->hw.conf.chandef;
  
        ieee80211_dfs_cac_cancel(local);
  
        if (local->use_chanctx)
                /* currently not handled */
                WARN_ON(1);
-       else {
-               chandef = local->hw.conf.chandef;
+       else
                cfg80211_radar_event(local->hw.wiphy, &chandef, GFP_KERNEL);
-       }
  }
  
  void ieee80211_radar_detected(struct ieee80211_hw *hw)
@@@ -2470,6 -2445,7 +2468,6 @@@ int ieee80211_send_action_csa(struct ie
  
        if (ieee80211_vif_is_mesh(&sdata->vif)) {
                struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
 -              __le16 pre_value;
  
                skb_put(skb, 8);
                *pos++ = WLAN_EID_CHAN_SWITCH_PARAM;            /* EID */
                          WLAN_EID_CHAN_SWITCH_PARAM_TX_RESTRICT : 0x00;
                put_unaligned_le16(WLAN_REASON_MESH_CHAN, pos); /* Reason Cd */
                pos += 2;
-               if (!ifmsh->pre_value)
-                       ifmsh->pre_value = 1;
-               else
-                       ifmsh->pre_value++;
 -              pre_value = cpu_to_le16(ifmsh->pre_value);
 -              memcpy(pos, &pre_value, 2);             /* Precedence Value */
 +              put_unaligned_le16(ifmsh->pre_value, pos);/* Precedence Value */
                pos += 2;
-               ifmsh->chsw_init = true;
        }
  
        ieee80211_tx_skb(sdata, skb);
        return 0;
  }
 +
 +bool ieee80211_cs_valid(const struct ieee80211_cipher_scheme *cs)
 +{
 +      return !(cs == NULL || cs->cipher == 0 ||
 +               cs->hdr_len < cs->pn_len + cs->pn_off ||
 +               cs->hdr_len <= cs->key_idx_off ||
 +               cs->key_idx_shift > 7 ||
 +               cs->key_idx_mask == 0);
 +}
 +
 +bool ieee80211_cs_list_valid(const struct ieee80211_cipher_scheme *cs, int n)
 +{
 +      int i;
 +
 +      /* Ensure we have enough iftype bitmap space for all iftype values */
 +      WARN_ON((NUM_NL80211_IFTYPES / 8 + 1) > sizeof(cs[0].iftype));
 +
 +      for (i = 0; i < n; i++)
 +              if (!ieee80211_cs_valid(&cs[i]))
 +                      return false;
 +
 +      return true;
 +}
 +
 +const struct ieee80211_cipher_scheme *
 +ieee80211_cs_get(struct ieee80211_local *local, u32 cipher,
 +               enum nl80211_iftype iftype)
 +{
 +      const struct ieee80211_cipher_scheme *l = local->hw.cipher_schemes;
 +      int n = local->hw.n_cipher_schemes;
 +      int i;
 +      const struct ieee80211_cipher_scheme *cs = NULL;
 +
 +      for (i = 0; i < n; i++) {
 +              if (l[i].cipher == cipher) {
 +                      cs = &l[i];
 +                      break;
 +              }
 +      }
 +
 +      if (!cs || !(cs->iftype & BIT(iftype)))
 +              return NULL;
 +
 +      return cs;
 +}
 +
 +int ieee80211_cs_headroom(struct ieee80211_local *local,
 +                        struct cfg80211_crypto_settings *crypto,
 +                        enum nl80211_iftype iftype)
 +{
 +      const struct ieee80211_cipher_scheme *cs;
 +      int headroom = IEEE80211_ENCRYPT_HEADROOM;
 +      int i;
 +
 +      for (i = 0; i < crypto->n_ciphers_pairwise; i++) {
 +              cs = ieee80211_cs_get(local, crypto->ciphers_pairwise[i],
 +                                    iftype);
 +
 +              if (cs && headroom < cs->hdr_len)
 +                      headroom = cs->hdr_len;
 +      }
 +
 +      cs = ieee80211_cs_get(local, crypto->cipher_group, iftype);
 +      if (cs && headroom < cs->hdr_len)
 +              headroom = cs->hdr_len;
 +
 +      return headroom;
 +}
diff --combined net/wireless/core.c
index fc968c861ee46830ef9d33601e5f6cd3d597573c,52b865fb7351ac3c221c120bc0cc236687a12513..06db6eb5258aefc332fb4fb09ed165562ea8cd7d
@@@ -357,6 -357,8 +357,6 @@@ struct wiphy *wiphy_new(const struct cf
        rdev->wiphy.rts_threshold = (u32) -1;
        rdev->wiphy.coverage_class = 0;
  
 -      rdev->wiphy.features = NL80211_FEATURE_SCAN_FLUSH;
 -
        return &rdev->wiphy;
  }
  EXPORT_SYMBOL(wiphy_new);
@@@ -449,6 -451,15 +449,15 @@@ int wiphy_register(struct wiphy *wiphy
        int i;
        u16 ifmodes = wiphy->interface_modes;
  
+       /* support for 5/10 MHz is broken due to nl80211 API mess - disable */
+       wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_5_10_MHZ;
+       /*
+        * There are major locking problems in nl80211/mac80211 for CSA,
+        * disable for all drivers until this has been reworked.
+        */
+       wiphy->flags &= ~WIPHY_FLAG_HAS_CHANNEL_SWITCH;
  #ifdef CONFIG_PM
        if (WARN_ON(wiphy->wowlan &&
                    (wiphy->wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) &&
        /* check and set up bitrates */
        ieee80211_set_bitrate_flags(wiphy);
  
 +      rdev->wiphy.features |= NL80211_FEATURE_SCAN_FLUSH;
 +
        rtnl_lock();
        res = device_add(&rdev->wiphy.dev);
        if (res) {
        if (IS_ERR(rdev->wiphy.debugfsdir))
                rdev->wiphy.debugfsdir = NULL;
  
 -      if (wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) {
 +      if (wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) {
                struct regulatory_request request;
  
                request.wiphy_idx = get_wiphy_idx(wiphy);
diff --combined net/wireless/ibss.c
index f79105712949528377199a86e45978237c104729,89737ee2669a8de9bc8f02aa1c392052369d210b..730147ed8e652c625cb035309df687ca08fd5b49
@@@ -262,7 -262,7 +262,7 @@@ int cfg80211_ibss_wext_join(struct cfg8
  
        /* try to find an IBSS channel if none requested ... */
        if (!wdev->wext.ibss.chandef.chan) {
-               wdev->wext.ibss.chandef.width = NL80211_CHAN_WIDTH_20_NOHT;
+               struct ieee80211_channel *new_chan = NULL;
  
                for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
                        struct ieee80211_supported_band *sband;
  
                        for (i = 0; i < sband->n_channels; i++) {
                                chan = &sband->channels[i];
 -                              if (chan->flags & IEEE80211_CHAN_NO_IBSS)
 +                              if (chan->flags & IEEE80211_CHAN_NO_IR)
                                        continue;
                                if (chan->flags & IEEE80211_CHAN_DISABLED)
                                        continue;
-                               wdev->wext.ibss.chandef.chan = chan;
-                               wdev->wext.ibss.chandef.center_freq1 =
-                                       chan->center_freq;
+                               new_chan = chan;
                                break;
                        }
  
-                       if (wdev->wext.ibss.chandef.chan)
+                       if (new_chan)
                                break;
                }
  
-               if (!wdev->wext.ibss.chandef.chan)
+               if (!new_chan)
                        return -EINVAL;
+               cfg80211_chandef_create(&wdev->wext.ibss.chandef, new_chan,
+                                       NL80211_CHAN_NO_HT);
        }
  
        /* don't join -- SSID is not there */
@@@ -345,7 -346,7 +346,7 @@@ int cfg80211_ibss_wext_siwfreq(struct n
                chan = ieee80211_get_channel(wdev->wiphy, freq);
                if (!chan)
                        return -EINVAL;
 -              if (chan->flags & IEEE80211_CHAN_NO_IBSS ||
 +              if (chan->flags & IEEE80211_CHAN_NO_IR ||
                    chan->flags & IEEE80211_CHAN_DISABLED)
                        return -EINVAL;
        }
                return err;
  
        if (chan) {
-               wdev->wext.ibss.chandef.chan = chan;
-               wdev->wext.ibss.chandef.width = NL80211_CHAN_WIDTH_20_NOHT;
-               wdev->wext.ibss.chandef.center_freq1 = freq;
+               cfg80211_chandef_create(&wdev->wext.ibss.chandef, chan,
+                                       NL80211_CHAN_NO_HT);
                wdev->wext.ibss.channel_fixed = true;
        } else {
                /* cfg80211_ibss_wext_join will pick one if needed */
diff --combined net/wireless/nl80211.c
index efaa23e562b4501045d314bcda149ece0e352a07,138dc3bb8b67d8c345531a95ce0c8342271ce79e..a693f86e59704016e9c8419eb82a8c43185d9642
@@@ -564,12 -564,12 +564,12 @@@ static int nl80211_msg_put_channel(stru
        if ((chan->flags & IEEE80211_CHAN_DISABLED) &&
            nla_put_flag(msg, NL80211_FREQUENCY_ATTR_DISABLED))
                goto nla_put_failure;
 -      if ((chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) &&
 -          nla_put_flag(msg, NL80211_FREQUENCY_ATTR_PASSIVE_SCAN))
 -              goto nla_put_failure;
 -      if ((chan->flags & IEEE80211_CHAN_NO_IBSS) &&
 -          nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IBSS))
 -              goto nla_put_failure;
 +      if (chan->flags & IEEE80211_CHAN_NO_IR) {
 +              if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IR))
 +                      goto nla_put_failure;
 +              if (nla_put_flag(msg, __NL80211_FREQUENCY_ATTR_NO_IBSS))
 +                      goto nla_put_failure;
 +      }
        if (chan->flags & IEEE80211_CHAN_RADAR) {
                if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR))
                        goto nla_put_failure;
@@@ -1247,6 -1247,10 +1247,6 @@@ static int nl80211_send_wiphy(struct cf
                if ((dev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) &&
                    nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP))
                        goto nla_put_failure;
 -              if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ) &&
 -                  nla_put_flag(msg, WIPHY_FLAG_SUPPORTS_5_10_MHZ))
 -                      goto nla_put_failure;
 -
                state->split_start++;
                if (state->split)
                        break;
                if (nl80211_send_coalesce(msg, dev))
                        goto nla_put_failure;
  
 +              if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ) &&
 +                  (nla_put_flag(msg, NL80211_ATTR_SUPPORT_5_MHZ) ||
 +                   nla_put_flag(msg, NL80211_ATTR_SUPPORT_10_MHZ)))
 +                      goto nla_put_failure;
 +
                /* done */
                state->split_start = 0;
                break;
@@@ -2188,7 -2187,7 +2188,7 @@@ static inline u64 wdev_id(struct wirele
  }
  
  static int nl80211_send_chandef(struct sk_buff *msg,
 -                               struct cfg80211_chan_def *chandef)
 +                              const struct cfg80211_chan_def *chandef)
  {
        WARN_ON(!cfg80211_chandef_valid(chandef));
  
@@@ -2688,7 -2687,7 +2688,7 @@@ static int nl80211_get_key(struct sk_bu
        hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
                             NL80211_CMD_NEW_KEY);
        if (!hdr)
-               return -ENOBUFS;
+               goto nla_put_failure;
  
        cookie.msg = msg;
        cookie.idx = key_idx;
@@@ -3237,7 -3236,6 +3237,7 @@@ static int nl80211_start_ap(struct sk_b
                        return PTR_ERR(params.acl);
        }
  
 +      wdev_lock(wdev);
        err = rdev_start_ap(rdev, dev, &params);
        if (!err) {
                wdev->preset_chandef = params.chandef;
                wdev->ssid_len = params.ssid_len;
                memcpy(wdev->ssid, params.ssid, wdev->ssid_len);
        }
 +      wdev_unlock(wdev);
  
        kfree(params.acl);
  
@@@ -3275,11 -3272,7 +3275,11 @@@ static int nl80211_set_beacon(struct sk
        if (err)
                return err;
  
 -      return rdev_change_beacon(rdev, dev, &params);
 +      wdev_lock(wdev);
 +      err = rdev_change_beacon(rdev, dev, &params);
 +      wdev_unlock(wdev);
 +
 +      return err;
  }
  
  static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info)
@@@ -4485,9 -4478,7 +4485,9 @@@ static int nl80211_set_bss(struct sk_bu
  {
        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 bss_parameters params;
 +      int err;
  
        memset(&params, 0, sizeof(params));
        /* default to not changing parameters */
            dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
                return -EOPNOTSUPP;
  
 -      return rdev_change_bss(rdev, dev, &params);
 +      wdev_lock(wdev);
 +      err = rdev_change_bss(rdev, dev, &params);
 +      wdev_unlock(wdev);
 +
 +      return err;
  }
  
  static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = {
@@@ -5111,7 -5098,7 +5111,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;
 +      enum nl80211_dfs_regions dfs_region = NL80211_DFS_UNSET;
        struct ieee80211_regdomain *rd = NULL;
  
        if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
                        return -EINVAL;
        }
  
 +      if (!reg_is_valid_request(alpha2))
 +              return -EINVAL;
 +
        size_of_regd = sizeof(struct ieee80211_regdomain) +
                       num_rules * sizeof(struct ieee80211_reg_rule);
  
@@@ -5365,6 -5349,10 +5365,10 @@@ static int nl80211_trigger_scan(struct 
                                err = -EINVAL;
                                goto out_free;
                        }
+                       if (!wiphy->bands[band])
+                               continue;
                        err = ieee80211_get_ratemask(wiphy->bands[band],
                                                     nla_data(attr),
                                                     nla_len(attr),
        if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) {
                request->flags = nla_get_u32(
                        info->attrs[NL80211_ATTR_SCAN_FLAGS]);
 -              if (((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
 -                   !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) ||
 -                  ((request->flags & NL80211_SCAN_FLAG_FLUSH) &&
 -                   !(wiphy->features & NL80211_FEATURE_SCAN_FLUSH))) {
 +              if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
 +                  !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) {
                        err = -EOPNOTSUPP;
                        goto out_free;
                }
@@@ -5618,8 -5608,10 +5622,8 @@@ static int nl80211_start_sched_scan(str
        if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) {
                request->flags = nla_get_u32(
                        info->attrs[NL80211_ATTR_SCAN_FLAGS]);
 -              if (((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
 -                   !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) ||
 -                  ((request->flags & NL80211_SCAN_FLAG_FLUSH) &&
 -                   !(wiphy->features & NL80211_FEATURE_SCAN_FLUSH))) {
 +              if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
 +                  !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) {
                        err = -EOPNOTSUPP;
                        goto out_free;
                }
@@@ -5682,7 -5674,7 +5686,7 @@@ static int nl80211_start_radar_detectio
        if (err == 0)
                return -EINVAL;
  
 -      if (chandef.chan->dfs_state != NL80211_DFS_USABLE)
 +      if (!cfg80211_chandef_dfs_usable(wdev->wiphy, &chandef))
                return -EINVAL;
  
        if (!rdev->ops->start_radar_detection)
@@@ -5822,11 -5814,7 +5826,11 @@@ skip_beacons
        if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX])
                params.block_tx = true;
  
 -      return rdev_channel_switch(rdev, dev, &params);
 +      wdev_lock(wdev);
 +      err = rdev_channel_switch(rdev, dev, &params);
 +      wdev_unlock(wdev);
 +
 +      return err;
  }
  
  static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
@@@ -7459,10 -7447,10 +7463,10 @@@ static int nl80211_tx_mgmt(struct sk_bu
        void *hdr = NULL;
        u64 cookie;
        struct sk_buff *msg = NULL;
 -      unsigned int wait = 0;
 -      bool offchan, no_cck, dont_wait_for_ack;
 -
 -      dont_wait_for_ack = info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK];
 +      struct cfg80211_mgmt_tx_params params = {
 +              .dont_wait_for_ack =
 +                      info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK],
 +      };
  
        if (!info->attrs[NL80211_ATTR_FRAME])
                return -EINVAL;
        if (info->attrs[NL80211_ATTR_DURATION]) {
                if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
                        return -EINVAL;
 -              wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
 +              params.wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
  
                /*
                 * We should wait on the channel for at least a minimum amount
                 * of time (10ms) but no longer than the driver supports.
                 */
 -              if (wait < NL80211_MIN_REMAIN_ON_CHANNEL_TIME ||
 -                  wait > rdev->wiphy.max_remain_on_channel_duration)
 +              if (params.wait < NL80211_MIN_REMAIN_ON_CHANNEL_TIME ||
 +                  params.wait > rdev->wiphy.max_remain_on_channel_duration)
                        return -EINVAL;
  
        }
  
 -      offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK];
 +      params.offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK];
  
 -      if (offchan && !(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
 +      if (params.offchan && !(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
                return -EINVAL;
  
 -      no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
 +      params.no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
  
        /* get the channel if any has been specified, otherwise pass NULL to
         * the driver. The latter will use the current one
                        return err;
        }
  
 -      if (!chandef.chan && offchan)
 +      if (!chandef.chan && params.offchan)
                return -EINVAL;
  
 -      if (!dont_wait_for_ack) {
 +      if (!params.dont_wait_for_ack) {
                msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
                if (!msg)
                        return -ENOMEM;
                }
        }
  
 -      err = cfg80211_mlme_mgmt_tx(rdev, wdev, chandef.chan, offchan, wait,
 -                                  nla_data(info->attrs[NL80211_ATTR_FRAME]),
 -                                  nla_len(info->attrs[NL80211_ATTR_FRAME]),
 -                                  no_cck, dont_wait_for_ack, &cookie);
 +      params.buf = nla_data(info->attrs[NL80211_ATTR_FRAME]);
 +      params.len = nla_len(info->attrs[NL80211_ATTR_FRAME]);
 +      params.chan = chandef.chan;
 +      err = cfg80211_mlme_mgmt_tx(rdev, wdev, &params, &cookie);
        if (err)
                goto free_msg;
  
@@@ -9649,8 -9637,9 +9653,9 @@@ static int nl80211_add_scan_req(struct 
            nla_put(msg, NL80211_ATTR_IE, req->ie_len, req->ie))
                goto nla_put_failure;
  
-       if (req->flags)
-               nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, req->flags);
+       if (req->flags &&
+           nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, req->flags))
+               goto nla_put_failure;
  
        return 0;
   nla_put_failure:
@@@ -10821,18 -10810,21 +10826,18 @@@ void cfg80211_ch_switch_notify(struct n
        struct wiphy *wiphy = wdev->wiphy;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
  
 -      trace_cfg80211_ch_switch_notify(dev, chandef);
 +      ASSERT_WDEV_LOCK(wdev);
  
 -      wdev_lock(wdev);
 +      trace_cfg80211_ch_switch_notify(dev, chandef);
  
        if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
                    wdev->iftype != NL80211_IFTYPE_P2P_GO &&
                    wdev->iftype != NL80211_IFTYPE_ADHOC &&
                    wdev->iftype != NL80211_IFTYPE_MESH_POINT))
 -              goto out;
 +              return;
  
        wdev->channel = chandef->chan;
        nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL);
 -out:
 -      wdev_unlock(wdev);
 -      return;
  }
  EXPORT_SYMBOL(cfg80211_ch_switch_notify);
  
@@@ -10891,7 -10883,7 +10896,7 @@@ EXPORT_SYMBOL(cfg80211_cqm_txe_notify)
  
  void
  nl80211_radar_notify(struct cfg80211_registered_device *rdev,
 -                   struct cfg80211_chan_def *chandef,
 +                   const struct cfg80211_chan_def *chandef,
                     enum nl80211_radar_event event,
                     struct net_device *netdev, gfp_t gfp)
  {
@@@ -11106,6 -11098,8 +11111,8 @@@ void cfg80211_report_wowlan_wakeup(stru
                struct nlattr *reasons;
  
                reasons = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS);
+               if (!reasons)
+                       goto free_msg;
  
                if (wakeup->disconnect &&
                    nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT))
                                wakeup->pattern_idx))
                        goto free_msg;
  
-               if (wakeup->tcp_match)
-                       nla_put_flag(msg, NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH);
+               if (wakeup->tcp_match &&
+                   nla_put_flag(msg, NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH))
+                       goto free_msg;
  
-               if (wakeup->tcp_connlost)
-                       nla_put_flag(msg,
-                                    NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST);
+               if (wakeup->tcp_connlost &&
+                   nla_put_flag(msg, NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST))
+                       goto free_msg;
  
-               if (wakeup->tcp_nomoretokens)
-                       nla_put_flag(msg,
-                               NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS);
+               if (wakeup->tcp_nomoretokens &&
+                   nla_put_flag(msg,
+                                NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS))
+                       goto free_msg;
  
                if (wakeup->packet) {
                        u32 pkt_attr = NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211;
@@@ -11276,24 -11272,29 +11285,29 @@@ void cfg80211_ft_event(struct net_devic
                return;
  
        hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FT_EVENT);
-       if (!hdr) {
-               nlmsg_free(msg);
-               return;
-       }
+       if (!hdr)
+               goto out;
  
-       nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
-       nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
-       nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, ft_event->target_ap);
-       if (ft_event->ies)
-               nla_put(msg, NL80211_ATTR_IE, ft_event->ies_len, ft_event->ies);
-       if (ft_event->ric_ies)
-               nla_put(msg, NL80211_ATTR_IE_RIC, ft_event->ric_ies_len,
-                       ft_event->ric_ies);
+       if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
+           nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
+           nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, ft_event->target_ap))
+               goto out;
+       if (ft_event->ies &&
+           nla_put(msg, NL80211_ATTR_IE, ft_event->ies_len, ft_event->ies))
+               goto out;
+       if (ft_event->ric_ies &&
+           nla_put(msg, NL80211_ATTR_IE_RIC, ft_event->ric_ies_len,
+                   ft_event->ric_ies))
+               goto out;
  
        genlmsg_end(msg, hdr);
  
        genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
                                NL80211_MCGRP_MLME, GFP_KERNEL);
+       return;
+  out:
+       nlmsg_free(msg);
  }
  EXPORT_SYMBOL(cfg80211_ft_event);
  
This page took 0.097417 seconds and 5 git commands to generate.