Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac802...
authorJohn W. Linville <linville@tuxdriver.com>
Mon, 2 Dec 2013 19:25:38 +0000 (14:25 -0500)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 2 Dec 2013 19:25:38 +0000 (14:25 -0500)
81 files changed:
Documentation/networking/regulatory.txt
drivers/net/wireless/ath/ath10k/mac.c
drivers/net/wireless/ath/ath6kl/cfg80211.c
drivers/net/wireless/ath/regd.c
drivers/net/wireless/brcm80211/brcmfmac/p2p.c
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
drivers/net/wireless/brcm80211/brcmsmac/channel.c
drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
drivers/net/wireless/cw1200/scan.c
drivers/net/wireless/ipw2x00/ipw2100.c
drivers/net/wireless/ipw2x00/ipw2200.c
drivers/net/wireless/iwlegacy/3945-mac.c
drivers/net/wireless/iwlegacy/4965-mac.c
drivers/net/wireless/iwlegacy/common.c
drivers/net/wireless/iwlegacy/debug.c
drivers/net/wireless/iwlwifi/dvm/debugfs.c
drivers/net/wireless/iwlwifi/dvm/mac80211.c
drivers/net/wireless/iwlwifi/dvm/scan.c
drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c
drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/scan.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/mwifiex/scan.c
drivers/net/wireless/rtlwifi/regd.c
drivers/net/wireless/ti/wl12xx/scan.c
drivers/net/wireless/ti/wlcore/cmd.c
drivers/net/wireless/ti/wlcore/main.c
drivers/net/wireless/ti/wlcore/scan.c
include/linux/ieee80211.h
include/net/cfg80211.h
include/net/mac80211.h
include/net/regulatory.h
include/uapi/linux/nl80211.h
net/mac80211/cfg.c
net/mac80211/chan.c
net/mac80211/debugfs.c
net/mac80211/debugfs_sta.c
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/key.c
net/mac80211/key.h
net/mac80211/main.c
net/mac80211/mesh.c
net/mac80211/mesh.h
net/mac80211/mesh_hwmp.c
net/mac80211/mesh_pathtbl.c
net/mac80211/mesh_plink.c
net/mac80211/mesh_ps.c
net/mac80211/mesh_sync.c
net/mac80211/mlme.c
net/mac80211/rate.h
net/mac80211/rc80211_minstrel.c
net/mac80211/rc80211_minstrel_ht.c
net/mac80211/rc80211_minstrel_ht_debugfs.c
net/mac80211/rx.c
net/mac80211/scan.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h
net/mac80211/status.c
net/mac80211/trace.h
net/mac80211/tx.c
net/mac80211/util.c
net/mac80211/vht.c
net/mac80211/wpa.c
net/mac80211/wpa.h
net/wireless/chan.c
net/wireless/core.c
net/wireless/core.h
net/wireless/genregdb.awk
net/wireless/ibss.c
net/wireless/mesh.c
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/nl80211.h
net/wireless/rdev-ops.h
net/wireless/reg.c
net/wireless/reg.h
net/wireless/trace.h

index 9551622d0a7b845fe982076b3657ef59ef1ed6b7..356f791af5747fe4a2e1f25dea588d8b371d3d5b 100644 (file)
@@ -159,10 +159,10 @@ struct ieee80211_regdomain mydriver_jp_regdom = {
                REG_RULE(2412-20, 2484+20, 40, 6, 20, 0),
                /* IEEE 802.11a, channels 34..48 */
                REG_RULE(5170-20, 5240+20, 40, 6, 20,
-                       NL80211_RRF_PASSIVE_SCAN),
+                       NL80211_RRF_NO_IR),
                /* IEEE 802.11a, channels 52..64 */
                REG_RULE(5260-20, 5320+20, 40, 6, 20,
-                       NL80211_RRF_NO_IBSS |
+                       NL80211_RRF_NO_IR|
                        NL80211_RRF_DFS),
        }
 };
index 97ac8c87cba232646f5f82617ea396b8c2573870..06fe2b8fa22dd40a0817b1f38725d6106491fa34 100644 (file)
@@ -1351,12 +1351,12 @@ static int ath10k_update_channel_list(struct ath10k *ar)
                        ch->allow_vht = true;
 
                        ch->allow_ibss =
-                               !(channel->flags & IEEE80211_CHAN_NO_IBSS);
+                               !(channel->flags & IEEE80211_CHAN_NO_IR);
 
                        ch->ht40plus =
                                !(channel->flags & IEEE80211_CHAN_NO_HT40PLUS);
 
-                       passive = channel->flags & IEEE80211_CHAN_PASSIVE_SCAN;
+                       passive = channel->flags & IEEE80211_CHAN_NO_IR;
                        ch->passive = passive;
 
                        ch->freq = channel->center_freq;
index 2437ad26949d1c43617204fc7c887bf196a1e2f5..fd4c89df67e1658ae404686a911fc62607cee1cd 100644 (file)
@@ -1109,7 +1109,9 @@ void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq,
                                (mode == WMI_11G_HT20) ?
                                        NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT);
 
+       mutex_lock(&vif->wdev.mtx);
        cfg80211_ch_switch_notify(vif->ndev, &chandef);
+       mutex_unlock(&vif->wdev.mtx);
 }
 
 static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
@@ -3169,12 +3171,15 @@ static bool ath6kl_is_p2p_go_ssid(const u8 *buf, size_t len)
 }
 
 static int ath6kl_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 ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev);
        struct ath6kl *ar = ath6kl_priv(vif->ndev);
+       struct ieee80211_channel *chan = params->chan;
+       const u8 *buf = params->buf;
+       size_t len = params->len;
+       unsigned int wait = params->wait;
+       bool no_cck = params->no_cck;
        u32 id, freq;
        const struct ieee80211_mgmt *mgmt;
        bool more_data, queued;
index 1217c52ab28e6b07847217890bb6f1d9840a84b1..d3bbf48522b62e1af70cdea2685c74d3ab25d29f 100644 (file)
@@ -37,17 +37,18 @@ static int __ath_regd_init(struct ath_regulatory *reg);
 
 /* We enable active scan on these a case by case basis by regulatory domain */
 #define ATH9K_2GHZ_CH12_13     REG_RULE(2467-10, 2472+10, 40, 0, 20,\
-                                       NL80211_RRF_PASSIVE_SCAN)
+                                        NL80211_RRF_NO_IR)
 #define ATH9K_2GHZ_CH14                REG_RULE(2484-10, 2484+10, 40, 0, 20,\
-                               NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_OFDM)
+                                        NL80211_RRF_NO_IR | \
+                                        NL80211_RRF_NO_OFDM)
 
 /* We allow IBSS on these on a case by case basis by regulatory domain */
 #define ATH9K_5GHZ_5150_5350   REG_RULE(5150-10, 5350+10, 80, 0, 30,\
-                               NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
+                                        NL80211_RRF_NO_IR)
 #define ATH9K_5GHZ_5470_5850   REG_RULE(5470-10, 5850+10, 80, 0, 30,\
-                               NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
+                                        NL80211_RRF_NO_IR)
 #define ATH9K_5GHZ_5725_5850   REG_RULE(5725-10, 5850+10, 80, 0, 30,\
-                               NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
+                                        NL80211_RRF_NO_IR)
 
 #define ATH9K_2GHZ_ALL         ATH9K_2GHZ_CH01_11, \
                                ATH9K_2GHZ_CH12_13, \
@@ -223,18 +224,11 @@ ath_reg_apply_beaconing_flags(struct wiphy *wiphy,
                                 * default during init, prior to calling our
                                 * regulatory_hint().
                                 */
-                               if (!(reg_rule->flags &
-                                   NL80211_RRF_NO_IBSS))
-                                       ch->flags &=
-                                         ~IEEE80211_CHAN_NO_IBSS;
-                               if (!(reg_rule->flags &
-                                   NL80211_RRF_PASSIVE_SCAN))
-                                       ch->flags &=
-                                         ~IEEE80211_CHAN_PASSIVE_SCAN;
+                               if (!(reg_rule->flags & NL80211_RRF_NO_IR))
+                                       ch->flags &= ~IEEE80211_CHAN_NO_IR;
                        } else {
                                if (ch->beacon_found)
-                                       ch->flags &= ~(IEEE80211_CHAN_NO_IBSS |
-                                         IEEE80211_CHAN_PASSIVE_SCAN);
+                                       ch->flags &= ~IEEE80211_CHAN_NO_IR;
                        }
                }
        }
@@ -260,11 +254,11 @@ ath_reg_apply_active_scan_flags(struct wiphy *wiphy,
         */
        if (initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) {
                ch = &sband->channels[11]; /* CH 12 */
-               if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
-                       ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
+               if (ch->flags & IEEE80211_CHAN_NO_IR)
+                       ch->flags &= ~IEEE80211_CHAN_NO_IR;
                ch = &sband->channels[12]; /* CH 13 */
-               if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
-                       ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
+               if (ch->flags & IEEE80211_CHAN_NO_IR)
+                       ch->flags &= ~IEEE80211_CHAN_NO_IR;
                return;
        }
 
@@ -278,17 +272,17 @@ ath_reg_apply_active_scan_flags(struct wiphy *wiphy,
        ch = &sband->channels[11]; /* CH 12 */
        reg_rule = freq_reg_info(wiphy, ch->center_freq);
        if (!IS_ERR(reg_rule)) {
-               if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
-                       if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
-                               ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
+               if (!(reg_rule->flags & NL80211_RRF_NO_IR))
+                       if (ch->flags & IEEE80211_CHAN_NO_IR)
+                               ch->flags &= ~IEEE80211_CHAN_NO_IR;
        }
 
        ch = &sband->channels[12]; /* CH 13 */
        reg_rule = freq_reg_info(wiphy, ch->center_freq);
        if (!IS_ERR(reg_rule)) {
-               if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
-                       if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
-                               ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
+               if (!(reg_rule->flags & NL80211_RRF_NO_IR))
+                       if (ch->flags & IEEE80211_CHAN_NO_IR)
+                               ch->flags &= ~IEEE80211_CHAN_NO_IR;
        }
 }
 
@@ -320,8 +314,7 @@ static void ath_reg_apply_radar_flags(struct wiphy *wiphy)
                 */
                if (!(ch->flags & IEEE80211_CHAN_DISABLED))
                        ch->flags |= IEEE80211_CHAN_RADAR |
-                                    IEEE80211_CHAN_NO_IBSS |
-                                    IEEE80211_CHAN_PASSIVE_SCAN;
+                                    IEEE80211_CHAN_NO_IR;
        }
 }
 
@@ -609,7 +602,7 @@ ath_regd_init_wiphy(struct ath_regulatory *reg,
        const struct ieee80211_regdomain *regd;
 
        wiphy->reg_notifier = reg_notifier;
-       wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
+       wiphy->regulatory_flags |= REGULATORY_STRICT_REG;
 
        if (ath_is_world_regd(reg)) {
                /*
@@ -617,7 +610,8 @@ ath_regd_init_wiphy(struct ath_regulatory *reg,
                 * saved on the wiphy orig_* parameters
                 */
                regd = ath_world_regdomain(reg);
-               wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
+               wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
+                                          REGULATORY_COUNTRY_IE_FOLLOW_POWER;
        } else {
                /*
                 * This gets applied in the case of the absence of CRDA,
index 4a2293041821ff708c6cefef86ed21406f18266c..d3180360725925c40f6e59bf09bdfb28e18a4300 100644 (file)
@@ -812,7 +812,7 @@ static s32 brcmf_p2p_run_escan(struct brcmf_cfg80211_info *cfg,
                        struct ieee80211_channel *chan = request->channels[i];
 
                        if (chan->flags & (IEEE80211_CHAN_RADAR |
-                                          IEEE80211_CHAN_PASSIVE_SCAN))
+                                          IEEE80211_CHAN_NO_IR))
                                continue;
 
                        chanspecs[i] = channel_to_chanspec(&p2p->cfg->d11inf,
index 470a47f2b384893405a2b8f50710a2f1fa96c4b4..3966fe0fcfd971418fb3ca22bfc9fcaddf7afaf7 100644 (file)
@@ -202,9 +202,9 @@ static struct ieee80211_supported_band __wl_band_5ghz_a = {
 
 /* This is to override regulatory domains defined in cfg80211 module (reg.c)
  * By default world regulatory domain defined in reg.c puts the flags
- * NL80211_RRF_PASSIVE_SCAN and NL80211_RRF_NO_IBSS for 5GHz channels (for
- * 36..48 and 149..165). With respect to these flags, wpa_supplicant doesn't
- * start p2p operations on 5GHz channels. All the changes in world regulatory
+ * NL80211_RRF_NO_IR for 5GHz channels (for * 36..48 and 149..165).
+ * With respect to these flags, wpa_supplicant doesn't * start p2p
+ * operations on 5GHz channels. All the changes in world regulatory
  * domain are to be done here.
  */
 static const struct ieee80211_regdomain brcmf_regdom = {
@@ -3973,11 +3973,12 @@ brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
 
 static int
 brcmf_cfg80211_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 brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+       struct ieee80211_channel *chan = params->chan;
+       const u8 *buf = params->buf;
+       size_t len = params->len;
        const struct ieee80211_mgmt *mgmt;
        struct brcmf_cfg80211_vif *vif;
        s32 err = 0;
@@ -4341,7 +4342,7 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
        wiphy->max_remain_on_channel_duration = 5000;
        brcmf_wiphy_pno_params(wiphy);
        brcmf_dbg(INFO, "Registering custom regulatory\n");
-       wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
+       wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
        wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
        err = wiphy_register(wiphy);
        if (err < 0) {
@@ -5197,10 +5198,10 @@ static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, u32 bw_cap)
                                        if (channel & WL_CHAN_RADAR)
                                                band_chan_arr[index].flags |=
                                                        (IEEE80211_CHAN_RADAR |
-                                                       IEEE80211_CHAN_NO_IBSS);
+                                                       IEEE80211_CHAN_NO_IR);
                                        if (channel & WL_CHAN_PASSIVE)
                                                band_chan_arr[index].flags |=
-                                                   IEEE80211_CHAN_PASSIVE_SCAN;
+                                                   IEEE80211_CHAN_NO_IR;
                                }
                        }
                        if (!update)
index cc87926f505562335a02c605541c739725cf1a03..ef05df04136b0ed26a3f80abd0a9591e8de9ec44 100644 (file)
 
 #define BRCM_2GHZ_2412_2462    REG_RULE(2412-10, 2462+10, 40, 0, 19, 0)
 #define BRCM_2GHZ_2467_2472    REG_RULE(2467-10, 2472+10, 20, 0, 19, \
-                                        NL80211_RRF_PASSIVE_SCAN | \
-                                        NL80211_RRF_NO_IBSS)
+                                        NL80211_RRF_NO_IR)
 
 #define BRCM_5GHZ_5180_5240    REG_RULE(5180-10, 5240+10, 40, 0, 21, \
-                                        NL80211_RRF_PASSIVE_SCAN | \
-                                        NL80211_RRF_NO_IBSS)
+                                        NL80211_RRF_NO_IR)
 #define BRCM_5GHZ_5260_5320    REG_RULE(5260-10, 5320+10, 40, 0, 21, \
-                                        NL80211_RRF_PASSIVE_SCAN | \
                                         NL80211_RRF_DFS | \
-                                        NL80211_RRF_NO_IBSS)
+                                        NL80211_RRF_NO_IR)
 #define BRCM_5GHZ_5500_5700    REG_RULE(5500-10, 5700+10, 40, 0, 21, \
-                                        NL80211_RRF_PASSIVE_SCAN | \
                                         NL80211_RRF_DFS | \
-                                        NL80211_RRF_NO_IBSS)
+                                        NL80211_RRF_NO_IR)
 #define BRCM_5GHZ_5745_5825    REG_RULE(5745-10, 5825+10, 40, 0, 21, \
-                                        NL80211_RRF_PASSIVE_SCAN | \
-                                        NL80211_RRF_NO_IBSS)
+                                        NL80211_RRF_NO_IR)
 
 static const struct ieee80211_regdomain brcms_regdom_x2 = {
        .n_reg_rules = 6,
@@ -395,7 +390,7 @@ brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, u16 chanspec,
                brcms_c_set_gmode(wlc, wlc->protection->gmode_user, false);
 
        brcms_b_set_chanspec(wlc->hw, chanspec,
-                             !!(ch->flags & IEEE80211_CHAN_PASSIVE_SCAN),
+                             !!(ch->flags & IEEE80211_CHAN_NO_IR),
                              &txpwr);
 }
 
@@ -657,8 +652,8 @@ static void brcms_reg_apply_radar_flags(struct wiphy *wiphy)
                 */
                if (!(ch->flags & IEEE80211_CHAN_DISABLED))
                        ch->flags |= IEEE80211_CHAN_RADAR |
-                                    IEEE80211_CHAN_NO_IBSS |
-                                    IEEE80211_CHAN_PASSIVE_SCAN;
+                                    IEEE80211_CHAN_NO_IR |
+                                    IEEE80211_CHAN_NO_IR;
        }
 }
 
@@ -688,14 +683,10 @@ brcms_reg_apply_beaconing_flags(struct wiphy *wiphy,
                                if (IS_ERR(rule))
                                        continue;
 
-                               if (!(rule->flags & NL80211_RRF_NO_IBSS))
-                                       ch->flags &= ~IEEE80211_CHAN_NO_IBSS;
-                               if (!(rule->flags & NL80211_RRF_PASSIVE_SCAN))
-                                       ch->flags &=
-                                               ~IEEE80211_CHAN_PASSIVE_SCAN;
+                               if (!(rule->flags & NL80211_RRF_NO_IR))
+                                       ch->flags &= ~IEEE80211_CHAN_NO_IR;
                        } else if (ch->beacon_found) {
-                               ch->flags &= ~(IEEE80211_CHAN_NO_IBSS |
-                                              IEEE80211_CHAN_PASSIVE_SCAN);
+                               ch->flags &= ~IEEE80211_CHAN_NO_IR;
                        }
                }
        }
@@ -775,8 +766,8 @@ void brcms_c_regd_init(struct brcms_c_info *wlc)
        }
 
        wlc->wiphy->reg_notifier = brcms_reg_notifier;
-       wlc->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
-                            WIPHY_FLAG_STRICT_REGULATORY;
+       wlc->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
+                                       REGULATORY_STRICT_REG;
        wiphy_apply_custom_regulatory(wlc->wiphy, regd->regdomain);
        brcms_reg_apply_beaconing_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER);
 }
index edc5d105ff980e40e1ad2221a4c7686f87b0cea1..e71ce8c842a22f3a337cf1bbf4a08dc0e3e52b70 100644 (file)
@@ -125,13 +125,13 @@ static struct ieee80211_channel brcms_2ghz_chantable[] = {
        CHAN2GHZ(10, 2457, IEEE80211_CHAN_NO_HT40PLUS),
        CHAN2GHZ(11, 2462, IEEE80211_CHAN_NO_HT40PLUS),
        CHAN2GHZ(12, 2467,
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS |
+                IEEE80211_CHAN_NO_IR |
                 IEEE80211_CHAN_NO_HT40PLUS),
        CHAN2GHZ(13, 2472,
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS |
+                IEEE80211_CHAN_NO_IR |
                 IEEE80211_CHAN_NO_HT40PLUS),
        CHAN2GHZ(14, 2484,
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS |
+                IEEE80211_CHAN_NO_IR |
                 IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS |
                 IEEE80211_CHAN_NO_OFDM)
 };
@@ -144,51 +144,51 @@ static struct ieee80211_channel brcms_5ghz_nphy_chantable[] = {
        CHAN5GHZ(48, IEEE80211_CHAN_NO_HT40PLUS),
        /* UNII-2 */
        CHAN5GHZ(52,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
+                IEEE80211_CHAN_RADAR |
+                IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),
        CHAN5GHZ(56,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
+                IEEE80211_CHAN_RADAR |
+                IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),
        CHAN5GHZ(60,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
+                IEEE80211_CHAN_RADAR |
+                IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),
        CHAN5GHZ(64,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
+                IEEE80211_CHAN_RADAR |
+                IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),
        /* MID */
        CHAN5GHZ(100,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
+                IEEE80211_CHAN_RADAR |
+                IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),
        CHAN5GHZ(104,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
+                IEEE80211_CHAN_RADAR |
+                IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),
        CHAN5GHZ(108,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
+                IEEE80211_CHAN_RADAR |
+                IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),
        CHAN5GHZ(112,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
+                IEEE80211_CHAN_RADAR |
+                IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),
        CHAN5GHZ(116,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
+                IEEE80211_CHAN_RADAR |
+                IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),
        CHAN5GHZ(120,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
+                IEEE80211_CHAN_RADAR |
+                IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),
        CHAN5GHZ(124,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
+                IEEE80211_CHAN_RADAR |
+                IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),
        CHAN5GHZ(128,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
+                IEEE80211_CHAN_RADAR |
+                IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),
        CHAN5GHZ(132,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
+                IEEE80211_CHAN_RADAR |
+                IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),
        CHAN5GHZ(136,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
+                IEEE80211_CHAN_RADAR |
+                IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),
        CHAN5GHZ(140,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS |
+                IEEE80211_CHAN_RADAR |
+                IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS |
                 IEEE80211_CHAN_NO_HT40MINUS),
        /* UNII-3 */
        CHAN5GHZ(149, IEEE80211_CHAN_NO_HT40MINUS),
index ee3c19037aac5e039fe023a0fa3fa3b7d08f503d..8c017bfd2ffcde11a71633ae63a9ba5294762a2b 100644 (file)
@@ -197,9 +197,9 @@ void cw1200_scan_work(struct work_struct *work)
                        if ((*it)->band != first->band)
                                break;
                        if (((*it)->flags ^ first->flags) &
-                                       IEEE80211_CHAN_PASSIVE_SCAN)
+                                       IEEE80211_CHAN_NO_IR)
                                break;
-                       if (!(first->flags & IEEE80211_CHAN_PASSIVE_SCAN) &&
+                       if (!(first->flags & IEEE80211_CHAN_NO_IR) &&
                            (*it)->max_power != first->max_power)
                                break;
                }
@@ -210,7 +210,7 @@ void cw1200_scan_work(struct work_struct *work)
                else
                        scan.max_tx_rate = WSM_TRANSMIT_RATE_1;
                scan.num_probes =
-                       (first->flags & IEEE80211_CHAN_PASSIVE_SCAN) ? 0 : 2;
+                       (first->flags & IEEE80211_CHAN_NO_IR) ? 0 : 2;
                scan.num_ssids = priv->scan.n_ssids;
                scan.ssids = &priv->scan.ssids[0];
                scan.num_channels = it - priv->scan.curr;
@@ -233,7 +233,7 @@ void cw1200_scan_work(struct work_struct *work)
                }
                for (i = 0; i < scan.num_channels; ++i) {
                        scan.ch[i].number = priv->scan.curr[i]->hw_value;
-                       if (priv->scan.curr[i]->flags & IEEE80211_CHAN_PASSIVE_SCAN) {
+                       if (priv->scan.curr[i]->flags & IEEE80211_CHAN_NO_IR) {
                                scan.ch[i].min_chan_time = 50;
                                scan.ch[i].max_chan_time = 100;
                        } else {
@@ -241,7 +241,7 @@ void cw1200_scan_work(struct work_struct *work)
                                scan.ch[i].max_chan_time = 25;
                        }
                }
-               if (!(first->flags & IEEE80211_CHAN_PASSIVE_SCAN) &&
+               if (!(first->flags & IEEE80211_CHAN_NO_IR) &&
                    priv->scan.output_power != first->max_power) {
                        priv->scan.output_power = first->max_power;
                        wsm_set_output_power(priv,
index f8ab193009cd9f3044a3d8846d4da4e7cbaec3e5..813c9af0ebd6e4a683a51f3ba7e5f39d4da14d77 100644 (file)
@@ -1930,10 +1930,10 @@ static int ipw2100_wdev_init(struct net_device *dev)
                        bg_band->channels[i].max_power = geo->bg[i].max_power;
                        if (geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY)
                                bg_band->channels[i].flags |=
-                                       IEEE80211_CHAN_PASSIVE_SCAN;
+                                       IEEE80211_CHAN_NO_IR;
                        if (geo->bg[i].flags & LIBIPW_CH_NO_IBSS)
                                bg_band->channels[i].flags |=
-                                       IEEE80211_CHAN_NO_IBSS;
+                                       IEEE80211_CHAN_NO_IR;
                        if (geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT)
                                bg_band->channels[i].flags |=
                                        IEEE80211_CHAN_RADAR;
index 81903e33d5b1bd4779681da798dc0183c0638f48..9244b3661d343d8908bb72ec3a4516391d1d9900 100644 (file)
@@ -11472,10 +11472,10 @@ static int ipw_wdev_init(struct net_device *dev)
                        bg_band->channels[i].max_power = geo->bg[i].max_power;
                        if (geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY)
                                bg_band->channels[i].flags |=
-                                       IEEE80211_CHAN_PASSIVE_SCAN;
+                                       IEEE80211_CHAN_NO_IR;
                        if (geo->bg[i].flags & LIBIPW_CH_NO_IBSS)
                                bg_band->channels[i].flags |=
-                                       IEEE80211_CHAN_NO_IBSS;
+                                       IEEE80211_CHAN_NO_IR;
                        if (geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT)
                                bg_band->channels[i].flags |=
                                        IEEE80211_CHAN_RADAR;
@@ -11511,10 +11511,10 @@ static int ipw_wdev_init(struct net_device *dev)
                        a_band->channels[i].max_power = geo->a[i].max_power;
                        if (geo->a[i].flags & LIBIPW_CH_PASSIVE_ONLY)
                                a_band->channels[i].flags |=
-                                       IEEE80211_CHAN_PASSIVE_SCAN;
+                                       IEEE80211_CHAN_NO_IR;
                        if (geo->a[i].flags & LIBIPW_CH_NO_IBSS)
                                a_band->channels[i].flags |=
-                                       IEEE80211_CHAN_NO_IBSS;
+                                       IEEE80211_CHAN_NO_IR;
                        if (geo->a[i].flags & LIBIPW_CH_RADAR_DETECT)
                                a_band->channels[i].flags |=
                                        IEEE80211_CHAN_RADAR;
index dea3b50d68b9c5bcfc1c95794262992bc59d917d..5c3bcedd679ba06b122e1ef5e05c18973980485b 100644 (file)
@@ -1595,7 +1595,7 @@ il3945_get_channels_for_scan(struct il_priv *il, enum ieee80211_band band,
                 *  and use long active_dwell time.
                 */
                if (!is_active || il_is_channel_passive(ch_info) ||
-                   (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)) {
+                   (chan->flags & IEEE80211_CHAN_NO_IR)) {
                        scan_ch->type = 0;      /* passive */
                        if (IL_UCODE_API(il->ucode_ver) == 1)
                                scan_ch->active_dwell =
@@ -3575,9 +3575,9 @@ il3945_setup_mac(struct il_priv *il)
        hw->wiphy->interface_modes =
            BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC);
 
-       hw->wiphy->flags |=
-           WIPHY_FLAG_CUSTOM_REGULATORY | WIPHY_FLAG_DISABLE_BEACON_HINTS |
-           WIPHY_FLAG_IBSS_RSN;
+       hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
+       hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
+                                      REGULATORY_DISABLE_BEACON_HINTS;
 
        hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
 
index 3982ab76f3755fdbda4f0cab89aa6cca537a8f43..43f488a8cda21790a646dcd4efa4ffd04d445c96 100644 (file)
@@ -805,7 +805,7 @@ il4965_get_channels_for_scan(struct il_priv *il, struct ieee80211_vif *vif,
                }
 
                if (!is_active || il_is_channel_passive(ch_info) ||
-                   (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN))
+                   (chan->flags & IEEE80211_CHAN_NO_IR))
                        scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
                else
                        scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE;
@@ -5778,9 +5778,9 @@ il4965_mac_setup_register(struct il_priv *il, u32 max_probe_length)
        hw->wiphy->interface_modes =
            BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC);
 
-       hw->wiphy->flags |=
-           WIPHY_FLAG_CUSTOM_REGULATORY | WIPHY_FLAG_DISABLE_BEACON_HINTS |
-           WIPHY_FLAG_IBSS_RSN;
+       hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
+       hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
+                                      REGULATORY_DISABLE_BEACON_HINTS;
 
        /*
         * For now, disable PS by default because it affects
index b03e22ef5462d929ea20ffad72a4a01ff067c4a4..a27b14cfeaec05753bb64fe8708ec7c25065995c 100644 (file)
@@ -3445,10 +3445,10 @@ il_init_geos(struct il_priv *il)
 
                if (il_is_channel_valid(ch)) {
                        if (!(ch->flags & EEPROM_CHANNEL_IBSS))
-                               geo_ch->flags |= IEEE80211_CHAN_NO_IBSS;
+                               geo_ch->flags |= IEEE80211_CHAN_NO_IR;
 
                        if (!(ch->flags & EEPROM_CHANNEL_ACTIVE))
-                               geo_ch->flags |= IEEE80211_CHAN_PASSIVE_SCAN;
+                               geo_ch->flags |= IEEE80211_CHAN_NO_IR;
 
                        if (ch->flags & EEPROM_CHANNEL_RADAR)
                                geo_ch->flags |= IEEE80211_CHAN_RADAR;
index eff26501d60a63407fba5b8cff66778d612df54e..3a487a3bb5de8fd62c896409df62562712e41239 100644 (file)
@@ -567,12 +567,12 @@ il_dbgfs_channels_read(struct file *file, char __user *user_buf, size_t count,
                                      flags & IEEE80211_CHAN_RADAR ?
                                      " (IEEE 802.11h required)" : "",
                                      ((channels[i].
-                                       flags & IEEE80211_CHAN_NO_IBSS) ||
+                                       flags & IEEE80211_CHAN_NO_IR) ||
                                       (channels[i].
                                        flags & IEEE80211_CHAN_RADAR)) ? "" :
                                      ", IBSS",
                                      channels[i].
-                                     flags & IEEE80211_CHAN_PASSIVE_SCAN ?
+                                     flags & IEEE80211_CHAN_NO_IR ?
                                      "passive only" : "active/passive");
        }
        supp_band = il_get_hw_mode(il, IEEE80211_BAND_5GHZ);
@@ -594,12 +594,12 @@ il_dbgfs_channels_read(struct file *file, char __user *user_buf, size_t count,
                                      flags & IEEE80211_CHAN_RADAR ?
                                      " (IEEE 802.11h required)" : "",
                                      ((channels[i].
-                                       flags & IEEE80211_CHAN_NO_IBSS) ||
+                                       flags & IEEE80211_CHAN_NO_IR) ||
                                       (channels[i].
                                        flags & IEEE80211_CHAN_RADAR)) ? "" :
                                      ", IBSS",
                                      channels[i].
-                                     flags & IEEE80211_CHAN_PASSIVE_SCAN ?
+                                     flags & IEEE80211_CHAN_NO_IR ?
                                      "passive only" : "active/passive");
        }
        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
index d94f8ab15004cb93f2e757f92a91fd3e669759cb..f69301e505ee0e8968d5a9b90f9dcb3404c1f843 100644 (file)
@@ -352,12 +352,12 @@ static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf,
                                        channels[i].max_power,
                                        channels[i].flags & IEEE80211_CHAN_RADAR ?
                                        " (IEEE 802.11h required)" : "",
-                                       ((channels[i].flags & IEEE80211_CHAN_NO_IBSS)
+                                       ((channels[i].flags & IEEE80211_CHAN_NO_IR)
                                        || (channels[i].flags &
                                        IEEE80211_CHAN_RADAR)) ? "" :
                                        ", IBSS",
                                        channels[i].flags &
-                                       IEEE80211_CHAN_PASSIVE_SCAN ?
+                                       IEEE80211_CHAN_NO_IR ?
                                        "passive only" : "active/passive");
        }
        supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_5GHZ);
@@ -375,12 +375,12 @@ static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf,
                                        channels[i].max_power,
                                        channels[i].flags & IEEE80211_CHAN_RADAR ?
                                        " (IEEE 802.11h required)" : "",
-                                       ((channels[i].flags & IEEE80211_CHAN_NO_IBSS)
+                                       ((channels[i].flags & IEEE80211_CHAN_NO_IR)
                                        || (channels[i].flags &
                                        IEEE80211_CHAN_RADAR)) ? "" :
                                        ", IBSS",
                                        channels[i].flags &
-                                       IEEE80211_CHAN_PASSIVE_SCAN ?
+                                       IEEE80211_CHAN_NO_IR ?
                                        "passive only" : "active/passive");
        }
        ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
index cae4d3182e334f9451e38d0afada8a8468785195..217f1ca321a0fecb7aaa876a5a22b5ec214b5818 100644 (file)
@@ -155,9 +155,9 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
                        ARRAY_SIZE(iwlagn_iface_combinations_dualmode);
        }
 
-       hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
-                           WIPHY_FLAG_DISABLE_BEACON_HINTS |
-                           WIPHY_FLAG_IBSS_RSN;
+       hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
+       hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
+                                      REGULATORY_DISABLE_BEACON_HINTS;
 
 #ifdef CONFIG_PM_SLEEP
        if (priv->fw->img[IWL_UCODE_WOWLAN].sec[0].len &&
index 35e0ee8b4e5b64162ecdb2287ae53ab3acd5ee4b..928f8640a0a7965aebfb5c429265ac71a4970f88 100644 (file)
@@ -544,7 +544,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
                channel = chan->hw_value;
                scan_ch->channel = cpu_to_le16(channel);
 
-               if (!is_active || (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN))
+               if (!is_active || (chan->flags & IEEE80211_CHAN_NO_IR))
                        scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
                else
                        scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE;
index 4c887f3659089ea3451bc9cc4f2a8dc44c764601..f4a6d317a023aad241ac4f15351a1cc2deae7a2c 100644 (file)
@@ -614,10 +614,10 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
                        channel->flags = IEEE80211_CHAN_NO_HT40;
 
                        if (!(eeprom_ch->flags & EEPROM_CHANNEL_IBSS))
-                               channel->flags |= IEEE80211_CHAN_NO_IBSS;
+                               channel->flags |= IEEE80211_CHAN_NO_IR;
 
                        if (!(eeprom_ch->flags & EEPROM_CHANNEL_ACTIVE))
-                               channel->flags |= IEEE80211_CHAN_PASSIVE_SCAN;
+                               channel->flags |= IEEE80211_CHAN_NO_IR;
 
                        if (eeprom_ch->flags & EEPROM_CHANNEL_RADAR)
                                channel->flags |= IEEE80211_CHAN_RADAR;
index b76a9a8fc0b3dbe831f74ce7d20a811e6cf17ada..2fab203d30275c658a5e4e6a8c296d9595a4ce73 100644 (file)
@@ -223,10 +223,10 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
                        channel->flags |= IEEE80211_CHAN_NO_160MHZ;
 
                if (!(ch_flags & NVM_CHANNEL_IBSS))
-                       channel->flags |= IEEE80211_CHAN_NO_IBSS;
+                       channel->flags |= IEEE80211_CHAN_NO_IR;
 
                if (!(ch_flags & NVM_CHANNEL_ACTIVE))
-                       channel->flags |= IEEE80211_CHAN_PASSIVE_SCAN;
+                       channel->flags |= IEEE80211_CHAN_NO_IR;
 
                if (ch_flags & NVM_CHANNEL_RADAR)
                        channel->flags |= IEEE80211_CHAN_RADAR;
index 74bc2c8af06d62fb360de4357621dca50201a8c2..b56c989ad784d97b00e293209f02bc69d34f31c5 100644 (file)
@@ -199,9 +199,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
        if (IWL_UCODE_API(mvm->fw->ucode_ver) >= 8)
                hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
 
-       hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
-                           WIPHY_FLAG_DISABLE_BEACON_HINTS |
-                           WIPHY_FLAG_IBSS_RSN;
+       hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
+       hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
+                                      REGULATORY_DISABLE_BEACON_HINTS;
 
        hw->wiphy->iface_combinations = iwl_mvm_iface_combinations;
        hw->wiphy->n_iface_combinations =
index dff7592e1ff84e5c3f6a05d673e2a39514cbb870..e0cd100b40cd6d5f69155d04fb2bcccd0d2c62a6 100644 (file)
@@ -192,7 +192,7 @@ static void iwl_mvm_scan_fill_channels(struct iwl_scan_cmd *cmd,
        for (i = 0; i < cmd->channel_count; i++) {
                chan->channel = cpu_to_le16(req->channels[i]->hw_value);
                chan->type = cpu_to_le32(type);
-               if (req->channels[i]->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+               if (req->channels[i]->flags & IEEE80211_CHAN_NO_IR)
                        chan->type &= cpu_to_le32(~SCAN_CHANNEL_TYPE_ACTIVE);
                chan->active_dwell = cpu_to_le16(active_dwell);
                chan->passive_dwell = cpu_to_le16(passive_dwell);
@@ -642,7 +642,7 @@ static void iwl_build_channel_cfg(struct iwl_mvm *mvm,
                channels->iter_count[index] = cpu_to_le16(1);
                channels->iter_interval[index] = 0;
 
-               if (!(s_band->channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN))
+               if (!(s_band->channels[i].flags & IEEE80211_CHAN_NO_IR))
                        channels->type[index] |=
                                cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_ACTIVE);
 
index 9df7bc91a26f54c9812718e481c538895aa5b4f8..3f9a4c9ad77a1d67ca53a0d6962800a20bff6391 100644 (file)
@@ -159,7 +159,7 @@ static const struct ieee80211_regdomain hwsim_world_regdom_custom_02 = {
        .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,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 */
        /*
@@ -362,7 +361,6 @@ struct mac80211_hwsim_data {
         * radio can be in more then one group.
         */
        u64 group;
-       struct dentry *debugfs_group;
 
        int power_level;
 
@@ -1485,7 +1483,7 @@ static void hw_scan_work(struct work_struct *work)
                    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 {
@@ -1734,9 +1732,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);
@@ -1893,6 +1889,17 @@ static int hwsim_fops_ps_write(void *dat, u64 val)
 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)
 {
@@ -2193,11 +2200,28 @@ static const struct ieee80211_iface_limit hwsim_if_limits[] = {
        { .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)
@@ -2215,7 +2239,7 @@ 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;
@@ -2295,13 +2319,15 @@ static int __init init_mac80211_hwsim(void)
                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);
@@ -2325,7 +2351,8 @@ static int __init init_mac80211_hwsim(void)
                            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;
 
@@ -2385,6 +2412,7 @@ static int __init init_mac80211_hwsim(void)
                        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 |
@@ -2427,46 +2455,53 @@ static int __init init_mac80211_hwsim(void)
                        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;
@@ -2533,16 +2568,18 @@ static int __init init_mac80211_hwsim(void)
 
                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);
        }
index aeaea0e3b4c414ae925b79a3eb4962f7bb36ad4b..d9b7330c902f1824a57cdc265df82590b16d3180 100644 (file)
@@ -50,24 +50,24 @@ static const struct ieee80211_regdomain mwifiex_world_regdom_custom = {
                REG_RULE(2412-10, 2462+10, 40, 3, 20, 0),
                /* Channel 12 - 13 */
                REG_RULE(2467-10, 2472+10, 20, 3, 20,
-                        NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS),
+                        NL80211_RRF_NO_IR),
                /* Channel 14 */
                REG_RULE(2484-10, 2484+10, 20, 3, 20,
-                        NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS |
+                        NL80211_RRF_NO_IR |
                         NL80211_RRF_NO_OFDM),
                /* Channel 36 - 48 */
                REG_RULE(5180-10, 5240+10, 40, 3, 20,
-                        NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS),
+                        NL80211_RRF_NO_IR),
                /* Channel 149 - 165 */
                REG_RULE(5745-10, 5825+10, 40, 3, 20,
-                        NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS),
+                        NL80211_RRF_NO_IR),
                /* Channel 52 - 64 */
                REG_RULE(5260-10, 5320+10, 40, 3, 30,
-                        NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS |
+                        NL80211_RRF_NO_IR |
                         NL80211_RRF_DFS),
                /* Channel 100 - 140 */
                REG_RULE(5500-10, 5700+10, 40, 3, 30,
-                        NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS |
+                        NL80211_RRF_NO_IR |
                         NL80211_RRF_DFS),
        }
 };
@@ -184,10 +184,10 @@ mwifiex_form_mgmt_frame(struct sk_buff *skb, const u8 *buf, size_t len)
  */
 static int
 mwifiex_cfg80211_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)
 {
+       const u8 *buf = params->buf;
+       size_t len = params->len;
        struct sk_buff *skb;
        u16 pkt_len;
        const struct ieee80211_mgmt *mgmt;
@@ -1968,7 +1968,7 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,
                user_scan_cfg->chan_list[i].chan_number = chan->hw_value;
                user_scan_cfg->chan_list[i].radio_type = chan->band;
 
-               if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+               if (chan->flags & IEEE80211_CHAN_NO_IR)
                        user_scan_cfg->chan_list[i].scan_type =
                                                MWIFIEX_SCAN_TYPE_PASSIVE;
                else
@@ -2702,9 +2702,10 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
        wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME |
                        WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD |
                        WIPHY_FLAG_AP_UAPSD |
-                       WIPHY_FLAG_CUSTOM_REGULATORY |
-                       WIPHY_FLAG_STRICT_REGULATORY |
                        WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+       wiphy->regulatory_flags |=
+                       REGULATORY_CUSTOM_REG |
+                       REGULATORY_STRICT_REG;
 
        wiphy_apply_custom_regulatory(wiphy, &mwifiex_world_regdom_custom);
 
index 8cf7d50a7603121682c7f9a9684a64a978de85c9..0ed06646f19a1e9de631f8874b1cb236dce06340 100644 (file)
@@ -515,14 +515,14 @@ mwifiex_scan_create_channel_list(struct mwifiex_private *priv,
                                scan_chan_list[chan_idx].max_scan_time =
                                        cpu_to_le16((u16) user_scan_in->
                                        chan_list[0].scan_time);
-                       else if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+                       else if (ch->flags & IEEE80211_CHAN_NO_IR)
                                scan_chan_list[chan_idx].max_scan_time =
                                        cpu_to_le16(adapter->passive_scan_time);
                        else
                                scan_chan_list[chan_idx].max_scan_time =
                                        cpu_to_le16(adapter->active_scan_time);
 
-                       if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+                       if (ch->flags & IEEE80211_CHAN_NO_IR)
                                scan_chan_list[chan_idx].chan_scan_mode_bitmap
                                        |= MWIFIEX_PASSIVE_SCAN;
                        else
index d7d0d4948b01f2e804e6bcddfca93b10c7cdb312..89e36568e70f71861c0b5ab1a988a6ac4ea998bd 100644 (file)
@@ -59,30 +59,26 @@ static struct country_code_to_enum_rd allCountries[] = {
  */
 #define RTL819x_2GHZ_CH12_13   \
        REG_RULE(2467-10, 2472+10, 40, 0, 20,\
-       NL80211_RRF_PASSIVE_SCAN)
+                NL80211_RRF_NO_IR)
 
 #define RTL819x_2GHZ_CH14      \
        REG_RULE(2484-10, 2484+10, 40, 0, 20, \
-       NL80211_RRF_PASSIVE_SCAN | \
-       NL80211_RRF_NO_OFDM)
+                NL80211_RRF_NO_IR | NL80211_RRF_NO_OFDM)
 
 /* 5G chan 36 - chan 64*/
 #define RTL819x_5GHZ_5150_5350 \
        REG_RULE(5150-10, 5350+10, 40, 0, 30, \
-       NL80211_RRF_PASSIVE_SCAN | \
-       NL80211_RRF_NO_IBSS)
+                NL80211_RRF_NO_IR)
 
 /* 5G chan 100 - chan 165*/
 #define RTL819x_5GHZ_5470_5850 \
        REG_RULE(5470-10, 5850+10, 40, 0, 30, \
-       NL80211_RRF_PASSIVE_SCAN | \
-       NL80211_RRF_NO_IBSS)
+                NL80211_RRF_NO_IR)
 
 /* 5G chan 149 - chan 165*/
 #define RTL819x_5GHZ_5725_5850 \
        REG_RULE(5725-10, 5850+10, 40, 0, 30, \
-       NL80211_RRF_PASSIVE_SCAN | \
-       NL80211_RRF_NO_IBSS)
+                NL80211_RRF_NO_IR)
 
 #define RTL819x_5GHZ_ALL       \
        (RTL819x_5GHZ_5150_5350, RTL819x_5GHZ_5470_5850)
@@ -185,16 +181,11 @@ static void _rtl_reg_apply_beaconing_flags(struct wiphy *wiphy,
                                 *regulatory_hint().
                                 */
 
-                               if (!(reg_rule->flags & NL80211_RRF_NO_IBSS))
-                                       ch->flags &= ~IEEE80211_CHAN_NO_IBSS;
-                               if (!(reg_rule->
-                                    flags & NL80211_RRF_PASSIVE_SCAN))
-                                       ch->flags &=
-                                           ~IEEE80211_CHAN_PASSIVE_SCAN;
+                               if (!(reg_rule->flags & NL80211_RRF_NO_IR))
+                                       ch->flags &= ~IEEE80211_CHAN_NO_IR;
                        } else {
                                if (ch->beacon_found)
-                                       ch->flags &= ~(IEEE80211_CHAN_NO_IBSS |
-                                                 IEEE80211_CHAN_PASSIVE_SCAN);
+                                       ch->flags &= ~IEEE80211_CHAN_NO_IR;
                        }
                }
        }
@@ -219,11 +210,11 @@ static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy,
         */
        if (initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) {
                ch = &sband->channels[11];      /* CH 12 */
-               if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
-                       ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
+               if (ch->flags & IEEE80211_CHAN_NO_IR)
+                       ch->flags &= ~IEEE80211_CHAN_NO_IR;
                ch = &sband->channels[12];      /* CH 13 */
-               if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
-                       ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
+               if (ch->flags & IEEE80211_CHAN_NO_IR)
+                       ch->flags &= ~IEEE80211_CHAN_NO_IR;
                return;
        }
 
@@ -237,17 +228,17 @@ static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy,
        ch = &sband->channels[11];      /* CH 12 */
        reg_rule = freq_reg_info(wiphy, ch->center_freq);
        if (!IS_ERR(reg_rule)) {
-               if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
-                       if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
-                               ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
+               if (!(reg_rule->flags & NL80211_RRF_NO_IR))
+                       if (ch->flags & IEEE80211_CHAN_NO_IR)
+                               ch->flags &= ~IEEE80211_CHAN_NO_IR;
        }
 
        ch = &sband->channels[12];      /* CH 13 */
        reg_rule = freq_reg_info(wiphy, ch->center_freq);
        if (!IS_ERR(reg_rule)) {
-               if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
-                       if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
-                               ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
+               if (!(reg_rule->flags & NL80211_RRF_NO_IR))
+                       if (ch->flags & IEEE80211_CHAN_NO_IR)
+                               ch->flags &= ~IEEE80211_CHAN_NO_IR;
        }
 }
 
@@ -284,8 +275,7 @@ static void _rtl_reg_apply_radar_flags(struct wiphy *wiphy)
                 */
                if (!(ch->flags & IEEE80211_CHAN_DISABLED))
                        ch->flags |= IEEE80211_CHAN_RADAR |
-                           IEEE80211_CHAN_NO_IBSS |
-                           IEEE80211_CHAN_PASSIVE_SCAN;
+                                    IEEE80211_CHAN_NO_IR;
        }
 }
 
@@ -354,9 +344,9 @@ static int _rtl_regd_init_wiphy(struct rtl_regulatory *reg,
 
        wiphy->reg_notifier = reg_notifier;
 
-       wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
-       wiphy->flags &= ~WIPHY_FLAG_STRICT_REGULATORY;
-       wiphy->flags &= ~WIPHY_FLAG_DISABLE_BEACON_HINTS;
+       wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
+       wiphy->regulatory_flags &= ~REGULATORY_STRICT_REG;
+       wiphy->regulatory_flags &= ~REGULATORY_DISABLE_BEACON_HINTS;
 
        regd = _rtl_regdomain_select(reg);
        wiphy_apply_custom_regulatory(wiphy, regd);
index 4a0bbb13806bd6fd61266c729f4a433d110ac838..7541bd1a4a4b40de9b6be249dea94ca8f95e96ae 100644 (file)
@@ -47,7 +47,7 @@ static int wl1271_get_scan_channels(struct wl1271 *wl,
                     * In active scans, we only scan channels not
                     * marked as passive.
                     */
-                   (passive || !(flags & IEEE80211_CHAN_PASSIVE_SCAN))) {
+                   (passive || !(flags & IEEE80211_CHAN_NO_IR))) {
                        wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ",
                                     req->channels[i]->band,
                                     req->channels[i]->center_freq);
index 34d9dfff2ad39ead03d3da275cd3e4443385a220..9b2ecf52449faa911f25bea176ed12683fe1836e 100644 (file)
@@ -1688,7 +1688,7 @@ int wlcore_cmd_regdomain_config_locked(struct wl1271 *wl)
 
                        if (channel->flags & (IEEE80211_CHAN_DISABLED |
                                              IEEE80211_CHAN_RADAR |
-                                             IEEE80211_CHAN_PASSIVE_SCAN))
+                                             IEEE80211_CHAN_NO_IR))
                                continue;
 
                        ch_bit_idx = wlcore_get_reg_conf_ch_idx(b, ch);
index 0368b9cbfb896d6460da3635b199ef6266805644..e9da47cead587704c7060ebd8ab754c1aa7da16b 100644 (file)
@@ -91,8 +91,7 @@ static void wl1271_reg_notify(struct wiphy *wiphy,
                        continue;
 
                if (ch->flags & IEEE80211_CHAN_RADAR)
-                       ch->flags |= IEEE80211_CHAN_NO_IBSS |
-                                    IEEE80211_CHAN_PASSIVE_SCAN;
+                       ch->flags |= IEEE80211_CHAN_NO_IR;
 
        }
 
index 7ed86203304b700c87e4b1ca48de127f7466420f..1e3d51cd673ab6d2be132c6fda17f698547b3ff7 100644 (file)
@@ -188,16 +188,14 @@ wlcore_scan_get_channels(struct wl1271 *wl,
                flags = req_channels[i]->flags;
 
                if (force_passive)
-                       flags |= IEEE80211_CHAN_PASSIVE_SCAN;
+                       flags |= IEEE80211_CHAN_NO_IR;
 
                if ((req_channels[i]->band == band) &&
                    !(flags & IEEE80211_CHAN_DISABLED) &&
                    (!!(flags & IEEE80211_CHAN_RADAR) == radar) &&
                    /* if radar is set, we ignore the passive flag */
                    (radar ||
-                    !!(flags & IEEE80211_CHAN_PASSIVE_SCAN) == passive)) {
-
-
+                    !!(flags & IEEE80211_CHAN_NO_IR) == passive)) {
                        if (flags & IEEE80211_CHAN_RADAR) {
                                channels[j].flags |= SCAN_CHANNEL_FLAGS_DFS;
 
@@ -220,7 +218,7 @@ wlcore_scan_get_channels(struct wl1271 *wl,
                            (band == IEEE80211_BAND_2GHZ) &&
                            (channels[j].channel >= 12) &&
                            (channels[j].channel <= 14) &&
-                           (flags & IEEE80211_CHAN_PASSIVE_SCAN) &&
+                           (flags & IEEE80211_CHAN_NO_IR) &&
                            !force_passive) {
                                /* pactive channels treated as DFS */
                                channels[j].flags = SCAN_CHANNEL_FLAGS_DFS;
@@ -243,8 +241,8 @@ wlcore_scan_get_channels(struct wl1271 *wl,
                                     max_dwell_time_active,
                                     flags & IEEE80211_CHAN_RADAR ?
                                        ", DFS" : "",
-                                    flags & IEEE80211_CHAN_PASSIVE_SCAN ?
-                                       ", PASSIVE" : "");
+                                    flags & IEEE80211_CHAN_NO_IR ?
+                                       ", NO-IR" : "");
                        j++;
                }
        }
index 8c3b26a215745b755a5018764e4c0ca1f1bd52b7..776cbb80d098d37e90c0bf0e8c37736ab961f338 100644 (file)
@@ -1411,8 +1411,12 @@ struct ieee80211_vht_operation {
 #define IEEE80211_VHT_CAP_RXSTBC_MASK                          0x00000700
 #define IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE                        0x00000800
 #define IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE                        0x00001000
-#define IEEE80211_VHT_CAP_BEAMFORMEE_STS_MAX                   0x0000e000
-#define IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MAX              0x00070000
+#define IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT                  13
+#define IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK                  \
+               (7 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT)
+#define IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT            16
+#define IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK             \
+               (7 << IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT)
 #define IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE                        0x00080000
 #define IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE                        0x00100000
 #define IEEE80211_VHT_CAP_VHT_TXOP_PS                          0x00200000
index 3eae46cb1acfecadbff979ee17e17aeab40971e7..e9abc7b536cdebb5434caae1cbd487378ad0dfe1 100644 (file)
@@ -91,9 +91,8 @@ enum ieee80211_band {
  * Channel flags set by the regulatory control code.
  *
  * @IEEE80211_CHAN_DISABLED: This channel is disabled.
- * @IEEE80211_CHAN_PASSIVE_SCAN: Only passive scanning is permitted
- *     on this channel.
- * @IEEE80211_CHAN_NO_IBSS: IBSS is not allowed on this channel.
+ * @IEEE80211_CHAN_NO_IR: do not initiate radiation, this includes
+ *     sending probe requests or beaconing.
  * @IEEE80211_CHAN_RADAR: Radar detection is required on this channel.
  * @IEEE80211_CHAN_NO_HT40PLUS: extension channel above this channel
  *     is not permitted.
@@ -113,8 +112,8 @@ enum ieee80211_band {
  */
 enum ieee80211_channel_flags {
        IEEE80211_CHAN_DISABLED         = 1<<0,
-       IEEE80211_CHAN_PASSIVE_SCAN     = 1<<1,
-       IEEE80211_CHAN_NO_IBSS          = 1<<2,
+       IEEE80211_CHAN_NO_IR            = 1<<1,
+       /* hole at 1<<2 */
        IEEE80211_CHAN_RADAR            = 1<<3,
        IEEE80211_CHAN_NO_HT40PLUS      = 1<<4,
        IEEE80211_CHAN_NO_HT40MINUS     = 1<<5,
@@ -1944,6 +1943,29 @@ struct cfg80211_update_ft_ies_params {
        size_t ie_len;
 };
 
+/**
+ * struct cfg80211_mgmt_tx_params - mgmt tx parameters
+ *
+ * This structure provides information needed to transmit a mgmt frame
+ *
+ * @chan: channel to use
+ * @offchan: indicates wether off channel operation is required
+ * @wait: duration for ROC
+ * @buf: buffer to transmit
+ * @len: buffer length
+ * @no_cck: don't use cck rates for this frame
+ * @dont_wait_for_ack: tells the low level not to wait for an ack
+ */
+struct cfg80211_mgmt_tx_params {
+       struct ieee80211_channel *chan;
+       bool offchan;
+       unsigned int wait;
+       const u8 *buf;
+       size_t len;
+       bool no_cck;
+       bool dont_wait_for_ack;
+};
+
 /**
  * struct cfg80211_ops - backend description for wireless configuration
  *
@@ -2342,9 +2364,8 @@ struct cfg80211_ops {
                                            u64 cookie);
 
        int     (*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);
        int     (*mgmt_tx_cancel_wait)(struct wiphy *wiphy,
                                       struct wireless_dev *wdev,
                                       u64 cookie);
@@ -2438,27 +2459,6 @@ struct cfg80211_ops {
 /**
  * enum wiphy_flags - wiphy capability flags
  *
- * @WIPHY_FLAG_CUSTOM_REGULATORY:  tells us the driver for this device
- *     has its own custom regulatory domain and cannot identify the
- *     ISO / IEC 3166 alpha2 it belongs to. When this is enabled
- *     we will disregard the first regulatory hint (when the
- *     initiator is %REGDOM_SET_BY_CORE).
- * @WIPHY_FLAG_STRICT_REGULATORY: tells us the driver for this device will
- *     ignore regulatory domain settings until it gets its own regulatory
- *     domain via its regulatory_hint() unless the regulatory hint is
- *     from a country IE. After its gets its own regulatory domain it will
- *     only allow further regulatory domain settings to further enhance
- *     compliance. For example if channel 13 and 14 are disabled by this
- *     regulatory domain no user regulatory domain can enable these channels
- *     at a later time. This can be used for devices which do not have
- *     calibration information guaranteed for frequencies or settings
- *     outside of its regulatory domain. If used in combination with
- *     WIPHY_FLAG_CUSTOM_REGULATORY the inspected country IE power settings
- *     will be followed.
- * @WIPHY_FLAG_DISABLE_BEACON_HINTS: enable this if your driver needs to ensure
- *     that passive scan flags and beaconing flags may not be lifted by
- *     cfg80211 due to regulatory beacon hints. For more information on beacon
- *     hints read the documenation for regulatory_hint_found_beacon()
  * @WIPHY_FLAG_NETNS_OK: if not set, do not allow changing the netns of this
  *     wiphy at all
  * @WIPHY_FLAG_PS_ON_BY_DEFAULT: if set to true, powersave will be enabled
@@ -2497,9 +2497,9 @@ struct cfg80211_ops {
  *     beaconing mode (AP, IBSS, Mesh, ...).
  */
 enum wiphy_flags {
-       WIPHY_FLAG_CUSTOM_REGULATORY            = BIT(0),
-       WIPHY_FLAG_STRICT_REGULATORY            = BIT(1),
-       WIPHY_FLAG_DISABLE_BEACON_HINTS         = BIT(2),
+       /* use hole at 0 */
+       /* use hole at 1 */
+       /* use hole at 2 */
        WIPHY_FLAG_NETNS_OK                     = BIT(3),
        WIPHY_FLAG_PS_ON_BY_DEFAULT             = BIT(4),
        WIPHY_FLAG_4ADDR_AP                     = BIT(5),
@@ -2721,6 +2721,8 @@ struct wiphy_coalesce_support {
  * @software_iftypes: bitmask of software interface types, these are not
  *     subject to any restrictions since they are purely managed in SW.
  * @flags: wiphy flags, see &enum wiphy_flags
+ * @regulatory_flags: wiphy regulatory flags, see
+ *     &enum ieee80211_regulatory_flags
  * @features: features advertised to nl80211, see &enum nl80211_feature_flags.
  * @bss_priv_size: each BSS struct has private data allocated with it,
  *     this variable determines its size
@@ -2809,7 +2811,7 @@ struct wiphy {
 
        u16 max_acl_mac_addrs;
 
-       u32 flags, features;
+       u32 flags, regulatory_flags, features;
 
        u32 ap_sme_capa;
 
@@ -3472,6 +3474,9 @@ int regulatory_hint(struct wiphy *wiphy, const char *alpha2);
  * custom regulatory domain will be trusted completely and as such previous
  * default channel settings will be disregarded. If no rule is found for a
  * channel on the regulatory domain the channel will be disabled.
+ * Drivers using this for a wiphy should also set the wiphy flag
+ * WIPHY_FLAG_CUSTOM_REGULATORY or cfg80211 will set it for the wiphy
+ * that called this helper.
  */
 void wiphy_apply_custom_regulatory(struct wiphy *wiphy,
                                   const struct ieee80211_regdomain *regd);
@@ -4146,6 +4151,7 @@ void cfg80211_radar_event(struct wiphy *wiphy,
 /**
  * cfg80211_cac_event - Channel availability check (CAC) event
  * @netdev: network device
+ * @chandef: chandef for the current channel
  * @event: type of event
  * @gfp: context flags
  *
@@ -4154,6 +4160,7 @@ void cfg80211_radar_event(struct wiphy *wiphy,
  * also by full-MAC drivers.
  */
 void cfg80211_cac_event(struct net_device *netdev,
+                       const struct cfg80211_chan_def *chandef,
                        enum nl80211_radar_event event, gfp_t gfp);
 
 
@@ -4279,7 +4286,8 @@ bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
  * @dev: the device which switched channels
  * @chandef: the new channel definition
  *
- * Acquires wdev_lock, so must only be called from sleepable driver context!
+ * Caller must acquire wdev_lock, therefore must only be called from sleepable
+ * driver context!
  */
 void cfg80211_ch_switch_notify(struct net_device *dev,
                               struct cfg80211_chan_def *chandef);
index 7ceed99a05bc79218a841352a454a980df48741b..3cd408b326de7400b00e6284be2524955beefe27 100644 (file)
@@ -154,12 +154,14 @@ struct ieee80211_low_level_stats {
  * @IEEE80211_CHANCTX_CHANGE_RADAR: radar detection flag changed
  * @IEEE80211_CHANCTX_CHANGE_CHANNEL: switched to another operating channel,
  *     this is used only with channel switching with CSA
+ * @IEEE80211_CHANCTX_CHANGE_MIN_WIDTH: The min required channel width changed
  */
 enum ieee80211_chanctx_change {
        IEEE80211_CHANCTX_CHANGE_WIDTH          = BIT(0),
        IEEE80211_CHANCTX_CHANGE_RX_CHAINS      = BIT(1),
        IEEE80211_CHANCTX_CHANGE_RADAR          = BIT(2),
        IEEE80211_CHANCTX_CHANGE_CHANNEL        = BIT(3),
+       IEEE80211_CHANCTX_CHANGE_MIN_WIDTH      = BIT(4),
 };
 
 /**
@@ -169,6 +171,7 @@ enum ieee80211_chanctx_change {
  * that contains it is visible in mac80211 only.
  *
  * @def: the channel definition
+ * @min_def: the minimum channel definition currently required.
  * @rx_chains_static: The number of RX chains that must always be
  *     active on the channel to receive MIMO transmissions
  * @rx_chains_dynamic: The number of RX chains that must be enabled
@@ -180,6 +183,7 @@ enum ieee80211_chanctx_change {
  */
 struct ieee80211_chanctx_conf {
        struct cfg80211_chan_def def;
+       struct cfg80211_chan_def min_def;
 
        u8 rx_chains_static, rx_chains_dynamic;
 
@@ -1228,6 +1232,36 @@ struct ieee80211_key_conf {
        u8 key[0];
 };
 
+/**
+ * struct ieee80211_cipher_scheme - cipher scheme
+ *
+ * This structure contains a cipher scheme information defining
+ * the secure packet crypto handling.
+ *
+ * @cipher: a cipher suite selector
+ * @iftype: a cipher iftype bit mask indicating an allowed cipher usage
+ * @hdr_len: a length of a security header used the cipher
+ * @pn_len: a length of a packet number in the security header
+ * @pn_off: an offset of pn from the beginning of the security header
+ * @key_idx_off: an offset of key index byte in the security header
+ * @key_idx_mask: a bit mask of key_idx bits
+ * @key_idx_shift: a bit shift needed to get key_idx
+ *     key_idx value calculation:
+ *      (sec_header_base[key_idx_off] & key_idx_mask) >> key_idx_shift
+ * @mic_len: a mic length in bytes
+ */
+struct ieee80211_cipher_scheme {
+       u32 cipher;
+       u16 iftype;
+       u8 hdr_len;
+       u8 pn_len;
+       u8 pn_off;
+       u8 key_idx_off;
+       u8 key_idx_mask;
+       u8 key_idx_shift;
+       u8 mic_len;
+};
+
 /**
  * enum set_key_cmd - key command
  *
@@ -1636,6 +1670,10 @@ enum ieee80211_hw_flags {
  * @uapsd_max_sp_len: maximum number of total buffered frames the WMM AP may
  *     deliver to a WMM STA during any Service Period triggered by the WMM STA.
  *     Use IEEE80211_WMM_IE_STA_QOSINFO_SP_* for correct values.
+ *
+ * @n_cipher_schemes: a size of an array of cipher schemes definitions.
+ * @cipher_schemes: a pointer to an array of cipher scheme definitions
+ *     supported by HW.
  */
 struct ieee80211_hw {
        struct ieee80211_conf conf;
@@ -1663,6 +1701,8 @@ struct ieee80211_hw {
        netdev_features_t netdev_features;
        u8 uapsd_queues;
        u8 uapsd_max_sp_len;
+       u8 n_cipher_schemes;
+       const struct ieee80211_cipher_scheme *cipher_schemes;
 };
 
 /**
index f17ed590d64a35b314c8c9c42dc7dc153e0f1619..c96a0b86f342cc1093dee253f070f9ff225b0ba6 100644 (file)
@@ -38,17 +38,17 @@ enum environment_cap {
  *
  * @rcu_head: RCU head struct used to free the request
  * @wiphy_idx: this is set if this request's initiator is
- *     %REGDOM_SET_BY_COUNTRY_IE or %REGDOM_SET_BY_DRIVER. This
- *     can be used by the wireless core to deal with conflicts
- *     and potentially inform users of which devices specifically
- *     cased the conflicts.
+ *     %REGDOM_SET_BY_COUNTRY_IE or %REGDOM_SET_BY_DRIVER. This
+ *     can be used by the wireless core to deal with conflicts
+ *     and potentially inform users of which devices specifically
+ *     cased the conflicts.
  * @initiator: indicates who sent this request, could be any of
- *     of those set in nl80211_reg_initiator (%NL80211_REGDOM_SET_BY_*)
+ *     of those set in nl80211_reg_initiator (%NL80211_REGDOM_SET_BY_*)
  * @alpha2: the ISO / IEC 3166 alpha2 country code of the requested
- *     regulatory domain. We have a few special codes:
- *     00 - World regulatory domain
- *     99 - built by driver but a specific alpha2 cannot be determined
- *     98 - result of an intersection between two regulatory domains
+ *     regulatory domain. We have a few special codes:
+ *     00 - World regulatory domain
+ *     99 - built by driver but a specific alpha2 cannot be determined
+ *     98 - result of an intersection between two regulatory domains
  *     97 - regulatory domain has not yet been configured
  * @dfs_region: If CRDA responded with a regulatory domain that requires
  *     DFS master operation on a known DFS region (NL80211_DFS_*),
@@ -59,8 +59,8 @@ enum environment_cap {
  *     of hint passed. This could be any of the %NL80211_USER_REG_HINT_*
  *     types.
  * @intersect: indicates whether the wireless core should intersect
- *     the requested regulatory domain with the presently set regulatory
- *     domain.
+ *     the requested regulatory domain with the presently set regulatory
+ *     domain.
  * @processed: indicates whether or not this requests has already been
  *     processed. When the last request is processed it means that the
  *     currently regulatory domain set on cfg80211 is updated from
@@ -68,9 +68,9 @@ enum environment_cap {
  *     the last request is not yet processed we must yield until it
  *     is processed before processing any new requests.
  * @country_ie_checksum: checksum of the last processed and accepted
- *     country IE
+ *     country IE
  * @country_ie_env: lets us know if the AP is telling us we are outdoor,
- *     indoor, or if it doesn't matter
+ *     indoor, or if it doesn't matter
  * @list: used to insert into the reg_requests_list linked list
  */
 struct regulatory_request {
@@ -79,13 +79,63 @@ struct regulatory_request {
        enum nl80211_reg_initiator initiator;
        enum nl80211_user_reg_hint_type user_reg_hint_type;
        char alpha2[2];
-       u8 dfs_region;
+       enum nl80211_dfs_regions dfs_region;
        bool intersect;
        bool processed;
        enum environment_cap country_ie_env;
        struct list_head list;
 };
 
+/**
+ * enum ieee80211_regulatory_flags - device regulatory flags
+ *
+ * @REGULATORY_CUSTOM_REG: tells us the driver for this device
+ *     has its own custom regulatory domain and cannot identify the
+ *     ISO / IEC 3166 alpha2 it belongs to. When this is enabled
+ *     we will disregard the first regulatory hint (when the
+ *     initiator is %REGDOM_SET_BY_CORE). Drivers that use
+ *     wiphy_apply_custom_regulatory() should have this flag set
+ *     or the regulatory core will set it for the wiphy.
+ * @REGULATORY_STRICT_REG: tells us that the wiphy for this device
+ *     has regulatory domain that it wishes to be considered as the
+ *     superset for regulatory rules. After this device gets its regulatory
+ *     domain programmed further regulatory hints shall only be considered
+ *     for this device to enhance regulatory compliance, forcing the
+ *     device to only possibly use subsets of the original regulatory
+ *     rules. For example if channel 13 and 14 are disabled by this
+ *     device's regulatory domain no user specified regulatory hint which
+ *     has these channels enabled would enable them for this wiphy,
+ *     the device's original regulatory domain will be trusted as the
+ *     base. You can program the superset of regulatory rules for this
+ *     wiphy with regulatory_hint() for cards programmed with an
+ *     ISO3166-alpha2 country code. wiphys that use regulatory_hint()
+ *     will have their wiphy->regd programmed once the regulatory
+ *     domain is set, and all other regulatory hints will be ignored
+ *     until their own regulatory domain gets programmed.
+ * @REGULATORY_DISABLE_BEACON_HINTS: enable this if your driver needs to
+ *     ensure that passive scan flags and beaconing flags may not be lifted by
+ *     cfg80211 due to regulatory beacon hints. For more information on beacon
+ *     hints read the documenation for regulatory_hint_found_beacon()
+ * @REGULATORY_COUNTRY_IE_FOLLOW_POWER:  for devices that have a preference
+ *     that even though they may have programmed their own custom power
+ *     setting prior to wiphy registration, they want to ensure their channel
+ *     power settings are updated for this connection with the power settings
+ *     derived from the regulatory domain. The regulatory domain used will be
+ *     based on the ISO3166-alpha2 from country IE provided through
+ *     regulatory_hint_country_ie()
+ * @REGULATORY_COUNTRY_IE_IGNORE: for devices that have a preference to ignore
+ *     all country IE information processed by the regulatory core. This will
+ *     override %REGULATORY_COUNTRY_IE_FOLLOW_POWER as all country IEs will
+ *     be ignored.
+ */
+enum ieee80211_regulatory_flags {
+       REGULATORY_CUSTOM_REG                   = BIT(0),
+       REGULATORY_STRICT_REG                   = BIT(1),
+       REGULATORY_DISABLE_BEACON_HINTS         = BIT(2),
+       REGULATORY_COUNTRY_IE_FOLLOW_POWER      = BIT(3),
+       REGULATORY_COUNTRY_IE_IGNORE            = BIT(4),
+};
+
 struct ieee80211_freq_range {
        u32 start_freq_khz;
        u32 end_freq_khz;
@@ -107,7 +157,7 @@ struct ieee80211_regdomain {
        struct rcu_head rcu_head;
        u32 n_reg_rules;
        char alpha2[2];
-       u8 dfs_region;
+       enum nl80211_dfs_regions dfs_region;
        struct ieee80211_reg_rule reg_rules[];
 };
 
index f752e9821e717ee68066f4d8467775a8bee2fd78..129b7b08714848279f3638019892a4dc0e9e6d65 100644 (file)
  *     operation, %NL80211_ATTR_MAC contains the peer MAC address, and
  *     %NL80211_ATTR_REASON_CODE the reason code to be used (only with
  *     %NL80211_TDLS_TEARDOWN).
- * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame.
+ * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame. The
+ *     %NL80211_ATTR_TDLS_ACTION attribute determines the type of frame to be
+ *     sent. Public Action codes (802.11-2012 8.1.5.1) will be sent as
+ *     802.11 management frames, while TDLS action codes (802.11-2012
+ *     8.5.13.1) will be encapsulated and sent as data frames. The currently
+ *     supported Public Action code is %WLAN_PUB_ACTION_TDLS_DISCOVER_RES
+ *     and the currently supported TDLS actions codes are given in
+ *     &enum ieee80211_tdls_actioncode.
  *
  * @NL80211_CMD_UNEXPECTED_FRAME: Used by an application controlling an AP
  *     (or GO) interface (i.e. hostapd) to ask for unexpected frames to
@@ -1508,6 +1515,11 @@ enum nl80211_commands {
  *     to react to radar events, e.g. initiate a channel switch or leave the
  *     IBSS network.
  *
+ * @NL80211_ATTR_SUPPORT_5_MHZ: A flag indicating that the device supports
+ *     5 MHz channel bandwidth.
+ * @NL80211_ATTR_SUPPORT_10_MHZ: A flag indicating that the device supports
+ *     10 MHz channel bandwidth.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1824,6 +1836,9 @@ enum nl80211_attrs {
 
        NL80211_ATTR_HANDLE_DFS,
 
+       NL80211_ATTR_SUPPORT_5_MHZ,
+       NL80211_ATTR_SUPPORT_10_MHZ,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
@@ -2224,10 +2239,9 @@ enum nl80211_band_attr {
  * @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz
  * @NL80211_FREQUENCY_ATTR_DISABLED: Channel is disabled in current
  *     regulatory domain.
- * @NL80211_FREQUENCY_ATTR_PASSIVE_SCAN: Only passive scanning is
- *     permitted on this channel in current regulatory domain.
- * @NL80211_FREQUENCY_ATTR_NO_IBSS: IBSS networks are not permitted
- *     on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_NO_IR: no mechanisms that initiate radiation
+ *     are permitted on this channel, this includes sending probe
+ *     requests, or modes of operation that require beaconing.
  * @NL80211_FREQUENCY_ATTR_RADAR: Radar detection is mandatory
  *     on this channel in current regulatory domain.
  * @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm
@@ -2254,8 +2268,8 @@ enum nl80211_frequency_attr {
        __NL80211_FREQUENCY_ATTR_INVALID,
        NL80211_FREQUENCY_ATTR_FREQ,
        NL80211_FREQUENCY_ATTR_DISABLED,
-       NL80211_FREQUENCY_ATTR_PASSIVE_SCAN,
-       NL80211_FREQUENCY_ATTR_NO_IBSS,
+       NL80211_FREQUENCY_ATTR_NO_IR,
+       __NL80211_FREQUENCY_ATTR_NO_IBSS,
        NL80211_FREQUENCY_ATTR_RADAR,
        NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
        NL80211_FREQUENCY_ATTR_DFS_STATE,
@@ -2271,6 +2285,9 @@ enum nl80211_frequency_attr {
 };
 
 #define NL80211_FREQUENCY_ATTR_MAX_TX_POWER NL80211_FREQUENCY_ATTR_MAX_TX_POWER
+#define NL80211_FREQUENCY_ATTR_PASSIVE_SCAN    NL80211_FREQUENCY_ATTR_NO_IR
+#define NL80211_FREQUENCY_ATTR_NO_IBSS         NL80211_FREQUENCY_ATTR_NO_IR
+#define NL80211_FREQUENCY_ATTR_NO_IR           NL80211_FREQUENCY_ATTR_NO_IR
 
 /**
  * enum nl80211_bitrate_attr - bitrate attributes
@@ -2413,8 +2430,9 @@ enum nl80211_sched_scan_match_attr {
  * @NL80211_RRF_DFS: DFS support is required to be used
  * @NL80211_RRF_PTP_ONLY: this is only for Point To Point links
  * @NL80211_RRF_PTMP_ONLY: this is only for Point To Multi Point links
- * @NL80211_RRF_PASSIVE_SCAN: passive scan is required
- * @NL80211_RRF_NO_IBSS: no IBSS is allowed
+ * @NL80211_RRF_NO_IR: no mechanisms that initiate radiation are allowed,
+ *     this includes probe requests or modes of operation that require
+ *     beaconing.
  */
 enum nl80211_reg_rule_flags {
        NL80211_RRF_NO_OFDM             = 1<<0,
@@ -2424,10 +2442,17 @@ enum nl80211_reg_rule_flags {
        NL80211_RRF_DFS                 = 1<<4,
        NL80211_RRF_PTP_ONLY            = 1<<5,
        NL80211_RRF_PTMP_ONLY           = 1<<6,
-       NL80211_RRF_PASSIVE_SCAN        = 1<<7,
-       NL80211_RRF_NO_IBSS             = 1<<8,
+       NL80211_RRF_NO_IR               = 1<<7,
+       __NL80211_RRF_NO_IBSS           = 1<<8,
 };
 
+#define NL80211_RRF_PASSIVE_SCAN       NL80211_RRF_NO_IR
+#define NL80211_RRF_NO_IBSS            NL80211_RRF_NO_IR
+#define NL80211_RRF_NO_IR              NL80211_RRF_NO_IR
+
+/* For backport compatibility with older userspace */
+#define NL80211_RRF_NO_IR_ALL          (NL80211_RRF_NO_IR | __NL80211_RRF_NO_IBSS)
+
 /**
  * enum nl80211_dfs_regions - regulatory DFS regions
  *
index 95667b088c5b73cd0e95e8c1753ed76acec9dca0..754069cbb7568474c7bd87060613ec12facf6d9a 100644 (file)
@@ -133,7 +133,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
                             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;
 
@@ -145,22 +147,28 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
        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))
@@ -216,10 +224,13 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
                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;
 }
@@ -244,7 +255,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
                        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
@@ -291,7 +302,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
                        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
@@ -521,8 +532,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
                                 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;
@@ -846,7 +857,7 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
        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)
@@ -870,7 +881,8 @@ int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
        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)
@@ -947,7 +959,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
                      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;
 
@@ -968,11 +980,19 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
         */
        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;
@@ -1001,7 +1021,8 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
 
        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);
@@ -1032,7 +1053,7 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev,
        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;
 
@@ -1050,15 +1071,18 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
        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 */
@@ -1091,8 +1115,10 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
        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);
        }
 
@@ -1953,7 +1979,7 @@ static int ieee80211_change_bss(struct wiphy *wiphy,
        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);
@@ -2964,27 +2990,33 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
        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;
@@ -2998,20 +3030,22 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
        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,
@@ -3024,6 +3058,8 @@ 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;
 
@@ -3136,7 +3172,7 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
                                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);
@@ -3146,26 +3182,25 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 }
 
 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) {
@@ -3213,7 +3248,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
        /* 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);
@@ -3226,8 +3261,10 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
                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;
@@ -3237,19 +3274,19 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
                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;
 
@@ -3269,8 +3306,8 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
                        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);
index 03ba6b5c5373b373d47956518fafeaf1338b2ad0..a57d5d9466bcbca1c8aa05276502ede6987783e7 100644 (file)
@@ -9,6 +9,140 @@
 #include "ieee80211_i.h"
 #include "driver-ops.h"
 
+static enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta)
+{
+       switch (sta->bandwidth) {
+       case IEEE80211_STA_RX_BW_20:
+               if (sta->ht_cap.ht_supported)
+                       return NL80211_CHAN_WIDTH_20;
+               else
+                       return NL80211_CHAN_WIDTH_20_NOHT;
+       case IEEE80211_STA_RX_BW_40:
+               return NL80211_CHAN_WIDTH_40;
+       case IEEE80211_STA_RX_BW_80:
+               return NL80211_CHAN_WIDTH_80;
+       case IEEE80211_STA_RX_BW_160:
+               /*
+                * This applied for both 160 and 80+80. since we use
+                * the returned value to consider degradation of
+                * ctx->conf.min_def, we have to make sure to take
+                * the bigger one (NL80211_CHAN_WIDTH_160).
+                * Otherwise we might try degrading even when not
+                * needed, as the max required sta_bw returned (80+80)
+                * might be smaller than the configured bw (160).
+                */
+               return NL80211_CHAN_WIDTH_160;
+       default:
+               WARN_ON(1);
+               return NL80211_CHAN_WIDTH_20;
+       }
+}
+
+static enum nl80211_chan_width
+ieee80211_get_max_required_bw(struct ieee80211_sub_if_data *sdata)
+{
+       enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT;
+       struct sta_info *sta;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(sta, &sdata->local->sta_list, list) {
+               if (sdata != sta->sdata &&
+                   !(sta->sdata->bss && sta->sdata->bss == sdata->bss))
+                       continue;
+
+               if (!sta->uploaded)
+                       continue;
+
+               max_bw = max(max_bw, ieee80211_get_sta_bw(&sta->sta));
+       }
+       rcu_read_unlock();
+
+       return max_bw;
+}
+
+static enum nl80211_chan_width
+ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local,
+                                     struct ieee80211_chanctx_conf *conf)
+{
+       struct ieee80211_sub_if_data *sdata;
+       enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+               struct ieee80211_vif *vif = &sdata->vif;
+               enum nl80211_chan_width width = NL80211_CHAN_WIDTH_20_NOHT;
+
+               if (!ieee80211_sdata_running(sdata))
+                       continue;
+
+               if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf)
+                       continue;
+
+               switch (vif->type) {
+               case NL80211_IFTYPE_AP:
+               case NL80211_IFTYPE_AP_VLAN:
+                       width = ieee80211_get_max_required_bw(sdata);
+                       break;
+               case NL80211_IFTYPE_P2P_DEVICE:
+                       continue;
+               case NL80211_IFTYPE_STATION:
+               case NL80211_IFTYPE_ADHOC:
+               case NL80211_IFTYPE_WDS:
+               case NL80211_IFTYPE_MESH_POINT:
+                       width = vif->bss_conf.chandef.width;
+                       break;
+               case NL80211_IFTYPE_UNSPECIFIED:
+               case NUM_NL80211_IFTYPES:
+               case NL80211_IFTYPE_MONITOR:
+               case NL80211_IFTYPE_P2P_CLIENT:
+               case NL80211_IFTYPE_P2P_GO:
+                       WARN_ON_ONCE(1);
+               }
+               max_bw = max(max_bw, width);
+       }
+       rcu_read_unlock();
+
+       return max_bw;
+}
+
+/*
+ * recalc the min required chan width of the channel context, which is
+ * the max of min required widths of all the interfaces bound to this
+ * channel context.
+ */
+void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
+                                     struct ieee80211_chanctx *ctx)
+{
+       enum nl80211_chan_width max_bw;
+       struct cfg80211_chan_def min_def;
+
+       lockdep_assert_held(&local->chanctx_mtx);
+
+       /* don't optimize 5MHz, 10MHz, and radar_enabled confs */
+       if (ctx->conf.def.width == NL80211_CHAN_WIDTH_5 ||
+           ctx->conf.def.width == NL80211_CHAN_WIDTH_10 ||
+           ctx->conf.radar_enabled) {
+               ctx->conf.min_def = ctx->conf.def;
+               return;
+       }
+
+       max_bw = ieee80211_get_chanctx_max_required_bw(local, &ctx->conf);
+
+       /* downgrade chandef up to max_bw */
+       min_def = ctx->conf.def;
+       while (min_def.width > max_bw)
+               ieee80211_chandef_downgrade(&min_def);
+
+       if (cfg80211_chandef_identical(&ctx->conf.min_def, &min_def))
+               return;
+
+       ctx->conf.min_def = min_def;
+       if (!ctx->driver_present)
+               return;
+
+       drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_MIN_WIDTH);
+}
+
 static void ieee80211_change_chanctx(struct ieee80211_local *local,
                                     struct ieee80211_chanctx *ctx,
                                     const struct cfg80211_chan_def *chandef)
@@ -20,6 +154,7 @@ static void ieee80211_change_chanctx(struct ieee80211_local *local,
 
        ctx->conf.def = *chandef;
        drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_WIDTH);
+       ieee80211_recalc_chanctx_min_def(local, ctx);
 
        if (!local->use_chanctx) {
                local->_oper_chandef = *chandef;
@@ -93,6 +228,7 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
        ctx->conf.rx_chains_dynamic = 1;
        ctx->mode = mode;
        ctx->conf.radar_enabled = ieee80211_is_radar_required(local);
+       ieee80211_recalc_chanctx_min_def(local, ctx);
        if (!local->use_chanctx)
                local->hw.conf.radar_enabled = ctx->conf.radar_enabled;
 
@@ -179,6 +315,7 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
        ctx->refcount++;
 
        ieee80211_recalc_txpower(sdata);
+       ieee80211_recalc_chanctx_min_def(local, ctx);
        sdata->vif.bss_conf.idle = false;
 
        if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
@@ -243,6 +380,7 @@ static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
                ieee80211_recalc_chanctx_chantype(sdata->local, ctx);
                ieee80211_recalc_smps_chanctx(local, ctx);
                ieee80211_recalc_radar_chanctx(local, ctx);
+               ieee80211_recalc_chanctx_min_def(local, ctx);
        }
 }
 
@@ -411,12 +549,12 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
 }
 
 int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
-                                const struct cfg80211_chan_def *chandef,
                                 u32 *changed)
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_chanctx_conf *conf;
        struct ieee80211_chanctx *ctx;
+       const struct cfg80211_chan_def *chandef = &sdata->csa_chandef;
        int ret;
        u32 chanctx_changed = 0;
 
@@ -456,6 +594,7 @@ int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
        ieee80211_recalc_chanctx_chantype(local, ctx);
        ieee80211_recalc_smps_chanctx(local, ctx);
        ieee80211_recalc_radar_chanctx(local, ctx);
+       ieee80211_recalc_chanctx_min_def(local, ctx);
 
        ret = 0;
  out:
index 5c090e41d9bbf1ea379307c8ecd6a648cb33f0ac..fa16e54980a1d3e76ce2f85fcb3253eb2599e838 100644 (file)
 
 #define DEBUGFS_FORMAT_BUFFER_SIZE 100
 
+#define TX_LATENCY_BIN_DELIMTER_C ','
+#define TX_LATENCY_BIN_DELIMTER_S ","
+#define TX_LATENCY_BINS_DISABLED "enable(bins disabled)\n"
+#define TX_LATENCY_DISABLED "disable\n"
+
+
+/*
+ * Display if Tx latency statistics & bins are enabled/disabled
+ */
+static ssize_t sta_tx_latency_stat_read(struct file *file,
+                                       char __user *userbuf,
+                                       size_t count, loff_t *ppos)
+{
+       struct ieee80211_local *local = file->private_data;
+       struct ieee80211_tx_latency_bin_ranges  *tx_latency;
+       char *buf;
+       int bufsz, i, ret;
+       int pos = 0;
+
+       rcu_read_lock();
+
+       tx_latency = rcu_dereference(local->tx_latency);
+
+       if (tx_latency && tx_latency->n_ranges) {
+               bufsz = tx_latency->n_ranges * 15;
+               buf = kzalloc(bufsz, GFP_ATOMIC);
+               if (!buf)
+                       goto err;
+
+               for (i = 0; i < tx_latency->n_ranges; i++)
+                       pos += scnprintf(buf + pos, bufsz - pos, "%d,",
+                                        tx_latency->ranges[i]);
+               pos += scnprintf(buf + pos, bufsz - pos, "\n");
+       } else if (tx_latency) {
+               bufsz = sizeof(TX_LATENCY_BINS_DISABLED) + 1;
+               buf = kzalloc(bufsz, GFP_ATOMIC);
+               if (!buf)
+                       goto err;
+
+               pos += scnprintf(buf + pos, bufsz - pos, "%s\n",
+                                TX_LATENCY_BINS_DISABLED);
+       } else {
+               bufsz = sizeof(TX_LATENCY_DISABLED) + 1;
+               buf = kzalloc(bufsz, GFP_ATOMIC);
+               if (!buf)
+                       goto err;
+
+               pos += scnprintf(buf + pos, bufsz - pos, "%s\n",
+                                TX_LATENCY_DISABLED);
+       }
+
+       rcu_read_unlock();
+
+       ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+       kfree(buf);
+
+       return ret;
+err:
+       rcu_read_unlock();
+       return -ENOMEM;
+}
+
+/*
+ * Receive input from user regarding Tx latency statistics
+ * The input should indicate if Tx latency statistics and bins are
+ * enabled/disabled.
+ * If bins are enabled input should indicate the amount of different bins and
+ * their ranges. Each bin will count how many Tx frames transmitted within the
+ * appropriate latency.
+ * Legal input is:
+ * a) "enable(bins disabled)" - to enable only general statistics
+ * b) "a,b,c,d,...z" - to enable general statistics and bins, where all are
+ * numbers and a < b < c < d.. < z
+ * c) "disable" - disable all statistics
+ * NOTE: must configure Tx latency statistics bins before stations connected.
+ */
+
+static ssize_t sta_tx_latency_stat_write(struct file *file,
+                                        const char __user *userbuf,
+                                        size_t count, loff_t *ppos)
+{
+       struct ieee80211_local *local = file->private_data;
+       char buf[128] = {};
+       char *bins = buf;
+       char *token;
+       int buf_size, i, alloc_size;
+       int prev_bin = 0;
+       int n_ranges = 0;
+       int ret = count;
+       struct ieee80211_tx_latency_bin_ranges  *tx_latency;
+
+       if (sizeof(buf) <= count)
+               return -EINVAL;
+       buf_size = count;
+       if (copy_from_user(buf, userbuf, buf_size))
+               return -EFAULT;
+
+       mutex_lock(&local->sta_mtx);
+
+       /* cannot change config once we have stations */
+       if (local->num_sta)
+               goto unlock;
+
+       tx_latency =
+               rcu_dereference_protected(local->tx_latency,
+                                         lockdep_is_held(&local->sta_mtx));
+
+       /* disable Tx statistics */
+       if (!strcmp(buf, TX_LATENCY_DISABLED)) {
+               if (!tx_latency)
+                       goto unlock;
+               rcu_assign_pointer(local->tx_latency, NULL);
+               synchronize_rcu();
+               kfree(tx_latency);
+               goto unlock;
+       }
+
+       /* Tx latency already enabled */
+       if (tx_latency)
+               goto unlock;
+
+       if (strcmp(TX_LATENCY_BINS_DISABLED, buf)) {
+               /* check how many bins and between what ranges user requested */
+               token = buf;
+               while (*token != '\0') {
+                       if (*token == TX_LATENCY_BIN_DELIMTER_C)
+                               n_ranges++;
+                       token++;
+               }
+               n_ranges++;
+       }
+
+       alloc_size = sizeof(struct ieee80211_tx_latency_bin_ranges) +
+                    n_ranges * sizeof(u32);
+       tx_latency = kzalloc(alloc_size, GFP_ATOMIC);
+       if (!tx_latency) {
+               ret = -ENOMEM;
+               goto unlock;
+       }
+       tx_latency->n_ranges = n_ranges;
+       for (i = 0; i < n_ranges; i++) { /* setting bin ranges */
+               token = strsep(&bins, TX_LATENCY_BIN_DELIMTER_S);
+               sscanf(token, "%d", &tx_latency->ranges[i]);
+               /* bins values should be in ascending order */
+               if (prev_bin >= tx_latency->ranges[i]) {
+                       ret = -EINVAL;
+                       kfree(tx_latency);
+                       goto unlock;
+               }
+               prev_bin = tx_latency->ranges[i];
+       }
+       rcu_assign_pointer(local->tx_latency, tx_latency);
+
+unlock:
+       mutex_unlock(&local->sta_mtx);
+
+       return ret;
+}
+
+static const struct file_operations stats_tx_latency_ops = {
+       .write = sta_tx_latency_stat_write,
+       .read = sta_tx_latency_stat_read,
+       .open = simple_open,
+       .llseek = generic_file_llseek,
+};
+
 int mac80211_format_buffer(char __user *userbuf, size_t count,
                                  loff_t *ppos, char *fmt, ...)
 {
@@ -315,4 +481,6 @@ void debugfs_hw_add(struct ieee80211_local *local)
        DEBUGFS_DEVSTATS_ADD(dot11RTSFailureCount);
        DEBUGFS_DEVSTATS_ADD(dot11FCSErrorCount);
        DEBUGFS_DEVSTATS_ADD(dot11RTSSuccessCount);
+
+       DEBUGFS_DEVSTATS_ADD(tx_latency);
 }
index 19c54a44ed4793823713b717a86111d4dda0d57d..80194b557a0cff8f3d2aba52f06cfc348212abf8 100644 (file)
@@ -38,6 +38,13 @@ static const struct file_operations sta_ ##name## _ops = {           \
        .llseek = generic_file_llseek,                                  \
 }
 
+#define STA_OPS_W(name)                                                        \
+static const struct file_operations sta_ ##name## _ops = {             \
+       .write = sta_##name##_write,                                    \
+       .open = simple_open,                                            \
+       .llseek = generic_file_llseek,                                  \
+}
+
 #define STA_OPS_RW(name)                                               \
 static const struct file_operations sta_ ##name## _ops = {             \
        .read = sta_##name##_read,                                      \
@@ -388,6 +395,131 @@ static ssize_t sta_last_rx_rate_read(struct file *file, char __user *userbuf,
 }
 STA_OPS(last_rx_rate);
 
+static int
+sta_tx_latency_stat_header(struct ieee80211_tx_latency_bin_ranges *tx_latency,
+                          char *buf, int pos, int bufsz)
+{
+       int i;
+       int range_count = tx_latency->n_ranges;
+       u32 *bin_ranges = tx_latency->ranges;
+
+       pos += scnprintf(buf + pos, bufsz - pos,
+                         "Station\t\t\tTID\tMax\tAvg");
+       if (range_count) {
+               pos += scnprintf(buf + pos, bufsz - pos,
+                                 "\t<=%d", bin_ranges[0]);
+               for (i = 0; i < range_count - 1; i++)
+                       pos += scnprintf(buf + pos, bufsz - pos, "\t%d-%d",
+                                         bin_ranges[i], bin_ranges[i+1]);
+               pos += scnprintf(buf + pos, bufsz - pos,
+                                 "\t%d<", bin_ranges[range_count - 1]);
+       }
+
+       pos += scnprintf(buf + pos, bufsz - pos, "\n");
+
+       return pos;
+}
+
+static int
+sta_tx_latency_stat_table(struct ieee80211_tx_latency_bin_ranges *tx_lat_range,
+                         struct ieee80211_tx_latency_stat *tx_lat,
+                         char *buf, int pos, int bufsz, int tid)
+{
+       u32 avg = 0;
+       int j;
+       int bin_count = tx_lat->bin_count;
+
+       pos += scnprintf(buf + pos, bufsz - pos, "\t\t\t%d", tid);
+       /* make sure you don't divide in 0 */
+       if (tx_lat->counter)
+               avg = tx_lat->sum / tx_lat->counter;
+
+       pos += scnprintf(buf + pos, bufsz - pos, "\t%d\t%d",
+                         tx_lat->max, avg);
+
+       if (tx_lat_range->n_ranges && tx_lat->bins)
+               for (j = 0; j < bin_count; j++)
+                       pos += scnprintf(buf + pos, bufsz - pos,
+                                         "\t%d", tx_lat->bins[j]);
+       pos += scnprintf(buf + pos, bufsz - pos, "\n");
+
+       return pos;
+}
+
+/*
+ * Output Tx latency statistics station && restart all statistics information
+ */
+static ssize_t sta_tx_latency_stat_read(struct file *file,
+                                       char __user *userbuf,
+                                       size_t count, loff_t *ppos)
+{
+       struct sta_info *sta = file->private_data;
+       struct ieee80211_local *local = sta->local;
+       struct ieee80211_tx_latency_bin_ranges *tx_latency;
+       char *buf;
+       int bufsz, ret, i;
+       int pos = 0;
+
+       bufsz = 20 * IEEE80211_NUM_TIDS *
+               sizeof(struct ieee80211_tx_latency_stat);
+       buf = kzalloc(bufsz, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       rcu_read_lock();
+
+       tx_latency = rcu_dereference(local->tx_latency);
+
+       if (!sta->tx_lat) {
+               pos += scnprintf(buf + pos, bufsz - pos,
+                                "Tx latency statistics are not enabled\n");
+               goto unlock;
+       }
+
+       pos = sta_tx_latency_stat_header(tx_latency, buf, pos, bufsz);
+
+       pos += scnprintf(buf + pos, bufsz - pos, "%pM\n", sta->sta.addr);
+       for (i = 0; i < IEEE80211_NUM_TIDS; i++)
+               pos = sta_tx_latency_stat_table(tx_latency, &sta->tx_lat[i],
+                                               buf, pos, bufsz, i);
+unlock:
+       rcu_read_unlock();
+
+       ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+       kfree(buf);
+
+       return ret;
+}
+STA_OPS(tx_latency_stat);
+
+static ssize_t sta_tx_latency_stat_reset_write(struct file *file,
+                                              const char __user *userbuf,
+                                              size_t count, loff_t *ppos)
+{
+       u32 *bins;
+       int bin_count;
+       struct sta_info *sta = file->private_data;
+       int i;
+
+       if (!sta->tx_lat)
+               return -EINVAL;
+
+       for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
+               bins = sta->tx_lat[i].bins;
+               bin_count = sta->tx_lat[i].bin_count;
+
+               sta->tx_lat[i].max = 0;
+               sta->tx_lat[i].sum = 0;
+               sta->tx_lat[i].counter = 0;
+
+               if (bin_count)
+                       memset(bins, 0, bin_count * sizeof(u32));
+       }
+
+       return count;
+}
+STA_OPS_W(tx_latency_stat_reset);
+
 #define DEBUGFS_ADD(name) \
        debugfs_create_file(#name, 0400, \
                sta->debugfs.dir, sta, &sta_ ##name## _ops);
@@ -441,6 +573,8 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
        DEBUGFS_ADD(last_ack_signal);
        DEBUGFS_ADD(current_tx_rate);
        DEBUGFS_ADD(last_rx_rate);
+       DEBUGFS_ADD(tx_latency_stat);
+       DEBUGFS_ADD(tx_latency_stat_reset);
 
        DEBUGFS_ADD_COUNTER(rx_packets, rx_packets);
        DEBUGFS_ADD_COUNTER(tx_packets, tx_packets);
index 531be040b9ae85972d61bf7df248ae28308d811b..0f1fb5db4bdb6f557007d7883dced071c2032aa8 100644 (file)
@@ -550,12 +550,12 @@ int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata)
                                        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);
@@ -922,7 +922,7 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
                                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 29dc505be125c3c19737f8f6cee911492c52727c..32bae218d6e58b56b802d98955d46fea38935eeb 100644 (file)
@@ -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];
 
@@ -735,6 +736,7 @@ struct ieee80211_sub_if_data {
        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;
@@ -811,6 +813,9 @@ static inline void sdata_unlock(struct ieee80211_sub_if_data *sdata)
        __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)
 {
@@ -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
  *
@@ -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;
 
@@ -1093,7 +1122,6 @@ struct ieee80211_local {
        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;
 
@@ -1692,6 +1720,7 @@ int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata,
 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);
@@ -1730,7 +1759,6 @@ ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
 /* 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);
@@ -1741,6 +1769,8 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
                                   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);
@@ -1749,6 +1779,15 @@ void ieee80211_dfs_radar_detected_work(struct work_struct *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
index ff101ea1d9ae1e208deb5d6fe1d67c1677b398c2..d226751ba63af6c73bf0efcd658465d3aed19b72 100644 (file)
@@ -401,6 +401,8 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
        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);
@@ -749,6 +751,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
        u32 hw_reconf_flags = 0;
        int i, flushed;
        struct ps_data *ps;
+       struct cfg80211_chan_def chandef;
 
        clear_bit(SDATA_STATE_RUNNING, &sdata->state);
 
@@ -823,11 +826,13 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
        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);
        }
 
@@ -1036,7 +1041,6 @@ static void ieee80211_set_multicast_list(struct net_device *dev)
  */
 static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata)
 {
-       int flushed;
        int i;
 
        /* free extra data */
@@ -1050,9 +1054,6 @@ static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata)
 
        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)
@@ -1270,6 +1271,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
 
        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;
 
@@ -1686,6 +1688,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
        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);
 
index 3e51dd7d98b34aad114e6b927beae8e4ecdde9fb..e568d98167d0244e499e53c0b2a3aad1263b1ea0 100644 (file)
@@ -260,25 +260,29 @@ static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
        int idx;
        bool defunikey, defmultikey, defmgmtkey;
 
+       /* caller must provide at least one old/new */
+       if (WARN_ON(!new && !old))
+               return;
+
        if (new)
                list_add_tail(&new->list, &sdata->key_list);
 
-       if (sta && pairwise) {
-               rcu_assign_pointer(sta->ptk, new);
-       } else if (sta) {
-               if (old)
-                       idx = old->conf.keyidx;
-               else
-                       idx = new->conf.keyidx;
-               rcu_assign_pointer(sta->gtk[idx], new);
-       } else {
-               WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx);
+       WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx);
 
-               if (old)
-                       idx = old->conf.keyidx;
-               else
-                       idx = new->conf.keyidx;
+       if (old)
+               idx = old->conf.keyidx;
+       else
+               idx = new->conf.keyidx;
 
+       if (sta) {
+               if (pairwise) {
+                       rcu_assign_pointer(sta->ptk[idx], new);
+                       sta->ptk_idx = idx;
+               } else {
+                       rcu_assign_pointer(sta->gtk[idx], new);
+                       sta->gtk_idx = idx;
+               }
+       } else {
                defunikey = old &&
                        old == key_mtx_dereference(sdata->local,
                                                sdata->default_unicast_key);
@@ -312,9 +316,11 @@ static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
                list_del(&old->list);
 }
 
-struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
-                                         const u8 *key_data,
-                                         size_t seq_len, const u8 *seq)
+struct ieee80211_key *
+ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
+                   const u8 *key_data,
+                   size_t seq_len, const u8 *seq,
+                   const struct ieee80211_cipher_scheme *cs)
 {
        struct ieee80211_key *key;
        int i, j, err;
@@ -393,6 +399,18 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
                        return ERR_PTR(err);
                }
                break;
+       default:
+               if (cs) {
+                       size_t len = (seq_len > MAX_PN_LEN) ?
+                                               MAX_PN_LEN : seq_len;
+
+                       key->conf.iv_len = cs->hdr_len;
+                       key->conf.icv_len = cs->mic_len;
+                       for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++)
+                               for (j = 0; j < len; j++)
+                                       key->u.gen.rx_pn[i][j] =
+                                                       seq[len - j - 1];
+               }
        }
        memcpy(key->conf.key, key_data, key_len);
        INIT_LIST_HEAD(&key->list);
@@ -475,7 +493,7 @@ int ieee80211_key_link(struct ieee80211_key *key,
        mutex_lock(&sdata->local->key_mtx);
 
        if (sta && pairwise)
-               old_key = key_mtx_dereference(sdata->local, sta->ptk);
+               old_key = key_mtx_dereference(sdata->local, sta->ptk[idx]);
        else if (sta)
                old_key = key_mtx_dereference(sdata->local, sta->gtk[idx]);
        else
@@ -625,8 +643,10 @@ void ieee80211_free_sta_keys(struct ieee80211_local *local,
                list_add(&key->list, &keys);
        }
 
-       key = key_mtx_dereference(local, sta->ptk);
-       if (key) {
+       for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
+               key = key_mtx_dereference(local, sta->ptk[i]);
+               if (!key)
+                       continue;
                ieee80211_key_replace(key->sdata, key->sta,
                                key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
                                key, NULL);
@@ -877,7 +897,7 @@ ieee80211_gtk_rekey_add(struct ieee80211_vif *vif,
 
        key = ieee80211_key_alloc(keyconf->cipher, keyconf->keyidx,
                                  keyconf->keylen, keyconf->key,
-                                 0, NULL);
+                                 0, NULL, NULL);
        if (IS_ERR(key))
                return ERR_CAST(key);
 
index aaae0ed3700402433ae56244eb97baa2804aba5b..0aebb889cabae566d6f33e00e59a2f299c9baa69 100644 (file)
@@ -18,6 +18,7 @@
 
 #define NUM_DEFAULT_KEYS 4
 #define NUM_DEFAULT_MGMT_KEYS 2
+#define MAX_PN_LEN 16
 
 struct ieee80211_local;
 struct ieee80211_sub_if_data;
@@ -93,6 +94,10 @@ struct ieee80211_key {
                        u32 replays; /* dot11RSNAStatsCMACReplays */
                        u32 icverrors; /* dot11RSNAStatsCMACICVErrors */
                } aes_cmac;
+               struct {
+                       /* generic cipher scheme */
+                       u8 rx_pn[IEEE80211_NUM_TIDS + 1][MAX_PN_LEN];
+               } gen;
        } u;
 
        /* number of times this key has been used */
@@ -113,9 +118,11 @@ struct ieee80211_key {
        struct ieee80211_key_conf conf;
 };
 
-struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
-                                         const u8 *key_data,
-                                         size_t seq_len, const u8 *seq);
+struct ieee80211_key *
+ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
+                   const u8 *key_data,
+                   size_t seq_len, const u8 *seq,
+                   const struct ieee80211_cipher_scheme *cs);
 /*
  * Insert a key into data structures (sdata, sta if necessary)
  * to make it used, free old key. On failure, also free the new key.
index 21d5d44444d04c82fc73c9fd6dee3f58ab56e512..8af75f0eed6ddd2fd9cbd47cc0dd8ae702f0e567 100644 (file)
@@ -651,15 +651,14 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 }
 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,
@@ -671,6 +670,93 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
                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))
@@ -851,43 +937,12 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        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;
@@ -1087,6 +1142,8 @@ void ieee80211_free_hw(struct ieee80211_hw *hw)
                     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);
index 896fe3bd599e9bedd5db13dbc8ed04ab76e5bd88..330d1f71c0c95380d4adfea250ab0e0bad95c0d8 100644 (file)
@@ -674,8 +674,6 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
        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;
@@ -697,8 +695,7 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
                          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();
@@ -959,7 +956,7 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata,
                                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 2bc7fd2f787dd9546ac616e8c55340e1957eafb1..f39a19f9090fe0d91181b8cb4487dd928232d24b 100644 (file)
@@ -215,8 +215,6 @@ int mesh_rmc_check(struct ieee80211_sub_if_data *sdata,
 bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
                        struct ieee802_11_elems *ie);
 void mesh_ids_set_default(struct ieee80211_if_mesh *mesh);
-void mesh_mgmt_ies_add(struct ieee80211_sub_if_data *sdata,
-                      struct sk_buff *skb);
 int mesh_add_meshconf_ie(struct ieee80211_sub_if_data *sdata,
                         struct sk_buff *skb);
 int mesh_add_meshid_ie(struct ieee80211_sub_if_data *sdata,
@@ -303,8 +301,8 @@ void mesh_mpath_table_grow(void);
 void mesh_mpp_table_grow(void);
 /* Mesh paths */
 int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata,
-                      u8 ttl, const u8 *target, __le32 target_sn,
-                      __le16 target_rcode, const u8 *ra);
+                      u8 ttl, const u8 *target, u32 target_sn,
+                      u16 target_rcode, const u8 *ra);
 void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta);
 void mesh_path_flush_pending(struct mesh_path *mpath);
 void mesh_path_tx_pending(struct mesh_path *mpath);
index 486819cd02cd7d03924e30d4e93f7ac201248b4c..f9514685d45a54802cb0f21dce0953ccbe9b78f4 100644 (file)
@@ -102,12 +102,11 @@ enum mpath_frame_type {
 static const u8 broadcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
 
 static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
-                                 const u8 *orig_addr, __le32 orig_sn,
+                                 const u8 *orig_addr, u32 orig_sn,
                                  u8 target_flags, const u8 *target,
-                                 __le32 target_sn, const u8 *da,
+                                 u32 target_sn, const u8 *da,
                                  u8 hop_count, u8 ttl,
-                                 __le32 lifetime, __le32 metric,
-                                 __le32 preq_id,
+                                 u32 lifetime, u32 metric, u32 preq_id,
                                  struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_local *local = sdata->local;
@@ -167,33 +166,33 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
        if (action == MPATH_PREP) {
                memcpy(pos, target, ETH_ALEN);
                pos += ETH_ALEN;
-               memcpy(pos, &target_sn, 4);
+               put_unaligned_le32(target_sn, pos);
                pos += 4;
        } else {
                if (action == MPATH_PREQ) {
-                       memcpy(pos, &preq_id, 4);
+                       put_unaligned_le32(preq_id, pos);
                        pos += 4;
                }
                memcpy(pos, orig_addr, ETH_ALEN);
                pos += ETH_ALEN;
-               memcpy(pos, &orig_sn, 4);
+               put_unaligned_le32(orig_sn, pos);
                pos += 4;
        }
-       memcpy(pos, &lifetime, 4);      /* interval for RANN */
+       put_unaligned_le32(lifetime, pos); /* interval for RANN */
        pos += 4;
-       memcpy(pos, &metric, 4);
+       put_unaligned_le32(metric, pos);
        pos += 4;
        if (action == MPATH_PREQ) {
                *pos++ = 1; /* destination count */
                *pos++ = target_flags;
                memcpy(pos, target, ETH_ALEN);
                pos += ETH_ALEN;
-               memcpy(pos, &target_sn, 4);
+               put_unaligned_le32(target_sn, pos);
                pos += 4;
        } else if (action == MPATH_PREP) {
                memcpy(pos, orig_addr, ETH_ALEN);
                pos += ETH_ALEN;
-               memcpy(pos, &orig_sn, 4);
+               put_unaligned_le32(orig_sn, pos);
                pos += 4;
        }
 
@@ -239,8 +238,8 @@ static void prepare_frame_for_deferred_tx(struct ieee80211_sub_if_data *sdata,
  * frame directly but add it to the pending queue instead.
  */
 int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata,
-                      u8 ttl, const u8 *target, __le32 target_sn,
-                      __le16 target_rcode, const u8 *ra)
+                      u8 ttl, const u8 *target, u32 target_sn,
+                      u16 target_rcode, const u8 *ra)
 {
        struct ieee80211_local *local = sdata->local;
        struct sk_buff *skb;
@@ -254,13 +253,13 @@ int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata,
                return -EAGAIN;
 
        skb = dev_alloc_skb(local->tx_headroom +
-                           IEEE80211_ENCRYPT_HEADROOM +
+                           sdata->encrypt_headroom +
                            IEEE80211_ENCRYPT_TAILROOM +
                            hdr_len +
                            2 + 15 /* PERR IE */);
        if (!skb)
                return -1;
-       skb_reserve(skb, local->tx_headroom + IEEE80211_ENCRYPT_HEADROOM);
+       skb_reserve(skb, local->tx_headroom + sdata->encrypt_headroom);
        mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len);
        memset(mgmt, 0, hdr_len);
        mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
@@ -293,9 +292,9 @@ int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata,
        pos++;
        memcpy(pos, target, ETH_ALEN);
        pos += ETH_ALEN;
-       memcpy(pos, &target_sn, 4);
+       put_unaligned_le32(target_sn, pos);
        pos += 4;
-       memcpy(pos, &target_rcode, 2);
+       put_unaligned_le16(target_rcode, pos);
 
        /* see note in function header */
        prepare_frame_for_deferred_tx(sdata, skb);
@@ -592,10 +591,9 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
                if (ttl != 0) {
                        mhwmp_dbg(sdata, "replying to the PREQ\n");
                        mesh_path_sel_frame_tx(MPATH_PREP, 0, orig_addr,
-                               cpu_to_le32(orig_sn), 0, target_addr,
-                               cpu_to_le32(target_sn), mgmt->sa, 0, ttl,
-                               cpu_to_le32(lifetime), cpu_to_le32(metric),
-                               0, sdata);
+                                              orig_sn, 0, target_addr,
+                                              target_sn, mgmt->sa, 0, ttl,
+                                              lifetime, metric, 0, sdata);
                } else {
                        ifmsh->mshstats.dropped_frames_ttl++;
                }
@@ -625,11 +623,9 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
                }
 
                mesh_path_sel_frame_tx(MPATH_PREQ, flags, orig_addr,
-                               cpu_to_le32(orig_sn), target_flags, target_addr,
-                               cpu_to_le32(target_sn), da,
-                               hopcount, ttl, cpu_to_le32(lifetime),
-                               cpu_to_le32(metric), cpu_to_le32(preq_id),
-                               sdata);
+                                      orig_sn, target_flags, target_addr,
+                                      target_sn, da, hopcount, ttl, lifetime,
+                                      metric, preq_id, sdata);
                if (!is_multicast_ether_addr(da))
                        ifmsh->mshstats.fwded_unicast++;
                else
@@ -695,11 +691,9 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,
        target_sn = PREP_IE_TARGET_SN(prep_elem);
        orig_sn = PREP_IE_ORIG_SN(prep_elem);
 
-       mesh_path_sel_frame_tx(MPATH_PREP, flags, orig_addr,
-               cpu_to_le32(orig_sn), 0, target_addr,
-               cpu_to_le32(target_sn), next_hop, hopcount,
-               ttl, cpu_to_le32(lifetime), cpu_to_le32(metric),
-               0, sdata);
+       mesh_path_sel_frame_tx(MPATH_PREP, flags, orig_addr, orig_sn, 0,
+                              target_addr, target_sn, next_hop, hopcount,
+                              ttl, lifetime, metric, 0, sdata);
        rcu_read_unlock();
 
        sdata->u.mesh.mshstats.fwded_unicast++;
@@ -750,8 +744,7 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata,
                        if (!ifmsh->mshcfg.dot11MeshForwarding)
                                goto endperr;
                        mesh_path_error_tx(sdata, ttl, target_addr,
-                                          cpu_to_le32(target_sn),
-                                          cpu_to_le16(target_rcode),
+                                          target_sn, target_rcode,
                                           broadcast_addr);
                } else
                        spin_unlock_bh(&mpath->state_lock);
@@ -847,11 +840,9 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
 
        if (ifmsh->mshcfg.dot11MeshForwarding) {
                mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr,
-                                      cpu_to_le32(orig_sn),
-                                      0, NULL, 0, broadcast_addr,
-                                      hopcount, ttl, cpu_to_le32(interval),
-                                      cpu_to_le32(metric + metric_txsta),
-                                      0, sdata);
+                                      orig_sn, 0, NULL, 0, broadcast_addr,
+                                      hopcount, ttl, interval,
+                                      metric + metric_txsta, 0, sdata);
        }
 
        rcu_read_unlock();
@@ -1049,11 +1040,9 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata)
 
        spin_unlock_bh(&mpath->state_lock);
        da = (mpath->is_root) ? mpath->rann_snd_addr : broadcast_addr;
-       mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->vif.addr,
-                       cpu_to_le32(ifmsh->sn), target_flags, mpath->dst,
-                       cpu_to_le32(mpath->sn), da, 0,
-                       ttl, cpu_to_le32(lifetime), 0,
-                       cpu_to_le32(ifmsh->preq_id++), sdata);
+       mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->vif.addr, ifmsh->sn,
+                              target_flags, mpath->dst, mpath->sn, da, 0,
+                              ttl, lifetime, 0, ifmsh->preq_id++, sdata);
        mod_timer(&mpath->timer, jiffies + mpath->discovery_timeout);
 
 enddiscovery:
@@ -1212,10 +1201,9 @@ void mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata)
        switch (ifmsh->mshcfg.dot11MeshHWMPRootMode) {
        case IEEE80211_PROACTIVE_RANN:
                mesh_path_sel_frame_tx(MPATH_RANN, flags, sdata->vif.addr,
-                              cpu_to_le32(++ifmsh->sn),
-                              0, NULL, 0, broadcast_addr,
-                              0, ifmsh->mshcfg.element_ttl,
-                              cpu_to_le32(interval), 0, 0, sdata);
+                                      ++ifmsh->sn, 0, NULL, 0, broadcast_addr,
+                                      0, ifmsh->mshcfg.element_ttl,
+                                      interval, 0, 0, sdata);
                break;
        case IEEE80211_PROACTIVE_PREQ_WITH_PREP:
                flags |= IEEE80211_PREQ_PROACTIVE_PREP_FLAG;
@@ -1224,11 +1212,10 @@ void mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata)
                target_flags |= IEEE80211_PREQ_TO_FLAG |
                                IEEE80211_PREQ_USN_FLAG;
                mesh_path_sel_frame_tx(MPATH_PREQ, flags, sdata->vif.addr,
-                               cpu_to_le32(++ifmsh->sn), target_flags,
-                               (u8 *) broadcast_addr, 0, broadcast_addr,
-                               0, ifmsh->mshcfg.element_ttl,
-                               cpu_to_le32(interval),
-                               0, cpu_to_le32(ifmsh->preq_id++), sdata);
+                                      ++ifmsh->sn, target_flags,
+                                      (u8 *) broadcast_addr, 0, broadcast_addr,
+                                      0, ifmsh->mshcfg.element_ttl, interval,
+                                      0, ifmsh->preq_id++, sdata);
                break;
        default:
                mhwmp_dbg(sdata, "Proactive mechanism not supported\n");
index 89aacfd2756d627287ce4d381e7038d0b0ebdd5e..7d050ed6fe5a4ec879bc9711c088db8360154448 100644 (file)
@@ -722,7 +722,6 @@ void mesh_plink_broken(struct sta_info *sta)
        struct mpath_node *node;
        struct ieee80211_sub_if_data *sdata = sta->sdata;
        int i;
-       __le16 reason = cpu_to_le16(WLAN_REASON_MESH_PATH_DEST_UNREACHABLE);
 
        rcu_read_lock();
        tbl = rcu_dereference(mesh_paths);
@@ -736,9 +735,9 @@ void mesh_plink_broken(struct sta_info *sta)
                        ++mpath->sn;
                        spin_unlock_bh(&mpath->state_lock);
                        mesh_path_error_tx(sdata,
-                                          sdata->u.mesh.mshcfg.element_ttl,
-                                          mpath->dst, cpu_to_le32(mpath->sn),
-                                          reason, bcast);
+                               sdata->u.mesh.mshcfg.element_ttl,
+                               mpath->dst, mpath->sn,
+                               WLAN_REASON_MESH_PATH_DEST_UNREACHABLE, bcast);
                }
        }
        rcu_read_unlock();
index 4301aa5aa227c3d539cd0bf89bdf5b004679976a..cf83217103f9c91479cd4f3f1b97a2752af0c897 100644 (file)
 #define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \
                                jiffies + HZ * t / 1000))
 
-/* We only need a valid sta if user configured a minimum rssi_threshold. */
-#define rssi_threshold_check(sta, sdata) \
-               (sdata->u.mesh.mshcfg.rssi_threshold == 0 ||\
-               (sta && (s8) -ewma_read(&sta->avg_signal) > \
-               sdata->u.mesh.mshcfg.rssi_threshold))
-
 enum plink_event {
        PLINK_UNDEFINED,
        OPN_ACPT,
@@ -61,7 +55,17 @@ static const char * const mplevents[] = {
 
 static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
                               enum ieee80211_self_protected_actioncode action,
-                              u8 *da, __le16 llid, __le16 plid, __le16 reason);
+                              u8 *da, u16 llid, u16 plid, u16 reason);
+
+
+/* We only need a valid sta if user configured a minimum rssi_threshold. */
+static bool rssi_threshold_check(struct ieee80211_sub_if_data *sdata,
+                                struct sta_info *sta)
+{
+       s32 rssi_threshold = sdata->u.mesh.mshcfg.rssi_threshold;
+       return rssi_threshold == 0 ||
+              (sta && (s8) -ewma_read(&sta->avg_signal) > rssi_threshold);
+}
 
 /**
  * mesh_plink_fsm_restart - restart a mesh peer link finite state machine
@@ -242,7 +246,7 @@ u32 mesh_plink_deactivate(struct sta_info *sta)
 
        spin_lock_bh(&sta->lock);
        changed = __mesh_plink_deactivate(sta);
-       sta->reason = cpu_to_le16(WLAN_REASON_MESH_PEER_CANCELED);
+       sta->reason = WLAN_REASON_MESH_PEER_CANCELED;
        mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
                            sta->sta.addr, sta->llid, sta->plid,
                            sta->reason);
@@ -253,7 +257,7 @@ u32 mesh_plink_deactivate(struct sta_info *sta)
 
 static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
                               enum ieee80211_self_protected_actioncode action,
-                              u8 *da, __le16 llid, __le16 plid, __le16 reason)
+                              u8 *da, u16 llid, u16 plid, u16 reason)
 {
        struct ieee80211_local *local = sdata->local;
        struct sk_buff *skb;
@@ -279,7 +283,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
                            2 + 8 + /* peering IE */
                            sdata->u.mesh.ie_len);
        if (!skb)
-               return -1;
+               return err;
        info = IEEE80211_SKB_CB(skb);
        skb_reserve(skb, local->tx_headroom);
        mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len);
@@ -301,7 +305,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
                if (action == WLAN_SP_MESH_PEERING_CONFIRM) {
                        /* AID */
                        pos = skb_put(skb, 2);
-                       memcpy(pos + 2, &plid, 2);
+                       put_unaligned_le16(plid, pos + 2);
                }
                if (ieee80211_add_srates_ie(sdata, skb, true, band) ||
                    ieee80211_add_ext_srates_ie(sdata, skb, true, band) ||
@@ -343,14 +347,14 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
        *pos++ = ie_len;
        memcpy(pos, &peering_proto, 2);
        pos += 2;
-       memcpy(pos, &llid, 2);
+       put_unaligned_le16(llid, pos);
        pos += 2;
        if (include_plid) {
-               memcpy(pos, &plid, 2);
+               put_unaligned_le16(plid, pos);
                pos += 2;
        }
        if (action == WLAN_SP_MESH_PEERING_CLOSE) {
-               memcpy(pos, &reason, 2);
+               put_unaligned_le16(reason, pos);
                pos += 2;
        }
 
@@ -518,7 +522,7 @@ void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata,
            sta->plink_state == NL80211_PLINK_LISTEN &&
            sdata->u.mesh.accepting_plinks &&
            sdata->u.mesh.mshcfg.auto_open_plinks &&
-           rssi_threshold_check(sta, sdata))
+           rssi_threshold_check(sdata, sta))
                changed = mesh_plink_open(sta);
 
        ieee80211_mps_frame_release(sta, elems);
@@ -530,9 +534,10 @@ out:
 static void mesh_plink_timer(unsigned long data)
 {
        struct sta_info *sta;
-       __le16 llid, plid, reason;
+       u16 reason = 0;
        struct ieee80211_sub_if_data *sdata;
        struct mesh_config *mshcfg;
+       enum ieee80211_self_protected_actioncode action = 0;
 
        /*
         * This STA is valid because sta_info_destroy() will
@@ -553,9 +558,6 @@ static void mesh_plink_timer(unsigned long data)
        mpl_dbg(sta->sdata,
                "Mesh plink timer for %pM fired on state %s\n",
                sta->sta.addr, mplstates[sta->plink_state]);
-       reason = 0;
-       llid = sta->llid;
-       plid = sta->plid;
        sdata = sta->sdata;
        mshcfg = &sdata->u.mesh.mshcfg;
 
@@ -574,33 +576,31 @@ static void mesh_plink_timer(unsigned long data)
                                             rand % sta->plink_timeout;
                        ++sta->plink_retries;
                        mod_plink_timer(sta, sta->plink_timeout);
-                       spin_unlock_bh(&sta->lock);
-                       mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN,
-                                           sta->sta.addr, llid, 0, 0);
+                       action = WLAN_SP_MESH_PEERING_OPEN;
                        break;
                }
-               reason = cpu_to_le16(WLAN_REASON_MESH_MAX_RETRIES);
+               reason = WLAN_REASON_MESH_MAX_RETRIES;
                /* fall through on else */
        case NL80211_PLINK_CNF_RCVD:
                /* confirm timer */
                if (!reason)
-                       reason = cpu_to_le16(WLAN_REASON_MESH_CONFIRM_TIMEOUT);
+                       reason = WLAN_REASON_MESH_CONFIRM_TIMEOUT;
                sta->plink_state = NL80211_PLINK_HOLDING;
                mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout);
-               spin_unlock_bh(&sta->lock);
-               mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
-                                   sta->sta.addr, llid, plid, reason);
+               action = WLAN_SP_MESH_PEERING_CLOSE;
                break;
        case NL80211_PLINK_HOLDING:
                /* holding timer */
                del_timer(&sta->plink_timer);
                mesh_plink_fsm_restart(sta);
-               spin_unlock_bh(&sta->lock);
                break;
        default:
-               spin_unlock_bh(&sta->lock);
                break;
        }
+       spin_unlock_bh(&sta->lock);
+       if (action)
+               mesh_plink_frame_tx(sdata, action, sta->sta.addr,
+                                   sta->llid, sta->plid, reason);
 }
 
 static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout)
@@ -612,9 +612,40 @@ static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout)
        add_timer(&sta->plink_timer);
 }
 
+static bool llid_in_use(struct ieee80211_sub_if_data *sdata,
+                       u16 llid)
+{
+       struct ieee80211_local *local = sdata->local;
+       bool in_use = false;
+       struct sta_info *sta;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(sta, &local->sta_list, list) {
+               if (!memcmp(&sta->llid, &llid, sizeof(llid))) {
+                       in_use = true;
+                       break;
+               }
+       }
+       rcu_read_unlock();
+
+       return in_use;
+}
+
+static u16 mesh_get_new_llid(struct ieee80211_sub_if_data *sdata)
+{
+       u16 llid;
+
+       do {
+               get_random_bytes(&llid, sizeof(llid));
+               /* for mesh PS we still only have the AID range for TIM bits */
+               llid = (llid % IEEE80211_MAX_AID) + 1;
+       } while (llid_in_use(sdata, llid));
+
+       return llid;
+}
+
 u32 mesh_plink_open(struct sta_info *sta)
 {
-       __le16 llid;
        struct ieee80211_sub_if_data *sdata = sta->sdata;
        u32 changed;
 
@@ -622,8 +653,7 @@ u32 mesh_plink_open(struct sta_info *sta)
                return 0;
 
        spin_lock_bh(&sta->lock);
-       get_random_bytes(&llid, 2);
-       sta->llid = llid;
+       sta->llid = mesh_get_new_llid(sdata);
        if (sta->plink_state != NL80211_PLINK_LISTEN &&
            sta->plink_state != NL80211_PLINK_BLOCKED) {
                spin_unlock_bh(&sta->lock);
@@ -640,7 +670,7 @@ u32 mesh_plink_open(struct sta_info *sta)
        changed = ieee80211_mps_local_status_update(sdata);
 
        mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN,
-                           sta->sta.addr, llid, 0, 0);
+                           sta->sta.addr, sta->llid, 0, 0);
        return changed;
 }
 
@@ -656,390 +686,147 @@ u32 mesh_plink_block(struct sta_info *sta)
        return changed;
 }
 
-
-void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
-                        struct ieee80211_mgmt *mgmt, size_t len,
-                        struct ieee80211_rx_status *rx_status)
+static void mesh_plink_close(struct ieee80211_sub_if_data *sdata,
+                            struct sta_info *sta,
+                            enum plink_event event)
 {
        struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg;
-       struct ieee802_11_elems elems;
-       struct sta_info *sta;
-       enum plink_event event;
-       enum ieee80211_self_protected_actioncode ftype;
-       size_t baselen;
-       bool matches_local = true;
-       u8 ie_len;
-       u8 *baseaddr;
-       u32 changed = 0;
-       __le16 plid, llid, reason;
-
-       /* need action_code, aux */
-       if (len < IEEE80211_MIN_ACTION_SIZE + 3)
-               return;
-
-       if (sdata->u.mesh.user_mpm)
-               /* userspace must register for these */
-               return;
-
-       if (is_multicast_ether_addr(mgmt->da)) {
-               mpl_dbg(sdata,
-                       "Mesh plink: ignore frame from multicast address\n");
-               return;
-       }
-
-       baseaddr = mgmt->u.action.u.self_prot.variable;
-       baselen = (u8 *) mgmt->u.action.u.self_prot.variable - (u8 *) mgmt;
-       if (mgmt->u.action.u.self_prot.action_code ==
-                                               WLAN_SP_MESH_PEERING_CONFIRM) {
-               baseaddr += 4;
-               baselen += 4;
-       }
-       ieee802_11_parse_elems(baseaddr, len - baselen, true, &elems);
-
-       if (!elems.peering) {
-               mpl_dbg(sdata,
-                       "Mesh plink: missing necessary peer link ie\n");
-               return;
-       }
 
-       if (elems.rsn_len &&
-           sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) {
-               mpl_dbg(sdata,
-                       "Mesh plink: can't establish link with secure peer\n");
-               return;
-       }
+       u16 reason = (event == CLS_ACPT) ?
+                    WLAN_REASON_MESH_CLOSE : WLAN_REASON_MESH_CONFIG;
 
-       ftype = mgmt->u.action.u.self_prot.action_code;
-       ie_len = elems.peering_len;
-       if ((ftype == WLAN_SP_MESH_PEERING_OPEN && ie_len != 4) ||
-           (ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 6) ||
-           (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 6
-                                                       && ie_len != 8)) {
-               mpl_dbg(sdata,
-                       "Mesh plink: incorrect plink ie length %d %d\n",
-                       ftype, ie_len);
-               return;
-       }
-
-       if (ftype != WLAN_SP_MESH_PEERING_CLOSE &&
-           (!elems.mesh_id || !elems.mesh_config)) {
-               mpl_dbg(sdata, "Mesh plink: missing necessary ie\n");
-               return;
-       }
-       /* Note the lines below are correct, the llid in the frame is the plid
-        * from the point of view of this host.
-        */
-       memcpy(&plid, PLINK_GET_LLID(elems.peering), 2);
-       if (ftype == WLAN_SP_MESH_PEERING_CONFIRM ||
-           (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8))
-               memcpy(&llid, PLINK_GET_PLID(elems.peering), 2);
-
-       /* WARNING: Only for sta pointer, is dropped & re-acquired */
-       rcu_read_lock();
-
-       sta = sta_info_get(sdata, mgmt->sa);
-       if (!sta && ftype != WLAN_SP_MESH_PEERING_OPEN) {
-               mpl_dbg(sdata, "Mesh plink: cls or cnf from unknown peer\n");
-               rcu_read_unlock();
-               return;
-       }
-
-       if (ftype == WLAN_SP_MESH_PEERING_OPEN &&
-           !rssi_threshold_check(sta, sdata)) {
-               mpl_dbg(sdata, "Mesh plink: %pM does not meet rssi threshold\n",
-                       mgmt->sa);
-               rcu_read_unlock();
-               return;
-       }
-
-       if (sta && !test_sta_flag(sta, WLAN_STA_AUTH)) {
-               mpl_dbg(sdata, "Mesh plink: Action frame from non-authed peer\n");
-               rcu_read_unlock();
-               return;
-       }
+       sta->reason = reason;
+       sta->plink_state = NL80211_PLINK_HOLDING;
+       mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout);
+}
 
-       if (sta && sta->plink_state == NL80211_PLINK_BLOCKED) {
-               rcu_read_unlock();
-               return;
-       }
+static u32 mesh_plink_establish(struct ieee80211_sub_if_data *sdata,
+                               struct sta_info *sta)
+{
+       struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg;
+       u32 changed = 0;
 
-       /* Now we will figure out the appropriate event... */
-       event = PLINK_UNDEFINED;
-       if (ftype != WLAN_SP_MESH_PEERING_CLOSE &&
-           !mesh_matches_local(sdata, &elems)) {
-               matches_local = false;
-               switch (ftype) {
-               case WLAN_SP_MESH_PEERING_OPEN:
-                       event = OPN_RJCT;
-                       break;
-               case WLAN_SP_MESH_PEERING_CONFIRM:
-                       event = CNF_RJCT;
-                       break;
-               default:
-                       break;
-               }
-       }
+       del_timer(&sta->plink_timer);
+       sta->plink_state = NL80211_PLINK_ESTAB;
+       changed |= mesh_plink_inc_estab_count(sdata);
+       changed |= mesh_set_ht_prot_mode(sdata);
+       changed |= mesh_set_short_slot_time(sdata);
+       mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n", sta->sta.addr);
+       ieee80211_mps_sta_status_update(sta);
+       changed |= ieee80211_mps_set_sta_local_pm(sta, mshcfg->power_mode);
+       return changed;
+}
 
-       if (!sta && !matches_local) {
-               rcu_read_unlock();
-               reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG);
-               llid = 0;
-               mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
-                                   mgmt->sa, llid, plid, reason);
-               return;
-       } else if (!sta) {
-               /* ftype == WLAN_SP_MESH_PEERING_OPEN */
-               if (!mesh_plink_free_count(sdata)) {
-                       mpl_dbg(sdata, "Mesh plink error: no more free plinks\n");
-                       rcu_read_unlock();
-                       return;
-               }
-               event = OPN_ACPT;
-       } else if (matches_local) {
-               switch (ftype) {
-               case WLAN_SP_MESH_PEERING_OPEN:
-                       if (!mesh_plink_free_count(sdata) ||
-                           (sta->plid && sta->plid != plid))
-                               event = OPN_IGNR;
-                       else
-                               event = OPN_ACPT;
-                       break;
-               case WLAN_SP_MESH_PEERING_CONFIRM:
-                       if (!mesh_plink_free_count(sdata) ||
-                           (sta->llid != llid || sta->plid != plid))
-                               event = CNF_IGNR;
-                       else
-                               event = CNF_ACPT;
-                       break;
-               case WLAN_SP_MESH_PEERING_CLOSE:
-                       if (sta->plink_state == NL80211_PLINK_ESTAB)
-                               /* Do not check for llid or plid. This does not
-                                * follow the standard but since multiple plinks
-                                * per sta are not supported, it is necessary in
-                                * order to avoid a livelock when MP A sees an
-                                * establish peer link to MP B but MP B does not
-                                * see it. This can be caused by a timeout in
-                                * B's peer link establishment or B beign
-                                * restarted.
-                                */
-                               event = CLS_ACPT;
-                       else if (sta->plid != plid)
-                               event = CLS_IGNR;
-                       else if (ie_len == 7 && sta->llid != llid)
-                               event = CLS_IGNR;
-                       else
-                               event = CLS_ACPT;
-                       break;
-               default:
-                       mpl_dbg(sdata, "Mesh plink: unknown frame subtype\n");
-                       rcu_read_unlock();
-                       return;
-               }
-       }
+/**
+ * mesh_plink_fsm - step @sta MPM based on @event
+ *
+ * @sdata: interface
+ * @sta: mesh neighbor
+ * @event: peering event
+ *
+ * Return: changed MBSS flags
+ */
+static u32 mesh_plink_fsm(struct ieee80211_sub_if_data *sdata,
+                         struct sta_info *sta, enum plink_event event)
+{
+       struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg;
+       enum ieee80211_self_protected_actioncode action = 0;
+       u32 changed = 0;
 
-       if (event == OPN_ACPT) {
-               rcu_read_unlock();
-               /* allocate sta entry if necessary and update info */
-               sta = mesh_sta_info_get(sdata, mgmt->sa, &elems);
-               if (!sta) {
-                       mpl_dbg(sdata, "Mesh plink: failed to init peer!\n");
-                       rcu_read_unlock();
-                       return;
-               }
-       }
+       mpl_dbg(sdata, "peer %pM in state %s got event %s\n", sta->sta.addr,
+               mplstates[sta->plink_state], mplevents[event]);
 
-       mpl_dbg(sdata, "peer %pM in state %s got event %s\n", mgmt->sa,
-                      mplstates[sta->plink_state], mplevents[event]);
-       reason = 0;
        spin_lock_bh(&sta->lock);
        switch (sta->plink_state) {
-               /* spin_unlock as soon as state is updated at each case */
        case NL80211_PLINK_LISTEN:
                switch (event) {
                case CLS_ACPT:
                        mesh_plink_fsm_restart(sta);
-                       spin_unlock_bh(&sta->lock);
                        break;
                case OPN_ACPT:
                        sta->plink_state = NL80211_PLINK_OPN_RCVD;
-                       sta->plid = plid;
-                       get_random_bytes(&llid, 2);
-                       sta->llid = llid;
+                       sta->llid = mesh_get_new_llid(sdata);
                        mesh_plink_timer_set(sta,
                                             mshcfg->dot11MeshRetryTimeout);
 
                        /* set the non-peer mode to active during peering */
                        changed |= ieee80211_mps_local_status_update(sdata);
-
-                       spin_unlock_bh(&sta->lock);
-                       mesh_plink_frame_tx(sdata,
-                                           WLAN_SP_MESH_PEERING_OPEN,
-                                           sta->sta.addr, llid, 0, 0);
-                       mesh_plink_frame_tx(sdata,
-                                           WLAN_SP_MESH_PEERING_CONFIRM,
-                                           sta->sta.addr, llid, plid, 0);
+                       action = WLAN_SP_MESH_PEERING_OPEN;
                        break;
                default:
-                       spin_unlock_bh(&sta->lock);
                        break;
                }
                break;
-
        case NL80211_PLINK_OPN_SNT:
                switch (event) {
                case OPN_RJCT:
                case CNF_RJCT:
-                       reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG);
                case CLS_ACPT:
-                       if (!reason)
-                               reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
-                       sta->reason = reason;
-                       sta->plink_state = NL80211_PLINK_HOLDING;
-                       if (!mod_plink_timer(sta,
-                                            mshcfg->dot11MeshHoldingTimeout))
-                               sta->ignore_plink_timer = true;
-
-                       llid = sta->llid;
-                       spin_unlock_bh(&sta->lock);
-                       mesh_plink_frame_tx(sdata,
-                                           WLAN_SP_MESH_PEERING_CLOSE,
-                                           sta->sta.addr, llid, plid, reason);
+                       mesh_plink_close(sdata, sta, event);
+                       action = WLAN_SP_MESH_PEERING_CLOSE;
                        break;
                case OPN_ACPT:
                        /* retry timer is left untouched */
                        sta->plink_state = NL80211_PLINK_OPN_RCVD;
-                       sta->plid = plid;
-                       llid = sta->llid;
-                       spin_unlock_bh(&sta->lock);
-                       mesh_plink_frame_tx(sdata,
-                                           WLAN_SP_MESH_PEERING_CONFIRM,
-                                           sta->sta.addr, llid, plid, 0);
+                       action = WLAN_SP_MESH_PEERING_CONFIRM;
                        break;
                case CNF_ACPT:
                        sta->plink_state = NL80211_PLINK_CNF_RCVD;
                        if (!mod_plink_timer(sta,
                                             mshcfg->dot11MeshConfirmTimeout))
                                sta->ignore_plink_timer = true;
-
-                       spin_unlock_bh(&sta->lock);
                        break;
                default:
-                       spin_unlock_bh(&sta->lock);
                        break;
                }
                break;
-
        case NL80211_PLINK_OPN_RCVD:
                switch (event) {
                case OPN_RJCT:
                case CNF_RJCT:
-                       reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG);
                case CLS_ACPT:
-                       if (!reason)
-                               reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
-                       sta->reason = reason;
-                       sta->plink_state = NL80211_PLINK_HOLDING;
-                       if (!mod_plink_timer(sta,
-                                            mshcfg->dot11MeshHoldingTimeout))
-                               sta->ignore_plink_timer = true;
-
-                       llid = sta->llid;
-                       spin_unlock_bh(&sta->lock);
-                       mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
-                                           sta->sta.addr, llid, plid, reason);
+                       mesh_plink_close(sdata, sta, event);
+                       action = WLAN_SP_MESH_PEERING_CLOSE;
                        break;
                case OPN_ACPT:
-                       llid = sta->llid;
-                       spin_unlock_bh(&sta->lock);
-                       mesh_plink_frame_tx(sdata,
-                                           WLAN_SP_MESH_PEERING_CONFIRM,
-                                           sta->sta.addr, llid, plid, 0);
+                       action = WLAN_SP_MESH_PEERING_CONFIRM;
                        break;
                case CNF_ACPT:
-                       del_timer(&sta->plink_timer);
-                       sta->plink_state = NL80211_PLINK_ESTAB;
-                       spin_unlock_bh(&sta->lock);
-                       changed |= mesh_plink_inc_estab_count(sdata);
-                       changed |= mesh_set_ht_prot_mode(sdata);
-                       changed |= mesh_set_short_slot_time(sdata);
-                       mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n",
-                               sta->sta.addr);
-                       ieee80211_mps_sta_status_update(sta);
-                       changed |= ieee80211_mps_set_sta_local_pm(sta,
-                                                      mshcfg->power_mode);
+                       changed |= mesh_plink_establish(sdata, sta);
                        break;
                default:
-                       spin_unlock_bh(&sta->lock);
                        break;
                }
                break;
-
        case NL80211_PLINK_CNF_RCVD:
                switch (event) {
                case OPN_RJCT:
                case CNF_RJCT:
-                       reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG);
                case CLS_ACPT:
-                       if (!reason)
-                               reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
-                       sta->reason = reason;
-                       sta->plink_state = NL80211_PLINK_HOLDING;
-                       if (!mod_plink_timer(sta,
-                                            mshcfg->dot11MeshHoldingTimeout))
-                               sta->ignore_plink_timer = true;
-
-                       llid = sta->llid;
-                       spin_unlock_bh(&sta->lock);
-                       mesh_plink_frame_tx(sdata,
-                                           WLAN_SP_MESH_PEERING_CLOSE,
-                                           sta->sta.addr, llid, plid, reason);
+                       mesh_plink_close(sdata, sta, event);
+                       action = WLAN_SP_MESH_PEERING_CLOSE;
                        break;
                case OPN_ACPT:
-                       del_timer(&sta->plink_timer);
-                       sta->plink_state = NL80211_PLINK_ESTAB;
-                       spin_unlock_bh(&sta->lock);
-                       changed |= mesh_plink_inc_estab_count(sdata);
-                       changed |= mesh_set_ht_prot_mode(sdata);
-                       changed |= mesh_set_short_slot_time(sdata);
-                       mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n",
-                               sta->sta.addr);
-                       mesh_plink_frame_tx(sdata,
-                                           WLAN_SP_MESH_PEERING_CONFIRM,
-                                           sta->sta.addr, llid, plid, 0);
-                       ieee80211_mps_sta_status_update(sta);
-                       changed |= ieee80211_mps_set_sta_local_pm(sta,
-                                                       mshcfg->power_mode);
+                       changed |= mesh_plink_establish(sdata, sta);
+                       action = WLAN_SP_MESH_PEERING_CONFIRM;
                        break;
                default:
-                       spin_unlock_bh(&sta->lock);
                        break;
                }
                break;
-
        case NL80211_PLINK_ESTAB:
                switch (event) {
                case CLS_ACPT:
-                       reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
-                       sta->reason = reason;
                        changed |= __mesh_plink_deactivate(sta);
-                       sta->plink_state = NL80211_PLINK_HOLDING;
-                       llid = sta->llid;
-                       mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout);
-                       spin_unlock_bh(&sta->lock);
                        changed |= mesh_set_ht_prot_mode(sdata);
                        changed |= mesh_set_short_slot_time(sdata);
-                       mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
-                                           sta->sta.addr, llid, plid, reason);
+                       mesh_plink_close(sdata, sta, event);
+                       action = WLAN_SP_MESH_PEERING_CLOSE;
                        break;
                case OPN_ACPT:
-                       llid = sta->llid;
-                       spin_unlock_bh(&sta->lock);
-                       mesh_plink_frame_tx(sdata,
-                                           WLAN_SP_MESH_PEERING_CONFIRM,
-                                           sta->sta.addr, llid, plid, 0);
+                       action = WLAN_SP_MESH_PEERING_CONFIRM;
                        break;
                default:
-                       spin_unlock_bh(&sta->lock);
                        break;
                }
                break;
@@ -1049,32 +836,271 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
                        if (del_timer(&sta->plink_timer))
                                sta->ignore_plink_timer = 1;
                        mesh_plink_fsm_restart(sta);
-                       spin_unlock_bh(&sta->lock);
                        break;
                case OPN_ACPT:
                case CNF_ACPT:
                case OPN_RJCT:
                case CNF_RJCT:
-                       llid = sta->llid;
-                       reason = sta->reason;
-                       spin_unlock_bh(&sta->lock);
-                       mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
-                                           sta->sta.addr, llid, plid, reason);
+                       action = WLAN_SP_MESH_PEERING_CLOSE;
                        break;
                default:
-                       spin_unlock_bh(&sta->lock);
+                       break;
                }
                break;
        default:
                /* should not get here, PLINK_BLOCKED is dealt with at the
                 * beginning of the function
                 */
-               spin_unlock_bh(&sta->lock);
                break;
        }
+       spin_unlock_bh(&sta->lock);
+       if (action) {
+               mesh_plink_frame_tx(sdata, action, sta->sta.addr,
+                                   sta->llid, sta->plid, sta->reason);
+
+               /* also send confirm in open case */
+               if (action == WLAN_SP_MESH_PEERING_OPEN) {
+                       mesh_plink_frame_tx(sdata,
+                                           WLAN_SP_MESH_PEERING_CONFIRM,
+                                           sta->sta.addr, sta->llid,
+                                           sta->plid, 0);
+               }
+       }
+
+       return changed;
+}
+
+/*
+ * mesh_plink_get_event - get correct MPM event
+ *
+ * @sdata: interface
+ * @sta: peer, leave NULL if processing a frame from a new suitable peer
+ * @elems: peering management IEs
+ * @ftype: frame type
+ * @llid: peer's peer link ID
+ * @plid: peer's local link ID
+ *
+ * Return: new peering event for @sta, but PLINK_UNDEFINED should be treated as
+ * an error.
+ */
+static enum plink_event
+mesh_plink_get_event(struct ieee80211_sub_if_data *sdata,
+                    struct sta_info *sta,
+                    struct ieee802_11_elems *elems,
+                    enum ieee80211_self_protected_actioncode ftype,
+                    u16 llid, u16 plid)
+{
+       enum plink_event event = PLINK_UNDEFINED;
+       u8 ie_len = elems->peering_len;
+       bool matches_local;
+
+       matches_local = (ftype == WLAN_SP_MESH_PEERING_CLOSE ||
+                        mesh_matches_local(sdata, elems));
+
+       /* deny open request from non-matching peer */
+       if (!matches_local && !sta) {
+               event = OPN_RJCT;
+               goto out;
+       }
+
+       if (!sta) {
+               if (ftype != WLAN_SP_MESH_PEERING_OPEN) {
+                       mpl_dbg(sdata, "Mesh plink: cls or cnf from unknown peer\n");
+                       goto out;
+               }
+               /* ftype == WLAN_SP_MESH_PEERING_OPEN */
+               if (!mesh_plink_free_count(sdata)) {
+                       mpl_dbg(sdata, "Mesh plink error: no more free plinks\n");
+                       goto out;
+               }
+       } else {
+               if (!test_sta_flag(sta, WLAN_STA_AUTH)) {
+                       mpl_dbg(sdata, "Mesh plink: Action frame from non-authed peer\n");
+                       goto out;
+               }
+               if (sta->plink_state == NL80211_PLINK_BLOCKED)
+                       goto out;
+       }
+
+       /* new matching peer */
+       if (!sta) {
+               event = OPN_ACPT;
+               goto out;
+       }
+
+       switch (ftype) {
+       case WLAN_SP_MESH_PEERING_OPEN:
+               if (!matches_local)
+                       event = OPN_RJCT;
+               if (!mesh_plink_free_count(sdata) ||
+                   (sta->plid && sta->plid != plid))
+                       event = OPN_IGNR;
+               else
+                       event = OPN_ACPT;
+               break;
+       case WLAN_SP_MESH_PEERING_CONFIRM:
+               if (!matches_local)
+                       event = CNF_RJCT;
+               if (!mesh_plink_free_count(sdata) ||
+                   (sta->llid != llid || sta->plid != plid))
+                       event = CNF_IGNR;
+               else
+                       event = CNF_ACPT;
+               break;
+       case WLAN_SP_MESH_PEERING_CLOSE:
+               if (sta->plink_state == NL80211_PLINK_ESTAB)
+                       /* Do not check for llid or plid. This does not
+                        * follow the standard but since multiple plinks
+                        * per sta are not supported, it is necessary in
+                        * order to avoid a livelock when MP A sees an
+                        * establish peer link to MP B but MP B does not
+                        * see it. This can be caused by a timeout in
+                        * B's peer link establishment or B beign
+                        * restarted.
+                        */
+                       event = CLS_ACPT;
+               else if (sta->plid != plid)
+                       event = CLS_IGNR;
+               else if (ie_len == 8 && sta->llid != llid)
+                       event = CLS_IGNR;
+               else
+                       event = CLS_ACPT;
+               break;
+       default:
+               mpl_dbg(sdata, "Mesh plink: unknown frame subtype\n");
+               break;
+       }
+
+out:
+       return event;
+}
 
+static void
+mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
+                        struct ieee80211_mgmt *mgmt,
+                        struct ieee802_11_elems *elems)
+{
+
+       struct sta_info *sta;
+       enum plink_event event;
+       enum ieee80211_self_protected_actioncode ftype;
+       u32 changed = 0;
+       u8 ie_len = elems->peering_len;
+       __le16 _plid, _llid;
+       u16 plid, llid = 0;
+
+       if (!elems->peering) {
+               mpl_dbg(sdata,
+                       "Mesh plink: missing necessary peer link ie\n");
+               return;
+       }
+
+       if (elems->rsn_len &&
+           sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) {
+               mpl_dbg(sdata,
+                       "Mesh plink: can't establish link with secure peer\n");
+               return;
+       }
+
+       ftype = mgmt->u.action.u.self_prot.action_code;
+       if ((ftype == WLAN_SP_MESH_PEERING_OPEN && ie_len != 4) ||
+           (ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 6) ||
+           (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 6
+                                                       && ie_len != 8)) {
+               mpl_dbg(sdata,
+                       "Mesh plink: incorrect plink ie length %d %d\n",
+                       ftype, ie_len);
+               return;
+       }
+
+       if (ftype != WLAN_SP_MESH_PEERING_CLOSE &&
+           (!elems->mesh_id || !elems->mesh_config)) {
+               mpl_dbg(sdata, "Mesh plink: missing necessary ie\n");
+               return;
+       }
+       /* Note the lines below are correct, the llid in the frame is the plid
+        * from the point of view of this host.
+        */
+       memcpy(&_plid, PLINK_GET_LLID(elems->peering), sizeof(__le16));
+       plid = le16_to_cpu(_plid);
+       if (ftype == WLAN_SP_MESH_PEERING_CONFIRM ||
+           (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8)) {
+               memcpy(&_llid, PLINK_GET_PLID(elems->peering), sizeof(__le16));
+               llid = le16_to_cpu(_llid);
+       }
+
+       /* WARNING: Only for sta pointer, is dropped & re-acquired */
+       rcu_read_lock();
+
+       sta = sta_info_get(sdata, mgmt->sa);
+
+       if (ftype == WLAN_SP_MESH_PEERING_OPEN &&
+           !rssi_threshold_check(sdata, sta)) {
+               mpl_dbg(sdata, "Mesh plink: %pM does not meet rssi threshold\n",
+                       mgmt->sa);
+               goto unlock_rcu;
+       }
+
+       /* Now we will figure out the appropriate event... */
+       event = mesh_plink_get_event(sdata, sta, elems, ftype, llid, plid);
+
+       if (event == OPN_ACPT) {
+               rcu_read_unlock();
+               /* allocate sta entry if necessary and update info */
+               sta = mesh_sta_info_get(sdata, mgmt->sa, elems);
+               if (!sta) {
+                       mpl_dbg(sdata, "Mesh plink: failed to init peer!\n");
+                       goto unlock_rcu;
+               }
+               sta->plid = plid;
+       } else if (!sta && event == OPN_RJCT) {
+               mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
+                                   mgmt->sa, 0, plid,
+                                   WLAN_REASON_MESH_CONFIG);
+               goto unlock_rcu;
+       } else if (!sta || event == PLINK_UNDEFINED) {
+               /* something went wrong */
+               goto unlock_rcu;
+       }
+
+       changed |= mesh_plink_fsm(sdata, sta, event);
+
+unlock_rcu:
        rcu_read_unlock();
 
        if (changed)
                ieee80211_mbss_info_change_notify(sdata, changed);
 }
+
+void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
+                        struct ieee80211_mgmt *mgmt, size_t len,
+                        struct ieee80211_rx_status *rx_status)
+{
+       struct ieee802_11_elems elems;
+       size_t baselen;
+       u8 *baseaddr;
+
+       /* need action_code, aux */
+       if (len < IEEE80211_MIN_ACTION_SIZE + 3)
+               return;
+
+       if (sdata->u.mesh.user_mpm)
+               /* userspace must register for these */
+               return;
+
+       if (is_multicast_ether_addr(mgmt->da)) {
+               mpl_dbg(sdata,
+                       "Mesh plink: ignore frame from multicast address\n");
+               return;
+       }
+
+       baseaddr = mgmt->u.action.u.self_prot.variable;
+       baselen = (u8 *) mgmt->u.action.u.self_prot.variable - (u8 *) mgmt;
+       if (mgmt->u.action.u.self_prot.action_code ==
+                                               WLAN_SP_MESH_PEERING_CONFIRM) {
+               baseaddr += 4;
+               baselen += 4;
+       }
+       ieee802_11_parse_elems(baseaddr, len - baselen, true, &elems);
+       mesh_process_plink_frame(sdata, mgmt, &elems);
+}
index 0f79b78b5e86b45a6d7059de497b68b44944da09..2802f9d9279de1527927a88bc731489cc22613c7 100644 (file)
@@ -576,10 +576,9 @@ void ieee80211_mps_frame_release(struct sta_info *sta,
        int ac, buffer_local = 0;
        bool has_buffered = false;
 
-       /* TIM map only for LLID <= IEEE80211_MAX_AID */
        if (sta->plink_state == NL80211_PLINK_ESTAB)
                has_buffered = ieee80211_check_tim(elems->tim, elems->tim_len,
-                               le16_to_cpu(sta->llid) % IEEE80211_MAX_AID);
+                                                  sta->llid);
 
        if (has_buffered)
                mps_dbg(sta->sdata, "%pM indicates buffered frames\n",
index 05a256b38e245b64b26a4adb11023898bcd115e1..d1cf2d5534998957c13cfbd5ca23c630d7c9f6a7 100644 (file)
@@ -92,12 +92,20 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
        if (stype != IEEE80211_STYPE_BEACON)
                return;
 
-       /* The current tsf is a first approximation for the timestamp
-        * for the received beacon.  Further down we try to get a
-        * better value from the rx_status->mactime field if
-        * available. Also we have to call drv_get_tsf() before
-        * entering the rcu-read section.*/
-       t_r = drv_get_tsf(local, sdata);
+       /*
+        * Get time when timestamp field was received.  If we don't
+        * have rx timestamps, then use current tsf as an approximation.
+        * drv_get_tsf() must be called before entering the rcu-read
+        * section.
+        */
+       if (ieee80211_have_rx_timestamp(rx_status))
+               t_r = ieee80211_calculate_rx_timestamp(local, rx_status,
+                                                      24 + 12 +
+                                                      elems->total_len +
+                                                      FCS_LEN,
+                                                      24);
+       else
+               t_r = drv_get_tsf(local, sdata);
 
        rcu_read_lock();
        sta = sta_info_get(sdata, mgmt->sa);
@@ -117,14 +125,6 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
                goto no_sync;
        }
 
-       if (ieee80211_have_rx_timestamp(rx_status))
-               /* time when timestamp field was received */
-               t_r = ieee80211_calculate_rx_timestamp(local, rx_status,
-                                                      24 + 12 +
-                                                      elems->total_len +
-                                                      FCS_LEN,
-                                                      24);
-
        /* Timing offset calculation (see 13.13.2.2.2) */
        t_t = le64_to_cpu(mgmt->u.beacon.timestamp);
        sta->t_offset = t_t - t_r;
index d7504ab61a34c7ef6a51f8adce10e58c021408d0..33bcf8018d8e3873f7719994a990eeed6da65e25 100644 (file)
@@ -330,6 +330,16 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
        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];
 
@@ -416,14 +426,6 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
                                         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;
 }
 
@@ -714,7 +716,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
        }
 
        /* 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,
@@ -748,7 +750,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
                                     &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);
@@ -779,7 +781,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
        }
 
        /* 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);
@@ -886,8 +888,7 @@ static void ieee80211_chswitch_work(struct work_struct *work)
        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");
@@ -897,7 +898,7 @@ static void ieee80211_chswitch_work(struct work_struct *work)
        }
 
        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
                 */
@@ -908,7 +909,7 @@ static void ieee80211_chswitch_work(struct work_struct *work)
        }
 
        /* 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,
@@ -1035,7 +1036,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
        }
        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,
@@ -1398,10 +1399,12 @@ void ieee80211_dfs_cac_timer_work(struct work_struct *work)
        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 */
@@ -1745,6 +1748,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
 
        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,
@@ -4189,6 +4194,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
 
        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 505bc0dea074809f1532f322528e222a5052c061..b95e16c070813da22169679e8c5c1aa7e3ee0f1d 100644 (file)
@@ -54,6 +54,8 @@ static inline void rate_control_rate_init(struct sta_info *sta)
        struct ieee80211_supported_band *sband;
        struct ieee80211_chanctx_conf *chanctx_conf;
 
+       ieee80211_sta_set_rx_nss(sta);
+
        if (!ref)
                return;
 
@@ -67,8 +69,6 @@ static inline void rate_control_rate_init(struct sta_info *sta)
 
        sband = local->hw.wiphy->bands[chanctx_conf->def.chan->band];
 
-       ieee80211_sta_set_rx_nss(sta);
-
        ref->ops->rate_init(ref->priv, sband, &chanctx_conf->def, ista,
                            priv_sta);
        rcu_read_unlock();
index 7fa1b36e620247ed5c14e97d54b2d72d7a0b43cb..d2f19f7e7091b6e6b9111702f19b02f612fdb52c 100644 (file)
@@ -422,10 +422,9 @@ init_sample_table(struct minstrel_sta_info *mi)
        memset(mi->sample_table, 0xff, SAMPLE_COLUMNS * mi->n_rates);
 
        for (col = 0; col < SAMPLE_COLUMNS; col++) {
+               prandom_bytes(rnd, sizeof(rnd));
                for (i = 0; i < mi->n_rates; i++) {
-                       get_random_bytes(rnd, sizeof(rnd));
                        new_idx = (i + rnd[i & 7]) % mi->n_rates;
-
                        while (SAMPLE_TBL(mi, new_idx, col) != 0xff)
                                new_idx = (new_idx + 1) % mi->n_rates;
 
index 5d60779a0c1be89e987b2cd478af865ec806d4bb..b91655a0d8f090867d1bdb9c8d2de2d5a63f5919 100644 (file)
@@ -135,7 +135,7 @@ minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi);
 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 @@ minstrel_ht_get_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
 
        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;
 
@@ -636,8 +636,7 @@ minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
                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;
        }
 
@@ -701,12 +700,16 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
        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)
@@ -817,7 +820,7 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
        }
 
        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;
 }
 
@@ -1052,10 +1055,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;
 
index df44a5ad827049f251dd255f47e5c06262f1eb77..3e7d793de0c3407180965bb785485fd361700560 100644 (file)
@@ -54,8 +54,7 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p)
                        int r = bitrates[j % 4];
                        p += sprintf(p, " %2u.%1uM", r / 10, r % 10);
                } else {
-                       p += sprintf(p, " MCS%-2u", (mg->streams - 1) *
-                                        MCS_GROUP_RATES + j);
+                       p += sprintf(p, " MCS%-2u", (mg->streams - 1) * 8 + j);
                }
 
                tp = mr->cur_tp / 10;
index caecef870c0e44e3562cdc0a874bcfd233fc77a1..30ac6099da06da2e5a0d409e707e0986d224a3b7 100644 (file)
@@ -638,6 +638,27 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb)
        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;
@@ -729,9 +750,7 @@ static void ieee80211_release_reorder_frames(struct ieee80211_sub_if_data *sdata
        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);
        }
@@ -757,8 +776,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
        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) {
                /*
@@ -793,15 +811,11 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
        } 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) {
@@ -861,8 +875,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata
 
        /* 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]) {
@@ -1368,6 +1381,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
        struct ieee80211_key *sta_ptk = NULL;
        int mmie_keyidx = -1;
        __le16 fc;
+       const struct ieee80211_cipher_scheme *cs = NULL;
 
        /*
         * Key selection 101
@@ -1405,11 +1419,19 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
 
        /* 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);
@@ -1471,6 +1493,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
                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
@@ -1486,15 +1509,21 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
 
                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)
@@ -1542,11 +1571,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
                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 */
@@ -2056,7 +2081,6 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
        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;
@@ -2164,7 +2188,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
        } 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;
index 5ad66a83ef7f4d4525de163c2c2f1fe9d6931a04..c22cbb57b49dd30196899c32902d3876803fbe09 100644 (file)
@@ -526,7 +526,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
                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 @@ ieee80211_scan_get_channel_time(struct ieee80211_channel *chan)
         * 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 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
         *
         * 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 @@ int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata,
                                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;
 
@@ -895,7 +895,7 @@ int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata,
 
                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;
 
index 1eb66e26e49d0a02869ec5e5ff4789583e9760d1..8ed97f76c3cfade5f0986fa2d17c8275753b3c35 100644 (file)
@@ -266,9 +266,17 @@ struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata,
  */
 void sta_info_free(struct ieee80211_local *local, struct sta_info *sta)
 {
+       int i;
+
        if (sta->rate_ctrl)
                rate_control_free_sta(sta);
 
+       if (sta->tx_lat) {
+               for (i = 0; i < IEEE80211_NUM_TIDS; i++)
+                       kfree(sta->tx_lat[i].bins);
+               kfree(sta->tx_lat);
+       }
+
        sta_dbg(sta->sdata, "Destroyed STA %pM\n", sta->sta.addr);
 
        kfree(sta);
@@ -333,6 +341,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_local *local = sdata->local;
        struct sta_info *sta;
        struct timespec uptime;
+       struct ieee80211_tx_latency_bin_ranges *tx_latency;
        int i;
 
        sta = kzalloc(sizeof(*sta) + local->hw.sta_data_size, gfp);
@@ -410,6 +419,31 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
                }
        }
 
+       rcu_read_lock();
+
+       tx_latency = rcu_dereference(local->tx_latency);
+       /* init stations Tx latency statistics && TID bins */
+       if (tx_latency)
+               sta->tx_lat = kzalloc(IEEE80211_NUM_TIDS *
+                                     sizeof(struct ieee80211_tx_latency_stat),
+                                     GFP_ATOMIC);
+
+       /*
+        * if Tx latency and bins are enabled and the previous allocation
+        * succeeded
+        */
+       if (tx_latency && tx_latency->n_ranges && sta->tx_lat)
+               for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
+                       /* size of bins is size of the ranges +1 */
+                       sta->tx_lat[i].bin_count =
+                               tx_latency->n_ranges + 1;
+                       sta->tx_lat[i].bins  = kcalloc(sta->tx_lat[i].bin_count,
+                                                      sizeof(u32),
+                                                      GFP_ATOMIC);
+               }
+
+       rcu_read_unlock();
+
        sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr);
 
        return sta;
@@ -507,6 +541,7 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
 
        set_sta_flag(sta, WLAN_STA_INSERTED);
 
+       ieee80211_recalc_min_chandef(sdata);
        ieee80211_sta_debugfs_add(sta);
        rate_control_add_sta_debugfs(sta);
 
@@ -630,8 +665,8 @@ void sta_info_recalc_tim(struct sta_info *sta)
 #ifdef CONFIG_MAC80211_MESH
        } else if (ieee80211_vif_is_mesh(&sta->sdata->vif)) {
                ps = &sta->sdata->u.mesh.ps;
-               /* TIM map only for PLID <= IEEE80211_MAX_AID */
-               id = le16_to_cpu(sta->plid) % IEEE80211_MAX_AID;
+               /* TIM map only for 1 <= PLID <= IEEE80211_MAX_AID */
+               id = sta->plid % (IEEE80211_MAX_AID + 1);
 #endif
        } else {
                return;
@@ -869,6 +904,7 @@ int __must_check __sta_info_destroy(struct sta_info *sta)
 
        rate_control_remove_sta_debugfs(sta);
        ieee80211_sta_debugfs_remove(sta);
+       ieee80211_recalc_min_chandef(sdata);
 
        call_rcu(&sta->rcu_head, free_sta_rcu);
 
index 3ef06a26b9cb9feaddfd3d752dd9bd8ac971a11c..0218caf5c14a793ef14045da6c0db6a13781b259 100644 (file)
@@ -220,6 +220,25 @@ struct sta_ampdu_mlme {
        u8 dialog_token_allocator;
 };
 
+/*
+ * struct ieee80211_tx_latency_stat - Tx latency statistics
+ *
+ * Measures TX latency and jitter for a station per TID.
+ *
+ * @max: worst case latency
+ * @sum: sum of all latencies
+ * @counter: amount of Tx frames sent from interface
+ * @bins: each bin counts how many frames transmitted within a certain
+ * latency range. when disabled it is NULL.
+ * @bin_count: amount of bins.
+ */
+struct ieee80211_tx_latency_stat {
+       u32 max;
+       u32 sum;
+       u32 counter;
+       u32 *bins;
+       u32 bin_count;
+};
 
 /**
  * struct sta_info - STA information
@@ -231,8 +250,10 @@ struct sta_ampdu_mlme {
  * @hnext: hash table linked list pointer
  * @local: pointer to the global information
  * @sdata: virtual interface this station belongs to
- * @ptk: peer key negotiated with this station, if any
+ * @ptk: peer keys negotiated with this station, if any
+ * @ptk_idx: last installed peer key index
  * @gtk: group keys negotiated with this station, if any
+ * @gtk_idx: last installed group key index
  * @rate_ctrl: rate control algorithm reference
  * @rate_ctrl_priv: rate control private per-STA pointer
  * @last_tx_rate: rate used for last transmit, to report to userspace as
@@ -274,6 +295,7 @@ struct sta_ampdu_mlme {
  * @tid_seq: per-TID sequence numbers for sending to this STA
  * @ampdu_mlme: A-MPDU state machine state
  * @timer_to_tid: identity mapping to ID timers
+ * @tx_lat: Tx latency statistics
  * @llid: Local link ID
  * @plid: Peer link ID
  * @reason: Cancel reason on PLINK_HOLDING state
@@ -303,6 +325,7 @@ struct sta_ampdu_mlme {
  * @chain_signal_avg: signal average (per chain)
  * @known_smps_mode: the smps_mode the client thinks we are in. Relevant for
  *     AP only.
+ * @cipher_scheme: optional cipher scheme for this station
  */
 struct sta_info {
        /* General information, mostly static */
@@ -312,7 +335,9 @@ struct sta_info {
        struct ieee80211_local *local;
        struct ieee80211_sub_if_data *sdata;
        struct ieee80211_key __rcu *gtk[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS];
-       struct ieee80211_key __rcu *ptk;
+       struct ieee80211_key __rcu *ptk[NUM_DEFAULT_KEYS];
+       u8 gtk_idx;
+       u8 ptk_idx;
        struct rate_control_ref *rate_ctrl;
        void *rate_ctrl_priv;
        spinlock_t lock;
@@ -380,14 +405,16 @@ struct sta_info {
        struct sta_ampdu_mlme ampdu_mlme;
        u8 timer_to_tid[IEEE80211_NUM_TIDS];
 
+       struct ieee80211_tx_latency_stat *tx_lat;
+
 #ifdef CONFIG_MAC80211_MESH
        /*
         * Mesh peer link attributes
         * TODO: move to a sub-structure that is referenced with pointer?
         */
-       __le16 llid;
-       __le16 plid;
-       __le16 reason;
+       u16 llid;
+       u16 plid;
+       u16 reason;
        u8 plink_retries;
        bool ignore_plink_timer;
        enum nl80211_plink_state plink_state;
@@ -414,6 +441,7 @@ struct sta_info {
        unsigned int beacon_loss_count;
 
        enum ieee80211_smps_mode known_smps_mode;
+       const struct ieee80211_cipher_scheme *cipher_scheme;
 
        /* keep last! */
        struct ieee80211_sta sta;
index 52a152b01b063b226fb5a523b19a4e9863eeffaf..1ee85c402439bfc886029f9ae6dfe6ec306e013f 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/export.h>
 #include <linux/etherdevice.h>
+#include <linux/time.h>
 #include <net/mac80211.h>
 #include <asm/unaligned.h>
 #include "ieee80211_i.h"
@@ -462,6 +463,77 @@ static void ieee80211_report_used_skb(struct ieee80211_local *local,
        }
 }
 
+/*
+ * Measure Tx frame completion and removal time for Tx latency statistics
+ * calculation. A single Tx frame latency should be measured from when it
+ * is entering the Kernel until we receive Tx complete confirmation indication
+ * and remove the skb.
+ */
+static void ieee80211_tx_latency_end_msrmnt(struct ieee80211_local *local,
+                                           struct sk_buff *skb,
+                                           struct sta_info *sta,
+                                           struct ieee80211_hdr *hdr)
+{
+       ktime_t skb_dprt;
+       struct timespec dprt_time;
+       u32 msrmnt;
+       u16 tid;
+       u8 *qc;
+       int i, bin_range_count, bin_count;
+       u32 *bin_ranges;
+       __le16 fc;
+       struct ieee80211_tx_latency_stat *tx_lat;
+       struct ieee80211_tx_latency_bin_ranges *tx_latency;
+       ktime_t skb_arv = skb->tstamp;
+
+       tx_latency = rcu_dereference(local->tx_latency);
+
+       /* assert Tx latency stats are enabled & frame arrived when enabled */
+       if (!tx_latency || !ktime_to_ns(skb_arv))
+               return;
+
+       fc = hdr->frame_control;
+
+       if (!ieee80211_is_data(fc)) /* make sure it is a data frame */
+               return;
+
+       /* get frame tid */
+       if (ieee80211_is_data_qos(hdr->frame_control)) {
+               qc = ieee80211_get_qos_ctl(hdr);
+               tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
+       } else {
+               tid = 0;
+       }
+
+       tx_lat = &sta->tx_lat[tid];
+
+       ktime_get_ts(&dprt_time); /* time stamp completion time */
+       skb_dprt = ktime_set(dprt_time.tv_sec, dprt_time.tv_nsec);
+       msrmnt = ktime_to_ms(ktime_sub(skb_dprt, skb_arv));
+
+       if (tx_lat->max < msrmnt) /* update stats */
+               tx_lat->max = msrmnt;
+       tx_lat->counter++;
+       tx_lat->sum += msrmnt;
+
+       if (!tx_lat->bins) /* bins not activated */
+               return;
+
+       /* count how many Tx frames transmitted with the appropriate latency */
+       bin_range_count = tx_latency->n_ranges;
+       bin_ranges = tx_latency->ranges;
+       bin_count = tx_lat->bin_count;
+
+       for (i = 0; i < bin_range_count; i++) {
+               if (msrmnt <= bin_ranges[i]) {
+                       tx_lat->bins[i]++;
+                       break;
+               }
+       }
+       if (i == bin_range_count) /* msrmnt is bigger than the biggest range */
+               tx_lat->bins[i]++;
+}
+
 /*
  * Use a static threshold for now, best value to be determined
  * by testing ...
@@ -620,6 +692,12 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
 
                if (acked)
                        sta->last_ack_signal = info->status.ack_signal;
+
+               /*
+                * Measure frame removal for tx latency
+                * statistics calculation
+                */
+               ieee80211_tx_latency_end_msrmnt(local, skb, sta, hdr);
        }
 
        rcu_read_unlock();
index d4cee98533fdc5a532a8ba74e48d6158faeb5003..e9ccf22f6dd972c8b0517c5d35a345085eb45ec6 100644 (file)
 #define CHANDEF_PR_ARG __entry->control_freq, __entry->chan_width,                     \
                        __entry->center_freq1, __entry->center_freq2
 
+#define MIN_CHANDEF_ENTRY                                                              \
+                       __field(u32, min_control_freq)                                  \
+                       __field(u32, min_chan_width)                                    \
+                       __field(u32, min_center_freq1)                                  \
+                       __field(u32, min_center_freq2)
+
+#define MIN_CHANDEF_ASSIGN(c)                                                          \
+                       __entry->min_control_freq = (c)->chan ? (c)->chan->center_freq : 0;     \
+                       __entry->min_chan_width = (c)->width;                           \
+                       __entry->min_center_freq1 = (c)->center_freq1;                  \
+                       __entry->min_center_freq2 = (c)->center_freq2;
+#define MIN_CHANDEF_PR_FMT     " min_control:%d MHz min_width:%d min_center: %d/%d MHz"
+#define MIN_CHANDEF_PR_ARG     __entry->min_control_freq, __entry->min_chan_width,     \
+                       __entry->min_center_freq1, __entry->min_center_freq2
+
 #define CHANCTX_ENTRY  CHANDEF_ENTRY                                                   \
+                       MIN_CHANDEF_ENTRY                                               \
                        __field(u8, rx_chains_static)                                   \
                        __field(u8, rx_chains_dynamic)
 #define CHANCTX_ASSIGN CHANDEF_ASSIGN(&ctx->conf.def)                                  \
+                       MIN_CHANDEF_ASSIGN(&ctx->conf.min_def)                          \
                        __entry->rx_chains_static = ctx->conf.rx_chains_static;         \
                        __entry->rx_chains_dynamic = ctx->conf.rx_chains_dynamic
-#define CHANCTX_PR_FMT CHANDEF_PR_FMT " chains:%d/%d"
-#define CHANCTX_PR_ARG CHANDEF_PR_ARG,                                                 \
+#define CHANCTX_PR_FMT CHANDEF_PR_FMT MIN_CHANDEF_PR_FMT " chains:%d/%d"
+#define CHANCTX_PR_ARG CHANDEF_PR_ARG, MIN_CHANDEF_PR_ARG,                             \
                        __entry->rx_chains_static, __entry->rx_chains_dynamic
 
 
index c558b246ef0036c38e6c8a00b338b43c46913f78..6d59e21cdb9fe8b686fdcef53ddc83a83738d0cf 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/bitmap.h>
 #include <linux/rcupdate.h>
 #include <linux/export.h>
+#include <linux/time.h>
 #include <net/net_namespace.h>
 #include <net/ieee80211_radiotap.h>
 #include <net/cfg80211.h>
@@ -557,7 +558,8 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
 
        if (unlikely(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT))
                tx->key = NULL;
-       else if (tx->sta && (key = rcu_dereference(tx->sta->ptk)))
+       else if (tx->sta &&
+                (key = rcu_dereference(tx->sta->ptk[tx->sta->ptk_idx])))
                tx->key = key;
        else if (ieee80211_is_mgmt(hdr->frame_control) &&
                 is_multicast_ether_addr(hdr->addr1) &&
@@ -840,15 +842,16 @@ static int ieee80211_fragment(struct ieee80211_tx_data *tx,
                rem -= fraglen;
                tmp = dev_alloc_skb(local->tx_headroom +
                                    frag_threshold +
-                                   IEEE80211_ENCRYPT_HEADROOM +
+                                   tx->sdata->encrypt_headroom +
                                    IEEE80211_ENCRYPT_TAILROOM);
                if (!tmp)
                        return -ENOMEM;
 
                __skb_queue_tail(&tx->skbs, tmp);
 
-               skb_reserve(tmp, local->tx_headroom +
-                                IEEE80211_ENCRYPT_HEADROOM);
+               skb_reserve(tmp,
+                           local->tx_headroom + tx->sdata->encrypt_headroom);
+
                /* copy control information */
                memcpy(tmp->cb, skb->cb, sizeof(tmp->cb));
 
@@ -1485,7 +1488,7 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
 
        headroom = local->tx_headroom;
        if (may_encrypt)
-               headroom += IEEE80211_ENCRYPT_HEADROOM;
+               headroom += sdata->encrypt_headroom;
        headroom -= skb_headroom(skb);
        headroom = max_t(int, 0, headroom);
 
@@ -1724,8 +1727,7 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
         * radar detection by itself. We can do that later by adding a
         * monitor flag interfaces used for AP support.
         */
-       if ((chan->flags & (IEEE80211_CHAN_NO_IBSS | IEEE80211_CHAN_RADAR |
-                           IEEE80211_CHAN_PASSIVE_SCAN)))
+       if ((chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR)))
                goto fail_rcu;
 
        ieee80211_xmit(sdata, skb, chan->band);
@@ -1740,6 +1742,26 @@ fail:
        return NETDEV_TX_OK; /* meaning, we dealt with the skb */
 }
 
+/*
+ * Measure Tx frame arrival time for Tx latency statistics calculation
+ * A single Tx frame latency should be measured from when it is entering the
+ * Kernel until we receive Tx complete confirmation indication and the skb is
+ * freed.
+ */
+static void ieee80211_tx_latency_start_msrmnt(struct ieee80211_local *local,
+                                             struct sk_buff *skb)
+{
+       struct timespec skb_arv;
+       struct ieee80211_tx_latency_bin_ranges *tx_latency;
+
+       tx_latency = rcu_dereference(local->tx_latency);
+       if (!tx_latency)
+               return;
+
+       ktime_get_ts(&skb_arv);
+       skb->tstamp = ktime_set(skb_arv.tv_sec, skb_arv.tv_nsec);
+}
+
 /**
  * ieee80211_subif_start_xmit - netif start_xmit function for Ethernet-type
  * subinterfaces (wlan#, WDS, and VLAN interfaces)
@@ -1790,6 +1812,9 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
 
        rcu_read_lock();
 
+       /* Measure frame arrival for Tx latency statistics calculation */
+       ieee80211_tx_latency_start_msrmnt(local, skb);
+
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_AP_VLAN:
                sta = rcu_dereference(sdata->u.vlan.sta);
@@ -2109,7 +2134,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
         */
 
        if (head_need > 0 || skb_cloned(skb)) {
-               head_need += IEEE80211_ENCRYPT_HEADROOM;
+               head_need += sdata->encrypt_headroom;
                head_need += local->tx_headroom;
                head_need = max_t(int, 0, head_need);
                if (ieee80211_skb_resize(sdata, skb, head_need, true)) {
index 592a18171f95e9ec5273b03307235dff2bd1c946..06265d7f8cc375d47e804623503af3540ec3eb38 100644 (file)
@@ -1804,6 +1804,26 @@ void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata)
        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;
@@ -2259,14 +2279,17 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
 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);
                }
@@ -2447,7 +2470,6 @@ int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
 
        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 */
@@ -2463,8 +2485,7 @@ int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
                        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;
        }
@@ -2472,3 +2493,71 @@ int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
        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;
+}
index de0112785aae19a8b23b2f8f84b364c80d27e8b3..d75f35c6e1a0884eb9452030cb27bcafb33deeab 100644 (file)
@@ -182,16 +182,15 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
                         IEEE80211_VHT_CAP_SHORT_GI_160);
 
        /* remaining ones */
-       if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) {
+       if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE)
                vht_cap->cap |= cap_info &
                                (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
-                                IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MAX);
-       }
+                                IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK);
 
        if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)
                vht_cap->cap |= cap_info &
                                (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
-                                IEEE80211_VHT_CAP_BEAMFORMEE_STS_MAX);
+                                IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK);
 
        if (own_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)
                vht_cap->cap |= cap_info &
index d6572822076367cdf203207892a2880c7e4487c2..7313d379c0d32aea2c6a152c9756263ff7bf523f 100644 (file)
@@ -545,6 +545,106 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)
        return RX_CONTINUE;
 }
 
+static ieee80211_tx_result
+ieee80211_crypto_cs_encrypt(struct ieee80211_tx_data *tx,
+                           struct sk_buff *skb)
+{
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       struct ieee80211_key *key = tx->key;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       const struct ieee80211_cipher_scheme *cs = key->sta->cipher_scheme;
+       int hdrlen;
+       u8 *pos;
+
+       if (info->control.hw_key &&
+           !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) {
+               /* hwaccel has no need for preallocated head room */
+               return TX_CONTINUE;
+       }
+
+       if (unlikely(skb_headroom(skb) < cs->hdr_len &&
+                    pskb_expand_head(skb, cs->hdr_len, 0, GFP_ATOMIC)))
+               return TX_DROP;
+
+       hdrlen = ieee80211_hdrlen(hdr->frame_control);
+
+       pos = skb_push(skb, cs->hdr_len);
+       memmove(pos, pos + cs->hdr_len, hdrlen);
+       skb_set_network_header(skb, skb_network_offset(skb) + cs->hdr_len);
+
+       return TX_CONTINUE;
+}
+
+static inline int ieee80211_crypto_cs_pn_compare(u8 *pn1, u8 *pn2, int len)
+{
+       int i;
+
+       /* pn is little endian */
+       for (i = len - 1; i >= 0; i--) {
+               if (pn1[i] < pn2[i])
+                       return -1;
+               else if (pn1[i] > pn2[i])
+                       return 1;
+       }
+
+       return 0;
+}
+
+static ieee80211_rx_result
+ieee80211_crypto_cs_decrypt(struct ieee80211_rx_data *rx)
+{
+       struct ieee80211_key *key = rx->key;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
+       const struct ieee80211_cipher_scheme *cs = NULL;
+       int hdrlen = ieee80211_hdrlen(hdr->frame_control);
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
+       int data_len;
+       u8 *rx_pn;
+       u8 *skb_pn;
+       u8 qos_tid;
+
+       if (!rx->sta || !rx->sta->cipher_scheme ||
+           !(status->flag & RX_FLAG_DECRYPTED))
+               return RX_DROP_UNUSABLE;
+
+       if (!ieee80211_is_data(hdr->frame_control))
+               return RX_CONTINUE;
+
+       cs = rx->sta->cipher_scheme;
+
+       data_len = rx->skb->len - hdrlen - cs->hdr_len;
+
+       if (data_len < 0)
+               return RX_DROP_UNUSABLE;
+
+       if (ieee80211_is_data_qos(hdr->frame_control))
+               qos_tid = *ieee80211_get_qos_ctl(hdr) &
+                               IEEE80211_QOS_CTL_TID_MASK;
+       else
+               qos_tid = 0;
+
+       if (skb_linearize(rx->skb))
+               return RX_DROP_UNUSABLE;
+
+       hdr = (struct ieee80211_hdr *)rx->skb->data;
+
+       rx_pn = key->u.gen.rx_pn[qos_tid];
+       skb_pn = rx->skb->data + hdrlen + cs->pn_off;
+
+       if (ieee80211_crypto_cs_pn_compare(skb_pn, rx_pn, cs->pn_len) <= 0)
+               return RX_DROP_UNUSABLE;
+
+       memcpy(rx_pn, skb_pn, cs->pn_len);
+
+       /* remove security header and MIC */
+       if (pskb_trim(rx->skb, rx->skb->len - cs->mic_len))
+               return RX_DROP_UNUSABLE;
+
+       memmove(rx->skb->data + cs->hdr_len, rx->skb->data, hdrlen);
+       skb_pull(rx->skb, cs->hdr_len);
+
+       return RX_CONTINUE;
+}
 
 static void bip_aad(struct sk_buff *skb, u8 *aad)
 {
@@ -685,6 +785,7 @@ ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx)
 {
        struct sk_buff *skb;
        struct ieee80211_tx_info *info = NULL;
+       ieee80211_tx_result res;
 
        skb_queue_walk(&tx->skbs, skb) {
                info  = IEEE80211_SKB_CB(skb);
@@ -692,9 +793,24 @@ ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx)
                /* handle hw-only algorithm */
                if (!info->control.hw_key)
                        return TX_DROP;
+
+               if (tx->key->sta->cipher_scheme) {
+                       res = ieee80211_crypto_cs_encrypt(tx, skb);
+                       if (res != TX_CONTINUE)
+                               return res;
+               }
        }
 
        ieee80211_tx_set_protected(tx);
 
        return TX_CONTINUE;
 }
+
+ieee80211_rx_result
+ieee80211_crypto_hw_decrypt(struct ieee80211_rx_data *rx)
+{
+       if (rx->sta->cipher_scheme)
+               return ieee80211_crypto_cs_decrypt(rx);
+
+       return RX_DROP_UNUSABLE;
+}
index 07e33f899c71fc52f9ff1771cd283226a8a64084..62e5a12dfe0a24010b32eec210d7a38a1c4c3eb8 100644 (file)
@@ -34,5 +34,7 @@ ieee80211_rx_result
 ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx);
 ieee80211_tx_result
 ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx);
+ieee80211_rx_result
+ieee80211_crypto_hw_decrypt(struct ieee80211_rx_data *rx);
 
 #endif /* WPA_H */
index 9b8cc877eb191a2a62370c9f2617bed513200d24..78559b5bbd1fe1d98c533f18dd1cc4fce4087baa 100644 (file)
@@ -277,6 +277,32 @@ void cfg80211_set_dfs_state(struct wiphy *wiphy,
                                     width, dfs_state);
 }
 
+static u32 cfg80211_get_start_freq(u32 center_freq,
+                                  u32 bandwidth)
+{
+       u32 start_freq;
+
+       if (bandwidth <= 20)
+               start_freq = center_freq;
+       else
+               start_freq = center_freq - bandwidth/2 + 10;
+
+       return start_freq;
+}
+
+static u32 cfg80211_get_end_freq(u32 center_freq,
+                                u32 bandwidth)
+{
+       u32 end_freq;
+
+       if (bandwidth <= 20)
+               end_freq = center_freq;
+       else
+               end_freq = center_freq + bandwidth/2 - 10;
+
+       return end_freq;
+}
+
 static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy,
                                            u32 center_freq,
                                            u32 bandwidth)
@@ -284,13 +310,8 @@ static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy,
        struct ieee80211_channel *c;
        u32 freq, start_freq, end_freq;
 
-       if (bandwidth <= 20) {
-               start_freq = center_freq;
-               end_freq = center_freq;
-       } else {
-               start_freq = center_freq - bandwidth/2 + 10;
-               end_freq = center_freq + bandwidth/2 - 10;
-       }
+       start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
+       end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
 
        for (freq = start_freq; freq <= end_freq; freq += 20) {
                c = ieee80211_get_channel(wiphy, freq);
@@ -330,33 +351,159 @@ int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
 }
 EXPORT_SYMBOL(cfg80211_chandef_dfs_required);
 
-static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
-                                       u32 center_freq, u32 bandwidth,
-                                       u32 prohibited_flags)
+static int cfg80211_get_chans_dfs_usable(struct wiphy *wiphy,
+                                        u32 center_freq,
+                                        u32 bandwidth)
 {
        struct ieee80211_channel *c;
        u32 freq, start_freq, end_freq;
+       int count = 0;
 
-       if (bandwidth <= 20) {
-               start_freq = center_freq;
-               end_freq = center_freq;
-       } else {
-               start_freq = center_freq - bandwidth/2 + 10;
-               end_freq = center_freq + bandwidth/2 - 10;
+       start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
+       end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
+
+       /*
+        * Check entire range of channels for the bandwidth.
+        * Check all channels are DFS channels (DFS_USABLE or
+        * DFS_AVAILABLE). Return number of usable channels
+        * (require CAC). Allow DFS and non-DFS channel mix.
+        */
+       for (freq = start_freq; freq <= end_freq; freq += 20) {
+               c = ieee80211_get_channel(wiphy, freq);
+               if (!c)
+                       return -EINVAL;
+
+               if (c->flags & IEEE80211_CHAN_DISABLED)
+                       return -EINVAL;
+
+               if (c->flags & IEEE80211_CHAN_RADAR) {
+                       if (c->dfs_state == NL80211_DFS_UNAVAILABLE)
+                               return -EINVAL;
+
+                       if (c->dfs_state == NL80211_DFS_USABLE)
+                               count++;
+               }
        }
 
+       return count;
+}
+
+bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy,
+                                const struct cfg80211_chan_def *chandef)
+{
+       int width;
+       int r1, r2 = 0;
+
+       if (WARN_ON(!cfg80211_chandef_valid(chandef)))
+               return false;
+
+       width = cfg80211_chandef_get_width(chandef);
+       if (width < 0)
+               return false;
+
+       r1 = cfg80211_get_chans_dfs_usable(wiphy, chandef->center_freq1,
+                                         width);
+
+       if (r1 < 0)
+               return false;
+
+       switch (chandef->width) {
+       case NL80211_CHAN_WIDTH_80P80:
+               WARN_ON(!chandef->center_freq2);
+               r2 = cfg80211_get_chans_dfs_usable(wiphy,
+                                                  chandef->center_freq2,
+                                                  width);
+               if (r2 < 0)
+                       return false;
+               break;
+       default:
+               WARN_ON(chandef->center_freq2);
+               break;
+       }
+
+       return (r1 + r2 > 0);
+}
+
+
+static bool cfg80211_get_chans_dfs_available(struct wiphy *wiphy,
+                                            u32 center_freq,
+                                            u32 bandwidth)
+{
+       struct ieee80211_channel *c;
+       u32 freq, start_freq, end_freq;
+
+       start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
+       end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
+
+       /*
+        * Check entire range of channels for the bandwidth.
+        * If any channel in between is disabled or has not
+        * had gone through CAC return false
+        */
        for (freq = start_freq; freq <= end_freq; freq += 20) {
                c = ieee80211_get_channel(wiphy, freq);
                if (!c)
                        return false;
 
-               /* check for radar flags */
-               if ((prohibited_flags & c->flags & IEEE80211_CHAN_RADAR) &&
+               if (c->flags & IEEE80211_CHAN_DISABLED)
+                       return false;
+
+               if ((c->flags & IEEE80211_CHAN_RADAR)  &&
                    (c->dfs_state != NL80211_DFS_AVAILABLE))
                        return false;
+       }
+
+       return true;
+}
+
+static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy,
+                               const struct cfg80211_chan_def *chandef)
+{
+       int width;
+       int r;
+
+       if (WARN_ON(!cfg80211_chandef_valid(chandef)))
+               return false;
+
+       width = cfg80211_chandef_get_width(chandef);
+       if (width < 0)
+               return false;
+
+       r = cfg80211_get_chans_dfs_available(wiphy, chandef->center_freq1,
+                                            width);
+
+       /* If any of channels unavailable for cf1 just return */
+       if (!r)
+               return r;
+
+       switch (chandef->width) {
+       case NL80211_CHAN_WIDTH_80P80:
+               WARN_ON(!chandef->center_freq2);
+               r = cfg80211_get_chans_dfs_available(wiphy,
+                                                    chandef->center_freq2,
+                                                    width);
+       default:
+               WARN_ON(chandef->center_freq2);
+               break;
+       }
+
+       return r;
+}
 
-               /* check for the other flags */
-               if (c->flags & prohibited_flags & ~IEEE80211_CHAN_RADAR)
+
+static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
+                                       u32 center_freq, u32 bandwidth,
+                                       u32 prohibited_flags)
+{
+       struct ieee80211_channel *c;
+       u32 freq, start_freq, end_freq;
+
+       start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
+       end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
+
+       for (freq = start_freq; freq <= end_freq; freq += 20) {
+               c = ieee80211_get_channel(wiphy, freq);
+               if (!c || c->flags & prohibited_flags)
                        return false;
        }
 
@@ -462,14 +609,19 @@ bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
                             struct cfg80211_chan_def *chandef)
 {
        bool res;
+       u32 prohibited_flags = IEEE80211_CHAN_DISABLED |
+                              IEEE80211_CHAN_NO_IR |
+                              IEEE80211_CHAN_RADAR;
 
        trace_cfg80211_reg_can_beacon(wiphy, chandef);
 
-       res = cfg80211_chandef_usable(wiphy, chandef,
-                                     IEEE80211_CHAN_DISABLED |
-                                     IEEE80211_CHAN_PASSIVE_SCAN |
-                                     IEEE80211_CHAN_NO_IBSS |
-                                     IEEE80211_CHAN_RADAR);
+       if (cfg80211_chandef_dfs_required(wiphy, chandef) > 0 &&
+           cfg80211_chandef_dfs_available(wiphy, chandef)) {
+               /* We can skip IEEE80211_CHAN_NO_IR if chandef dfs available */
+               prohibited_flags = IEEE80211_CHAN_DISABLED;
+       }
+
+       res = cfg80211_chandef_usable(wiphy, chandef, prohibited_flags);
 
        trace_cfg80211_return_bool(res);
        return res;
@@ -510,6 +662,7 @@ cfg80211_get_chan_state(struct wireless_dev *wdev,
                                  : CHAN_MODE_EXCLUSIVE;
                        return;
                }
+               break;
        case NL80211_IFTYPE_STATION:
        case NL80211_IFTYPE_P2P_CLIENT:
                if (wdev->current_bss) {
index aff959e5a1b360e7cb467cade7f7d617544b3909..fc968c861ee46830ef9d33601e5f6cd3d597573c 100644 (file)
@@ -357,8 +357,6 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
        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);
@@ -566,6 +564,8 @@ int wiphy_register(struct wiphy *wiphy)
        /* 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) {
@@ -586,7 +586,7 @@ int wiphy_register(struct wiphy *wiphy)
        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);
index af10e59af2d86f418bd7cc4e69914c9bb31831c7..0a277c33bb027a879d854492ddde295be2c663a0 100644 (file)
@@ -317,9 +317,8 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid);
 void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev);
 int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
                          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);
 void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa,
                               const struct ieee80211_ht_cap *ht_capa_mask);
 void cfg80211_oper_and_vht_capa(struct ieee80211_vht_cap *vht_capa,
@@ -382,6 +381,19 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
                                 enum cfg80211_chan_mode chanmode,
                                 u8 radar_detect);
 
+/**
+ * cfg80211_chandef_dfs_usable - checks if chandef is DFS usable
+ * @wiphy: the wiphy to validate against
+ * @chandef: the channel definition to check
+ *
+ * Checks if chandef is usable and we can/need start CAC on such channel.
+ *
+ * Return: Return true if all channels available and at least
+ *        one channel require CAC (NL80211_DFS_USABLE)
+ */
+bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy,
+                                const struct cfg80211_chan_def *chandef);
+
 void cfg80211_set_dfs_state(struct wiphy *wiphy,
                            const struct cfg80211_chan_def *chandef,
                            enum nl80211_dfs_state dfs_state);
index 42ed274e81f4ca7debc59c4ae17137c35a0993d8..9a8217d2a90882f872451833cabe30159a64953f 100644 (file)
@@ -33,15 +33,7 @@ BEGIN {
        regdb = "const struct ieee80211_regdomain *reg_regdb[] = {\n"
 }
 
-/^[ \t]*#/ {
-       # Ignore
-}
-
-!active && /^[ \t]*$/ {
-       # Ignore
-}
-
-!active && /country/ {
+function parse_country_head() {
        country=$2
        sub(/:/, "", country)
        printf "static const struct ieee80211_regdomain regdom_%s = {\n", country
@@ -57,7 +49,8 @@ BEGIN {
        regdb = regdb "\t&regdom_" country ",\n"
 }
 
-active && /^[ \t]*\(/ {
+function parse_reg_rule()
+{
        start = $1
        sub(/\(/, "", start)
        end = $3
@@ -107,17 +100,21 @@ active && /^[ \t]*\(/ {
                } else if (flagarray[arg] == "PTMP-ONLY") {
                        flags = flags "\n\t\t\tNL80211_RRF_PTMP_ONLY | "
                } else if (flagarray[arg] == "PASSIVE-SCAN") {
-                       flags = flags "\n\t\t\tNL80211_RRF_PASSIVE_SCAN | "
+                       flags = flags "\n\t\t\tNL80211_RRF_NO_IR | "
                } else if (flagarray[arg] == "NO-IBSS") {
-                       flags = flags "\n\t\t\tNL80211_RRF_NO_IBSS | "
+                       flags = flags "\n\t\t\tNL80211_RRF_NO_IR | "
+               } else if (flagarray[arg] == "NO-IR") {
+                       flags = flags "\n\t\t\tNL80211_RRF_NO_IR | "
                }
+
        }
        flags = flags "0"
        printf "\t\tREG_RULE(%d, %d, %d, %d, %d, %s),\n", start, end, bw, gain, power, flags
        rules++
 }
 
-active && /^[ \t]*$/ {
+function print_tail_country()
+{
        active = 0
        printf "\t},\n"
        printf "\t.n_reg_rules = %d\n", rules
@@ -125,7 +122,29 @@ active && /^[ \t]*$/ {
        rules = 0;
 }
 
+/^[ \t]*#/ {
+       # Ignore
+}
+
+!active && /^[ \t]*$/ {
+       # Ignore
+}
+
+!active && /country/ {
+       parse_country_head()
+}
+
+active && /^[ \t]*\(/ {
+       parse_reg_rule()
+}
+
+active && /^[ \t]*$/ {
+       print_tail_country()
+}
+
 END {
+       if (active)
+               print_tail_country()
        print regdb "};"
        print ""
        print "int reg_regdb_size = ARRAY_SIZE(reg_regdb);"
index 9d797df56649c5a47fdf1f61e665ee31e4b77e7c..f79105712949528377199a86e45978237c104729 100644 (file)
@@ -274,7 +274,7 @@ int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
 
                        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;
@@ -345,7 +345,7 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
                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;
        }
index 0553fd4d85aeb4b9338d2661ba020448105a68e9..b0e1869de7de0b0775561c445389f4f2013beb58 100644 (file)
@@ -141,8 +141,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
 
                        for (i = 0; i < sband->n_channels; i++) {
                                chan = &sband->channels[i];
-                               if (chan->flags & (IEEE80211_CHAN_NO_IBSS |
-                                                  IEEE80211_CHAN_PASSIVE_SCAN |
+                               if (chan->flags & (IEEE80211_CHAN_NO_IR |
                                                   IEEE80211_CHAN_DISABLED |
                                                   IEEE80211_CHAN_RADAR))
                                        continue;
index 6a6b1c8e907df93e73b44a8912a3ae1fda5f80a5..52cca05044a898b977927f2c9e540b00d6811634 100644 (file)
@@ -520,9 +520,7 @@ void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev)
 
 int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
                          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)
 {
        const struct ieee80211_mgmt *mgmt;
        u16 stype;
@@ -533,10 +531,10 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
        if (!rdev->ops->mgmt_tx)
                return -EOPNOTSUPP;
 
-       if (len < 24 + 1)
+       if (params->len < 24 + 1)
                return -EINVAL;
 
-       mgmt = (const struct ieee80211_mgmt *) buf;
+       mgmt = (const struct ieee80211_mgmt *)params->buf;
 
        if (!ieee80211_is_mgmt(mgmt->frame_control))
                return -EINVAL;
@@ -615,9 +613,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
                return -EINVAL;
 
        /* Transmit the Action frame as requested by user space */
-       return rdev_mgmt_tx(rdev, wdev, chan, offchan,
-                           wait, buf, len, no_cck, dont_wait_for_ack,
-                           cookie);
+       return rdev_mgmt_tx(rdev, wdev, params, cookie);
 }
 
 bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm,
@@ -763,12 +759,12 @@ void cfg80211_radar_event(struct wiphy *wiphy,
 EXPORT_SYMBOL(cfg80211_radar_event);
 
 void cfg80211_cac_event(struct net_device *netdev,
+                       const struct cfg80211_chan_def *chandef,
                        enum nl80211_radar_event event, gfp_t gfp)
 {
        struct wireless_dev *wdev = netdev->ieee80211_ptr;
        struct wiphy *wiphy = wdev->wiphy;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-       struct cfg80211_chan_def chandef;
        unsigned long timeout;
 
        trace_cfg80211_cac_event(netdev, event);
@@ -779,14 +775,12 @@ void cfg80211_cac_event(struct net_device *netdev,
        if (WARN_ON(!wdev->channel))
                return;
 
-       cfg80211_chandef_create(&chandef, wdev->channel, NL80211_CHAN_NO_HT);
-
        switch (event) {
        case NL80211_RADAR_CAC_FINISHED:
                timeout = wdev->cac_start_time +
                          msecs_to_jiffies(IEEE80211_DFS_MIN_CAC_TIME_MS);
                WARN_ON(!time_after_eq(jiffies, timeout));
-               cfg80211_set_dfs_state(wiphy, &chandef, NL80211_DFS_AVAILABLE);
+               cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_AVAILABLE);
                break;
        case NL80211_RADAR_CAC_ABORTED:
                break;
@@ -796,6 +790,6 @@ void cfg80211_cac_event(struct net_device *netdev,
        }
        wdev->cac_started = false;
 
-       nl80211_radar_notify(rdev, &chandef, event, netdev, gfp);
+       nl80211_radar_notify(rdev, chandef, event, netdev, gfp);
 }
 EXPORT_SYMBOL(cfg80211_cac_event);
index a1eb21073176115a587f9eb1edf5d36dba582484..efaa23e562b4501045d314bcda149ece0e352a07 100644 (file)
@@ -564,12 +564,12 @@ static int nl80211_msg_put_channel(struct sk_buff *msg,
        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,10 +1247,6 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
                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;
@@ -1579,6 +1575,11 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
                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;
@@ -2187,7 +2188,7 @@ static inline u64 wdev_id(struct wireless_dev *wdev)
 }
 
 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));
 
@@ -3236,6 +3237,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
                        return PTR_ERR(params.acl);
        }
 
+       wdev_lock(wdev);
        err = rdev_start_ap(rdev, dev, &params);
        if (!err) {
                wdev->preset_chandef = params.chandef;
@@ -3244,6 +3246,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
                wdev->ssid_len = params.ssid_len;
                memcpy(wdev->ssid, params.ssid, wdev->ssid_len);
        }
+       wdev_unlock(wdev);
 
        kfree(params.acl);
 
@@ -3272,7 +3275,11 @@ static int nl80211_set_beacon(struct sk_buff *skb, struct genl_info *info)
        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)
@@ -4478,7 +4485,9 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
        struct net_device *dev = info->user_ptr[1];
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct bss_parameters params;
+       int err;
 
        memset(&params, 0, sizeof(params));
        /* default to not changing parameters */
@@ -4544,7 +4553,11 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
            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] = {
@@ -5098,7 +5111,7 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
        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])
@@ -5119,6 +5132,9 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
                        return -EINVAL;
        }
 
+       if (!reg_is_valid_request(alpha2))
+               return -EINVAL;
+
        size_of_regd = sizeof(struct ieee80211_regdomain) +
                       num_rules * sizeof(struct ieee80211_reg_rule);
 
@@ -5361,10 +5377,8 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
        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;
                }
@@ -5604,10 +5618,8 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
        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;
                }
@@ -5670,7 +5682,7 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
        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)
@@ -5810,7 +5822,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,
@@ -7443,10 +7459,10 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
        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;
@@ -7473,24 +7489,24 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
        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
@@ -7502,10 +7518,10 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
                        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;
@@ -7518,10 +7534,10 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
                }
        }
 
-       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;
 
@@ -10805,21 +10821,18 @@ void cfg80211_ch_switch_notify(struct net_device *dev,
        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);
 
@@ -10878,7 +10891,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)
 {
index 2c0f2b3c07cba7e4c2f50b17895d498c79d08dfb..b1b231324e102a44218bcf2354e52662fac78f5a 100644 (file)
@@ -70,7 +70,7 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
 
 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);
 
index 37ce9fdfe934345fe6603b399b8c4d3fd4f44ec1..a6c03ab14a0d47ea9a7f676dec76301804ab809b 100644 (file)
@@ -624,16 +624,12 @@ rdev_cancel_remain_on_channel(struct cfg80211_registered_device *rdev,
 
 static inline int rdev_mgmt_tx(struct cfg80211_registered_device *rdev,
                               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)
 {
        int ret;
-       trace_rdev_mgmt_tx(&rdev->wiphy, wdev, chan, offchan,
-                          wait, no_cck, dont_wait_for_ack);
-       ret = rdev->ops->mgmt_tx(&rdev->wiphy, wdev, chan, offchan,
-                                 wait, buf, len, no_cck,
-                                 dont_wait_for_ack, cookie);
+       trace_rdev_mgmt_tx(&rdev->wiphy, wdev, params);
+       ret = rdev->ops->mgmt_tx(&rdev->wiphy, wdev, params, cookie);
        trace_rdev_return_int_cookie(&rdev->wiphy, ret, *cookie);
        return ret;
 }
index 7da67fd0b4188a7cf3e3ded0ae2a64d565274947..ec54e1aac8e29c01e89ab4d0c6e9078bf112b5f9 100644 (file)
@@ -120,6 +120,21 @@ static const struct ieee80211_regdomain *get_wiphy_regdom(struct wiphy *wiphy)
        return rtnl_dereference(wiphy->regd);
 }
 
+static const char *reg_dfs_region_str(enum nl80211_dfs_regions dfs_region)
+{
+       switch (dfs_region) {
+       case NL80211_DFS_UNSET:
+               return "unset";
+       case NL80211_DFS_FCC:
+               return "FCC";
+       case NL80211_DFS_ETSI:
+               return "ETSI";
+       case NL80211_DFS_JP:
+               return "JP";
+       }
+       return "Unknown";
+}
+
 static void rcu_free_regdom(const struct ieee80211_regdomain *r)
 {
        if (!r)
@@ -163,35 +178,29 @@ static const struct ieee80211_regdomain world_regdom = {
                REG_RULE(2412-10, 2462+10, 40, 6, 20, 0),
                /* IEEE 802.11b/g, channels 12..13. */
                REG_RULE(2467-10, 2472+10, 40, 6, 20,
-                       NL80211_RRF_PASSIVE_SCAN |
-                       NL80211_RRF_NO_IBSS),
+                       NL80211_RRF_NO_IR),
                /* IEEE 802.11 channel 14 - Only JP enables
                 * this and for 802.11b only */
                REG_RULE(2484-10, 2484+10, 20, 6, 20,
-                       NL80211_RRF_PASSIVE_SCAN |
-                       NL80211_RRF_NO_IBSS |
+                       NL80211_RRF_NO_IR |
                        NL80211_RRF_NO_OFDM),
                /* IEEE 802.11a, channel 36..48 */
                REG_RULE(5180-10, 5240+10, 160, 6, 20,
-                        NL80211_RRF_PASSIVE_SCAN |
-                        NL80211_RRF_NO_IBSS),
+                        NL80211_RRF_NO_IR),
 
                /* IEEE 802.11a, channel 52..64 - DFS required */
                REG_RULE(5260-10, 5320+10, 160, 6, 20,
-                       NL80211_RRF_PASSIVE_SCAN |
-                       NL80211_RRF_NO_IBSS |
+                       NL80211_RRF_NO_IR |
                        NL80211_RRF_DFS),
 
                /* IEEE 802.11a, channel 100..144 - DFS required */
                REG_RULE(5500-10, 5720+10, 160, 6, 20,
-                       NL80211_RRF_PASSIVE_SCAN |
-                       NL80211_RRF_NO_IBSS |
+                       NL80211_RRF_NO_IR |
                        NL80211_RRF_DFS),
 
                /* IEEE 802.11a, channel 149..165 */
                REG_RULE(5745-10, 5825+10, 80, 6, 20,
-                       NL80211_RRF_PASSIVE_SCAN |
-                       NL80211_RRF_NO_IBSS),
+                       NL80211_RRF_NO_IR),
 
                /* IEEE 802.11ad (60gHz), channels 1..3 */
                REG_RULE(56160+2160*1-1080, 56160+2160*3+1080, 2160, 0, 0, 0),
@@ -208,11 +217,26 @@ static char user_alpha2[2];
 module_param(ieee80211_regdom, charp, 0444);
 MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
 
+static void reg_kfree_last_request(void)
+{
+       struct regulatory_request *lr;
+
+       lr = get_last_request();
+
+       if (lr != &core_request_world && lr)
+               kfree_rcu(lr, rcu_head);
+}
+
+static void reg_update_last_request(struct regulatory_request *request)
+{
+       reg_kfree_last_request();
+       rcu_assign_pointer(last_request, request);
+}
+
 static void reset_regdomains(bool full_reset,
                             const struct ieee80211_regdomain *new_regdom)
 {
        const struct ieee80211_regdomain *r;
-       struct regulatory_request *lr;
 
        ASSERT_RTNL();
 
@@ -235,10 +259,7 @@ static void reset_regdomains(bool full_reset,
        if (!full_reset)
                return;
 
-       lr = get_last_request();
-       if (lr != &core_request_world && lr)
-               kfree_rcu(lr, rcu_head);
-       rcu_assign_pointer(last_request, &core_request_world);
+       reg_update_last_request(&core_request_world);
 }
 
 /*
@@ -456,7 +477,15 @@ static int call_crda(const char *alpha2)
        return kobject_uevent(&reg_pdev->dev.kobj, KOBJ_CHANGE);
 }
 
-static bool reg_is_valid_request(const char *alpha2)
+static enum reg_request_treatment
+reg_call_crda(struct regulatory_request *request)
+{
+       if (call_crda(request->alpha2))
+               return REG_REQ_IGNORE;
+       return REG_REQ_OK;
+}
+
+bool reg_is_valid_request(const char *alpha2)
 {
        struct regulatory_request *lr = get_last_request();
 
@@ -556,6 +585,20 @@ static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range,
 #undef ONE_GHZ_IN_KHZ
 }
 
+/*
+ * Later on we can perhaps use the more restrictive DFS
+ * region but we don't have information for that yet so
+ * for now simply disallow conflicts.
+ */
+static enum nl80211_dfs_regions
+reg_intersect_dfs_region(const enum nl80211_dfs_regions dfs_region1,
+                        const enum nl80211_dfs_regions dfs_region2)
+{
+       if (dfs_region1 != dfs_region2)
+               return NL80211_DFS_UNSET;
+       return dfs_region1;
+}
+
 /*
  * Helper for regdom_intersect(), this does the real
  * mathematical intersection fun
@@ -687,6 +730,8 @@ regdom_intersect(const struct ieee80211_regdomain *rd1,
        rd->n_reg_rules = num_rules;
        rd->alpha2[0] = '9';
        rd->alpha2[1] = '8';
+       rd->dfs_region = reg_intersect_dfs_region(rd1->dfs_region,
+                                                 rd2->dfs_region);
 
        return rd;
 }
@@ -698,10 +743,8 @@ regdom_intersect(const struct ieee80211_regdomain *rd1,
 static u32 map_regdom_flags(u32 rd_flags)
 {
        u32 channel_flags = 0;
-       if (rd_flags & NL80211_RRF_PASSIVE_SCAN)
-               channel_flags |= IEEE80211_CHAN_PASSIVE_SCAN;
-       if (rd_flags & NL80211_RRF_NO_IBSS)
-               channel_flags |= IEEE80211_CHAN_NO_IBSS;
+       if (rd_flags & NL80211_RRF_NO_IR_ALL)
+               channel_flags |= IEEE80211_CHAN_NO_IR;
        if (rd_flags & NL80211_RRF_DFS)
                channel_flags |= IEEE80211_CHAN_RADAR;
        if (rd_flags & NL80211_RRF_NO_OFDM)
@@ -854,8 +897,18 @@ static void handle_channel(struct wiphy *wiphy,
                    PTR_ERR(reg_rule) == -ERANGE)
                        return;
 
-               REG_DBG_PRINT("Disabling freq %d MHz\n", chan->center_freq);
-               chan->flags |= IEEE80211_CHAN_DISABLED;
+               if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
+                   request_wiphy && request_wiphy == wiphy &&
+                   request_wiphy->regulatory_flags & REGULATORY_STRICT_REG) {
+                       REG_DBG_PRINT("Disabling freq %d MHz for good\n",
+                                     chan->center_freq);
+                       chan->orig_flags |= IEEE80211_CHAN_DISABLED;
+                       chan->flags = chan->orig_flags;
+               } else {
+                       REG_DBG_PRINT("Disabling freq %d MHz\n",
+                                     chan->center_freq);
+                       chan->flags |= IEEE80211_CHAN_DISABLED;
+               }
                return;
        }
 
@@ -873,7 +926,7 @@ static void handle_channel(struct wiphy *wiphy,
 
        if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
            request_wiphy && request_wiphy == wiphy &&
-           request_wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) {
+           request_wiphy->regulatory_flags & REGULATORY_STRICT_REG) {
                /*
                 * This guarantees the driver's requested regulatory domain
                 * will always be used as a base for further regulatory
@@ -899,13 +952,11 @@ static void handle_channel(struct wiphy *wiphy,
        chan->max_reg_power = (int) MBM_TO_DBM(power_rule->max_eirp);
        if (chan->orig_mpwr) {
                /*
-                * Devices that have their own custom regulatory domain
-                * but also use WIPHY_FLAG_STRICT_REGULATORY will follow the
-                * passed country IE power settings.
+                * Devices that use REGULATORY_COUNTRY_IE_FOLLOW_POWER
+                * will always follow the passed country IE power settings.
                 */
                if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE &&
-                   wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY &&
-                   wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY)
+                   wiphy->regulatory_flags & REGULATORY_COUNTRY_IE_FOLLOW_POWER)
                        chan->max_power = chan->max_reg_power;
                else
                        chan->max_power = min(chan->orig_mpwr,
@@ -975,8 +1026,8 @@ static bool reg_dev_ignore_cell_hint(struct wiphy *wiphy)
 
 static bool wiphy_strict_alpha2_regd(struct wiphy *wiphy)
 {
-       if (wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY &&
-           !(wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY))
+       if (wiphy->regulatory_flags & REGULATORY_STRICT_REG &&
+           !(wiphy->regulatory_flags & REGULATORY_CUSTOM_REG))
                return true;
        return false;
 }
@@ -994,7 +1045,7 @@ static bool ignore_reg_update(struct wiphy *wiphy,
        }
 
        if (initiator == NL80211_REGDOM_SET_BY_CORE &&
-           wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) {
+           wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) {
                REG_DBG_PRINT("Ignoring regulatory request set by %s "
                              "since the driver uses its own custom "
                              "regulatory domain\n",
@@ -1032,7 +1083,7 @@ static bool reg_is_world_roaming(struct wiphy *wiphy)
                return true;
 
        if (lr && lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE &&
-           wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY)
+           wiphy->regulatory_flags & REGULATORY_CUSTOM_REG)
                return true;
 
        return false;
@@ -1060,19 +1111,14 @@ static void handle_reg_beacon(struct wiphy *wiphy, unsigned int chan_idx,
        if (!reg_is_world_roaming(wiphy))
                return;
 
-       if (wiphy->flags & WIPHY_FLAG_DISABLE_BEACON_HINTS)
+       if (wiphy->regulatory_flags & REGULATORY_DISABLE_BEACON_HINTS)
                return;
 
        chan_before.center_freq = chan->center_freq;
        chan_before.flags = chan->flags;
 
-       if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) {
-               chan->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
-               channel_changed = true;
-       }
-
-       if (chan->flags & IEEE80211_CHAN_NO_IBSS) {
-               chan->flags &= ~IEEE80211_CHAN_NO_IBSS;
+       if (chan->flags & IEEE80211_CHAN_NO_IR) {
+               chan->flags &= ~IEEE80211_CHAN_NO_IR;
                channel_changed = true;
        }
 
@@ -1205,14 +1251,30 @@ static void reg_process_ht_flags(struct wiphy *wiphy)
                reg_process_ht_flags_band(wiphy, wiphy->bands[band]);
 }
 
+static void reg_call_notifier(struct wiphy *wiphy,
+                             struct regulatory_request *request)
+{
+       if (wiphy->reg_notifier)
+               wiphy->reg_notifier(wiphy, request);
+}
+
 static void wiphy_update_regulatory(struct wiphy *wiphy,
                                    enum nl80211_reg_initiator initiator)
 {
        enum ieee80211_band band;
        struct regulatory_request *lr = get_last_request();
 
-       if (ignore_reg_update(wiphy, initiator))
+       if (ignore_reg_update(wiphy, initiator)) {
+               /*
+                * Regulatory updates set by CORE are ignored for custom
+                * regulatory cards. Let us notify the changes to the driver,
+                * as some drivers used this to restore its orig_* reg domain.
+                */
+               if (initiator == NL80211_REGDOM_SET_BY_CORE &&
+                   wiphy->regulatory_flags & REGULATORY_CUSTOM_REG)
+                       reg_call_notifier(wiphy, lr);
                return;
+       }
 
        lr->dfs_region = get_cfg80211_regdom()->dfs_region;
 
@@ -1221,9 +1283,7 @@ static void wiphy_update_regulatory(struct wiphy *wiphy,
 
        reg_process_beacons(wiphy);
        reg_process_ht_flags(wiphy);
-
-       if (wiphy->reg_notifier)
-               wiphy->reg_notifier(wiphy, lr);
+       reg_call_notifier(wiphy, lr);
 }
 
 static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator)
@@ -1236,15 +1296,6 @@ static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator)
        list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
                wiphy = &rdev->wiphy;
                wiphy_update_regulatory(wiphy, initiator);
-               /*
-                * Regulatory updates set by CORE are ignored for custom
-                * regulatory cards. Let us notify the changes to the driver,
-                * as some drivers used this to restore its orig_* reg domain.
-                */
-               if (initiator == NL80211_REGDOM_SET_BY_CORE &&
-                   wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY &&
-                   wiphy->reg_notifier)
-                       wiphy->reg_notifier(wiphy, get_last_request());
        }
 }
 
@@ -1263,7 +1314,8 @@ static void handle_channel_custom(struct wiphy *wiphy,
        if (IS_ERR(reg_rule)) {
                REG_DBG_PRINT("Disabling freq %d MHz as custom regd has no rule that fits it\n",
                              chan->center_freq);
-               chan->flags = IEEE80211_CHAN_DISABLED;
+               chan->orig_flags |= IEEE80211_CHAN_DISABLED;
+               chan->flags = chan->orig_flags;
                return;
        }
 
@@ -1305,6 +1357,10 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy,
        enum ieee80211_band band;
        unsigned int bands_set = 0;
 
+       WARN(!(wiphy->regulatory_flags & REGULATORY_CUSTOM_REG),
+            "wiphy should have REGULATORY_CUSTOM_REG\n");
+       wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
+
        for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
                if (!wiphy->bands[band])
                        continue;
@@ -1320,225 +1376,285 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy,
 }
 EXPORT_SYMBOL(wiphy_apply_custom_regulatory);
 
-/* This has the logic which determines when a new request
- * should be ignored. */
-static enum reg_request_treatment
-get_reg_request_treatment(struct wiphy *wiphy,
-                         struct regulatory_request *pending_request)
+static void reg_set_request_processed(void)
 {
-       struct wiphy *last_wiphy = NULL;
+       bool need_more_processing = false;
        struct regulatory_request *lr = get_last_request();
 
-       /* All initial requests are respected */
-       if (!lr)
-               return REG_REQ_OK;
+       lr->processed = true;
 
-       switch (pending_request->initiator) {
-       case NL80211_REGDOM_SET_BY_CORE:
-               return REG_REQ_OK;
-       case NL80211_REGDOM_SET_BY_COUNTRY_IE:
-               if (reg_request_cell_base(lr)) {
-                       /* Trust a Cell base station over the AP's country IE */
-                       if (regdom_changes(pending_request->alpha2))
-                               return REG_REQ_IGNORE;
-                       return REG_REQ_ALREADY_SET;
-               }
+       spin_lock(&reg_requests_lock);
+       if (!list_empty(&reg_requests_list))
+               need_more_processing = true;
+       spin_unlock(&reg_requests_lock);
 
-               last_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx);
+       if (lr->initiator == NL80211_REGDOM_SET_BY_USER)
+               cancel_delayed_work(&reg_timeout);
 
-               if (unlikely(!is_an_alpha2(pending_request->alpha2)))
-                       return -EINVAL;
-               if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
-                       if (last_wiphy != wiphy) {
-                               /*
-                                * Two cards with two APs claiming different
-                                * Country IE alpha2s. We could
-                                * intersect them, but that seems unlikely
-                                * to be correct. Reject second one for now.
-                                */
-                               if (regdom_changes(pending_request->alpha2))
-                                       return REG_REQ_IGNORE;
-                               return REG_REQ_ALREADY_SET;
-                       }
-                       /*
-                        * Two consecutive Country IE hints on the same wiphy.
-                        * This should be picked up early by the driver/stack
-                        */
-                       if (WARN_ON(regdom_changes(pending_request->alpha2)))
-                               return REG_REQ_OK;
-                       return REG_REQ_ALREADY_SET;
-               }
-               return REG_REQ_OK;
-       case NL80211_REGDOM_SET_BY_DRIVER:
-               if (lr->initiator == NL80211_REGDOM_SET_BY_CORE) {
-                       if (regdom_changes(pending_request->alpha2))
-                               return REG_REQ_OK;
-                       return REG_REQ_ALREADY_SET;
-               }
+       if (need_more_processing)
+               schedule_work(&reg_work);
+}
 
-               /*
-                * This would happen if you unplug and plug your card
-                * back in or if you add a new device for which the previously
-                * loaded card also agrees on the regulatory domain.
-                */
-               if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
-                   !regdom_changes(pending_request->alpha2))
-                       return REG_REQ_ALREADY_SET;
+/**
+ * reg_process_hint_core - process core regulatory requests
+ * @pending_request: a pending core regulatory request
+ *
+ * The wireless subsystem can use this function to process
+ * a regulatory request issued by the regulatory core.
+ *
+ * Returns one of the different reg request treatment values.
+ */
+static enum reg_request_treatment
+reg_process_hint_core(struct regulatory_request *core_request)
+{
+
+       core_request->intersect = false;
+       core_request->processed = false;
+
+       reg_update_last_request(core_request);
 
+       return reg_call_crda(core_request);
+}
+
+static enum reg_request_treatment
+__reg_process_hint_user(struct regulatory_request *user_request)
+{
+       struct regulatory_request *lr = get_last_request();
+
+       if (reg_request_cell_base(user_request))
+               return reg_ignore_cell_hint(user_request);
+
+       if (reg_request_cell_base(lr))
+               return REG_REQ_IGNORE;
+
+       if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)
                return REG_REQ_INTERSECT;
-       case NL80211_REGDOM_SET_BY_USER:
-               if (reg_request_cell_base(pending_request))
-                       return reg_ignore_cell_hint(pending_request);
+       /*
+        * If the user knows better the user should set the regdom
+        * to their country before the IE is picked up
+        */
+       if (lr->initiator == NL80211_REGDOM_SET_BY_USER &&
+           lr->intersect)
+               return REG_REQ_IGNORE;
+       /*
+        * Process user requests only after previous user/driver/core
+        * requests have been processed
+        */
+       if ((lr->initiator == NL80211_REGDOM_SET_BY_CORE ||
+            lr->initiator == NL80211_REGDOM_SET_BY_DRIVER ||
+            lr->initiator == NL80211_REGDOM_SET_BY_USER) &&
+           regdom_changes(lr->alpha2))
+               return REG_REQ_IGNORE;
 
-               if (reg_request_cell_base(lr))
-                       return REG_REQ_IGNORE;
+       if (!regdom_changes(user_request->alpha2))
+               return REG_REQ_ALREADY_SET;
 
-               if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)
-                       return REG_REQ_INTERSECT;
-               /*
-                * If the user knows better the user should set the regdom
-                * to their country before the IE is picked up
-                */
-               if (lr->initiator == NL80211_REGDOM_SET_BY_USER &&
-                   lr->intersect)
-                       return REG_REQ_IGNORE;
-               /*
-                * Process user requests only after previous user/driver/core
-                * requests have been processed
-                */
-               if ((lr->initiator == NL80211_REGDOM_SET_BY_CORE ||
-                    lr->initiator == NL80211_REGDOM_SET_BY_DRIVER ||
-                    lr->initiator == NL80211_REGDOM_SET_BY_USER) &&
-                   regdom_changes(lr->alpha2))
-                       return REG_REQ_IGNORE;
+       return REG_REQ_OK;
+}
 
-               if (!regdom_changes(pending_request->alpha2))
-                       return REG_REQ_ALREADY_SET;
+/**
+ * reg_process_hint_user - process user regulatory requests
+ * @user_request: a pending user regulatory request
+ *
+ * The wireless subsystem can use this function to process
+ * a regulatory request initiated by userspace.
+ *
+ * Returns one of the different reg request treatment values.
+ */
+static enum reg_request_treatment
+reg_process_hint_user(struct regulatory_request *user_request)
+{
+       enum reg_request_treatment treatment;
 
-               return REG_REQ_OK;
+       treatment = __reg_process_hint_user(user_request);
+       if (treatment == REG_REQ_IGNORE ||
+           treatment == REG_REQ_ALREADY_SET) {
+               kfree(user_request);
+               return treatment;
        }
 
-       return REG_REQ_IGNORE;
+       user_request->intersect = treatment == REG_REQ_INTERSECT;
+       user_request->processed = false;
+
+       reg_update_last_request(user_request);
+
+       user_alpha2[0] = user_request->alpha2[0];
+       user_alpha2[1] = user_request->alpha2[1];
+
+       return reg_call_crda(user_request);
 }
 
-static void reg_set_request_processed(void)
+static enum reg_request_treatment
+__reg_process_hint_driver(struct regulatory_request *driver_request)
 {
-       bool need_more_processing = false;
        struct regulatory_request *lr = get_last_request();
 
-       lr->processed = true;
-
-       spin_lock(&reg_requests_lock);
-       if (!list_empty(&reg_requests_list))
-               need_more_processing = true;
-       spin_unlock(&reg_requests_lock);
+       if (lr->initiator == NL80211_REGDOM_SET_BY_CORE) {
+               if (regdom_changes(driver_request->alpha2))
+                       return REG_REQ_OK;
+               return REG_REQ_ALREADY_SET;
+       }
 
-       if (lr->initiator == NL80211_REGDOM_SET_BY_USER)
-               cancel_delayed_work(&reg_timeout);
+       /*
+        * This would happen if you unplug and plug your card
+        * back in or if you add a new device for which the previously
+        * loaded card also agrees on the regulatory domain.
+        */
+       if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
+           !regdom_changes(driver_request->alpha2))
+               return REG_REQ_ALREADY_SET;
 
-       if (need_more_processing)
-               schedule_work(&reg_work);
+       return REG_REQ_INTERSECT;
 }
 
 /**
- * __regulatory_hint - hint to the wireless core a regulatory domain
- * @wiphy: if the hint comes from country information from an AP, this
- *     is required to be set to the wiphy that received the information
- * @pending_request: the regulatory request currently being processed
+ * reg_process_hint_driver - process driver regulatory requests
+ * @driver_request: a pending driver regulatory request
  *
- * The Wireless subsystem can use this function to hint to the wireless core
- * what it believes should be the current regulatory domain.
+ * The wireless subsystem can use this function to process
+ * a regulatory request issued by an 802.11 driver.
  *
  * Returns one of the different reg request treatment values.
  */
 static enum reg_request_treatment
-__regulatory_hint(struct wiphy *wiphy,
-                 struct regulatory_request *pending_request)
+reg_process_hint_driver(struct wiphy *wiphy,
+                       struct regulatory_request *driver_request)
 {
        const struct ieee80211_regdomain *regd;
-       bool intersect = false;
        enum reg_request_treatment treatment;
-       struct regulatory_request *lr;
 
-       treatment = get_reg_request_treatment(wiphy, pending_request);
+       treatment = __reg_process_hint_driver(driver_request);
 
        switch (treatment) {
-       case REG_REQ_INTERSECT:
-               if (pending_request->initiator ==
-                   NL80211_REGDOM_SET_BY_DRIVER) {
-                       regd = reg_copy_regd(get_cfg80211_regdom());
-                       if (IS_ERR(regd)) {
-                               kfree(pending_request);
-                               return PTR_ERR(regd);
-                       }
-                       rcu_assign_pointer(wiphy->regd, regd);
-               }
-               intersect = true;
-               break;
        case REG_REQ_OK:
                break;
-       default:
-               /*
-                * If the regulatory domain being requested by the
-                * driver has already been set just copy it to the
-                * wiphy
-                */
-               if (treatment == REG_REQ_ALREADY_SET &&
-                   pending_request->initiator == NL80211_REGDOM_SET_BY_DRIVER) {
-                       regd = reg_copy_regd(get_cfg80211_regdom());
-                       if (IS_ERR(regd)) {
-                               kfree(pending_request);
-                               return REG_REQ_IGNORE;
-                       }
-                       treatment = REG_REQ_ALREADY_SET;
-                       rcu_assign_pointer(wiphy->regd, regd);
-                       goto new_request;
-               }
-               kfree(pending_request);
+       case REG_REQ_IGNORE:
+               kfree(driver_request);
                return treatment;
+       case REG_REQ_INTERSECT:
+               /* fall through */
+       case REG_REQ_ALREADY_SET:
+               regd = reg_copy_regd(get_cfg80211_regdom());
+               if (IS_ERR(regd)) {
+                       kfree(driver_request);
+                       return REG_REQ_IGNORE;
+               }
+               rcu_assign_pointer(wiphy->regd, regd);
        }
 
-new_request:
-       lr = get_last_request();
-       if (lr != &core_request_world && lr)
-               kfree_rcu(lr, rcu_head);
 
-       pending_request->intersect = intersect;
-       pending_request->processed = false;
-       rcu_assign_pointer(last_request, pending_request);
-       lr = pending_request;
+       driver_request->intersect = treatment == REG_REQ_INTERSECT;
+       driver_request->processed = false;
 
-       pending_request = NULL;
+       reg_update_last_request(driver_request);
 
-       if (lr->initiator == NL80211_REGDOM_SET_BY_USER) {
-               user_alpha2[0] = lr->alpha2[0];
-               user_alpha2[1] = lr->alpha2[1];
+       /*
+        * Since CRDA will not be called in this case as we already
+        * have applied the requested regulatory domain before we just
+        * inform userspace we have processed the request
+        */
+       if (treatment == REG_REQ_ALREADY_SET) {
+               nl80211_send_reg_change_event(driver_request);
+               reg_set_request_processed();
+               return treatment;
        }
 
-       /* When r == REG_REQ_INTERSECT we do need to call CRDA */
-       if (treatment != REG_REQ_OK && treatment != REG_REQ_INTERSECT) {
+       return reg_call_crda(driver_request);
+}
+
+static enum reg_request_treatment
+__reg_process_hint_country_ie(struct wiphy *wiphy,
+                             struct regulatory_request *country_ie_request)
+{
+       struct wiphy *last_wiphy = NULL;
+       struct regulatory_request *lr = get_last_request();
+
+       if (reg_request_cell_base(lr)) {
+               /* Trust a Cell base station over the AP's country IE */
+               if (regdom_changes(country_ie_request->alpha2))
+                       return REG_REQ_IGNORE;
+               return REG_REQ_ALREADY_SET;
+       } else {
+               if (wiphy->regulatory_flags & REGULATORY_COUNTRY_IE_IGNORE)
+                       return REG_REQ_IGNORE;
+       }
+
+       if (unlikely(!is_an_alpha2(country_ie_request->alpha2)))
+               return -EINVAL;
+
+       if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE)
+               return REG_REQ_OK;
+
+       last_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx);
+
+       if (last_wiphy != wiphy) {
                /*
-                * Since CRDA will not be called in this case as we already
-                * have applied the requested regulatory domain before we just
-                * inform userspace we have processed the request
+                * Two cards with two APs claiming different
+                * Country IE alpha2s. We could
+                * intersect them, but that seems unlikely
+                * to be correct. Reject second one for now.
                 */
-               if (treatment == REG_REQ_ALREADY_SET) {
-                       nl80211_send_reg_change_event(lr);
-                       reg_set_request_processed();
-               }
-               return treatment;
+               if (regdom_changes(country_ie_request->alpha2))
+                       return REG_REQ_IGNORE;
+               return REG_REQ_ALREADY_SET;
        }
+       /*
+        * Two consecutive Country IE hints on the same wiphy.
+        * This should be picked up early by the driver/stack
+        */
+       if (WARN_ON(regdom_changes(country_ie_request->alpha2)))
+               return REG_REQ_OK;
+       return REG_REQ_ALREADY_SET;
+}
+
+/**
+ * reg_process_hint_country_ie - process regulatory requests from country IEs
+ * @country_ie_request: a regulatory request from a country IE
+ *
+ * The wireless subsystem can use this function to process
+ * a regulatory request issued by a country Information Element.
+ *
+ * Returns one of the different reg request treatment values.
+ */
+static enum reg_request_treatment
+reg_process_hint_country_ie(struct wiphy *wiphy,
+                           struct regulatory_request *country_ie_request)
+{
+       enum reg_request_treatment treatment;
+
+       treatment = __reg_process_hint_country_ie(wiphy, country_ie_request);
 
-       if (call_crda(lr->alpha2))
+       switch (treatment) {
+       case REG_REQ_OK:
+               break;
+       case REG_REQ_IGNORE:
+               /* fall through */
+       case REG_REQ_ALREADY_SET:
+               kfree(country_ie_request);
+               return treatment;
+       case REG_REQ_INTERSECT:
+               kfree(country_ie_request);
+               /*
+                * This doesn't happen yet, not sure we
+                * ever want to support it for this case.
+                */
+               WARN_ONCE(1, "Unexpected intersection for country IEs");
                return REG_REQ_IGNORE;
-       return REG_REQ_OK;
+       }
+
+       country_ie_request->intersect = false;
+       country_ie_request->processed = false;
+
+       reg_update_last_request(country_ie_request);
+
+       return reg_call_crda(country_ie_request);
 }
 
 /* This processes *all* regulatory hints */
-static void reg_process_hint(struct regulatory_request *reg_request,
-                            enum nl80211_reg_initiator reg_initiator)
+static void reg_process_hint(struct regulatory_request *reg_request)
 {
        struct wiphy *wiphy = NULL;
+       enum reg_request_treatment treatment;
 
        if (WARN_ON(!reg_request->alpha2))
                return;
@@ -1546,23 +1662,37 @@ static void reg_process_hint(struct regulatory_request *reg_request,
        if (reg_request->wiphy_idx != WIPHY_IDX_INVALID)
                wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx);
 
-       if (reg_initiator == NL80211_REGDOM_SET_BY_DRIVER && !wiphy) {
+       if (reg_request->initiator == NL80211_REGDOM_SET_BY_DRIVER && !wiphy) {
                kfree(reg_request);
                return;
        }
 
-       switch (__regulatory_hint(wiphy, reg_request)) {
-       case REG_REQ_ALREADY_SET:
-               /* This is required so that the orig_* parameters are saved */
-               if (wiphy && wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY)
-                       wiphy_update_regulatory(wiphy, reg_initiator);
+       switch (reg_request->initiator) {
+       case NL80211_REGDOM_SET_BY_CORE:
+               reg_process_hint_core(reg_request);
+               return;
+       case NL80211_REGDOM_SET_BY_USER:
+               treatment = reg_process_hint_user(reg_request);
+               if (treatment == REG_REQ_OK ||
+                   treatment == REG_REQ_ALREADY_SET)
+                       return;
+               schedule_delayed_work(&reg_timeout, msecs_to_jiffies(3142));
+               return;
+       case NL80211_REGDOM_SET_BY_DRIVER:
+               treatment = reg_process_hint_driver(wiphy, reg_request);
                break;
-       default:
-               if (reg_initiator == NL80211_REGDOM_SET_BY_USER)
-                       schedule_delayed_work(&reg_timeout,
-                                             msecs_to_jiffies(3142));
+       case NL80211_REGDOM_SET_BY_COUNTRY_IE:
+               treatment = reg_process_hint_country_ie(wiphy, reg_request);
                break;
+       default:
+               WARN(1, "invalid initiator %d\n", reg_request->initiator);
+               return;
        }
+
+       /* This is required so that the orig_* parameters are saved */
+       if (treatment == REG_REQ_ALREADY_SET && wiphy &&
+           wiphy->regulatory_flags & REGULATORY_STRICT_REG)
+               wiphy_update_regulatory(wiphy, reg_request->initiator);
 }
 
 /*
@@ -1596,7 +1726,7 @@ static void reg_process_pending_hints(void)
 
        spin_unlock(&reg_requests_lock);
 
-       reg_process_hint(reg_request, reg_request->initiator);
+       reg_process_hint(reg_request);
 }
 
 /* Processes beacon hints -- this has nothing to do with country IEs */
@@ -1888,7 +2018,7 @@ static void restore_regulatory_settings(bool reset_user)
        world_alpha2[1] = cfg80211_world_regdom->alpha2[1];
 
        list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
-               if (rdev->wiphy.flags & WIPHY_FLAG_CUSTOM_REGULATORY)
+               if (rdev->wiphy.regulatory_flags & REGULATORY_CUSTOM_REG)
                        restore_custom_reg_settings(&rdev->wiphy);
        }
 
@@ -2016,7 +2146,7 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd)
        }
 }
 
-bool reg_supported_dfs_region(u8 dfs_region)
+bool reg_supported_dfs_region(enum nl80211_dfs_regions dfs_region)
 {
        switch (dfs_region) {
        case NL80211_DFS_UNSET:
@@ -2031,27 +2161,6 @@ bool reg_supported_dfs_region(u8 dfs_region)
        }
 }
 
-static void print_dfs_region(u8 dfs_region)
-{
-       if (!dfs_region)
-               return;
-
-       switch (dfs_region) {
-       case NL80211_DFS_FCC:
-               pr_info(" DFS Master region FCC");
-               break;
-       case NL80211_DFS_ETSI:
-               pr_info(" DFS Master region ETSI");
-               break;
-       case NL80211_DFS_JP:
-               pr_info(" DFS Master region JP");
-               break;
-       default:
-               pr_info(" DFS Master region Unknown");
-               break;
-       }
-}
-
 static void print_regdomain(const struct ieee80211_regdomain *rd)
 {
        struct regulatory_request *lr = get_last_request();
@@ -2083,7 +2192,7 @@ static void print_regdomain(const struct ieee80211_regdomain *rd)
                }
        }
 
-       print_dfs_region(rd->dfs_region);
+       pr_info(" DFS Master region: %s", reg_dfs_region_str(rd->dfs_region));
        print_rd_rules(rd);
 }
 
@@ -2093,48 +2202,60 @@ static void print_regdomain_info(const struct ieee80211_regdomain *rd)
        print_rd_rules(rd);
 }
 
-/* Takes ownership of rd only if it doesn't fail */
-static int __set_regdom(const struct ieee80211_regdomain *rd)
+static int reg_set_rd_core(const struct ieee80211_regdomain *rd)
+{
+       if (!is_world_regdom(rd->alpha2))
+               return -EINVAL;
+       update_world_regdomain(rd);
+       return 0;
+}
+
+static int reg_set_rd_user(const struct ieee80211_regdomain *rd,
+                          struct regulatory_request *user_request)
 {
-       const struct ieee80211_regdomain *regd;
        const struct ieee80211_regdomain *intersected_rd = NULL;
-       struct wiphy *request_wiphy;
-       struct regulatory_request *lr = get_last_request();
 
-       /* Some basic sanity checks first */
+       if (is_world_regdom(rd->alpha2))
+               return -EINVAL;
+
+       if (!regdom_changes(rd->alpha2))
+               return -EALREADY;
 
-       if (!reg_is_valid_request(rd->alpha2))
+       if (!is_valid_rd(rd)) {
+               pr_err("Invalid regulatory domain detected:\n");
+               print_regdomain_info(rd);
                return -EINVAL;
+       }
 
-       if (is_world_regdom(rd->alpha2)) {
-               update_world_regdomain(rd);
+       if (!user_request->intersect) {
+               reset_regdomains(false, rd);
                return 0;
        }
 
-       if (!is_alpha2_set(rd->alpha2) && !is_an_alpha2(rd->alpha2) &&
-           !is_unknown_alpha2(rd->alpha2))
+       intersected_rd = regdom_intersect(rd, get_cfg80211_regdom());
+       if (!intersected_rd)
                return -EINVAL;
 
-       /*
-        * Lets only bother proceeding on the same alpha2 if the current
-        * rd is non static (it means CRDA was present and was used last)
-        * and the pending request came in from a country IE
-        */
-       if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) {
-               /*
-                * If someone else asked us to change the rd lets only bother
-                * checking if the alpha2 changes if CRDA was already called
-                */
-               if (!regdom_changes(rd->alpha2))
-                       return -EALREADY;
-       }
+       kfree(rd);
+       rd = NULL;
+       reset_regdomains(false, intersected_rd);
 
-       /*
-        * Now lets set the regulatory domain, update all driver channels
-        * and finally inform them of what we have done, in case they want
-        * to review or adjust their own settings based on their own
-        * internal EEPROM data
-        */
+       return 0;
+}
+
+static int reg_set_rd_driver(const struct ieee80211_regdomain *rd,
+                            struct regulatory_request *driver_request)
+{
+       const struct ieee80211_regdomain *regd;
+       const struct ieee80211_regdomain *intersected_rd = NULL;
+       const struct ieee80211_regdomain *tmp;
+       struct wiphy *request_wiphy;
+
+       if (is_world_regdom(rd->alpha2))
+               return -EINVAL;
+
+       if (!regdom_changes(rd->alpha2))
+               return -EALREADY;
 
        if (!is_valid_rd(rd)) {
                pr_err("Invalid regulatory domain detected:\n");
@@ -2142,29 +2263,13 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
                return -EINVAL;
        }
 
-       request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx);
-       if (!request_wiphy &&
-           (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER ||
-            lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)) {
+       request_wiphy = wiphy_idx_to_wiphy(driver_request->wiphy_idx);
+       if (!request_wiphy) {
                schedule_delayed_work(&reg_timeout, 0);
                return -ENODEV;
        }
 
-       if (!lr->intersect) {
-               if (lr->initiator != NL80211_REGDOM_SET_BY_DRIVER) {
-                       reset_regdomains(false, rd);
-                       return 0;
-               }
-
-               /*
-                * For a driver hint, lets copy the regulatory domain the
-                * driver wanted to the wiphy to deal with conflicts
-                */
-
-               /*
-                * Userspace could have sent two replies with only
-                * one kernel request.
-                */
+       if (!driver_request->intersect) {
                if (request_wiphy->regd)
                        return -EALREADY;
 
@@ -2177,38 +2282,59 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
                return 0;
        }
 
-       /* Intersection requires a bit more work */
+       intersected_rd = regdom_intersect(rd, get_cfg80211_regdom());
+       if (!intersected_rd)
+               return -EINVAL;
 
-       if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) {
-               intersected_rd = regdom_intersect(rd, get_cfg80211_regdom());
-               if (!intersected_rd)
-                       return -EINVAL;
+       /*
+        * We can trash what CRDA provided now.
+        * However if a driver requested this specific regulatory
+        * domain we keep it for its private use
+        */
+       tmp = get_wiphy_regdom(request_wiphy);
+       rcu_assign_pointer(request_wiphy->regd, rd);
+       rcu_free_regdom(tmp);
 
-               /*
-                * We can trash what CRDA provided now.
-                * However if a driver requested this specific regulatory
-                * domain we keep it for its private use
-                */
-               if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER) {
-                       const struct ieee80211_regdomain *tmp;
+       rd = NULL;
 
-                       tmp = get_wiphy_regdom(request_wiphy);
-                       rcu_assign_pointer(request_wiphy->regd, rd);
-                       rcu_free_regdom(tmp);
-               } else {
-                       kfree(rd);
-               }
+       reset_regdomains(false, intersected_rd);
 
-               rd = NULL;
+       return 0;
+}
 
-               reset_regdomains(false, intersected_rd);
+static int reg_set_rd_country_ie(const struct ieee80211_regdomain *rd,
+                                struct regulatory_request *country_ie_request)
+{
+       struct wiphy *request_wiphy;
 
-               return 0;
+       if (!is_alpha2_set(rd->alpha2) && !is_an_alpha2(rd->alpha2) &&
+           !is_unknown_alpha2(rd->alpha2))
+               return -EINVAL;
+
+       /*
+        * Lets only bother proceeding on the same alpha2 if the current
+        * rd is non static (it means CRDA was present and was used last)
+        * and the pending request came in from a country IE
+        */
+
+       if (!is_valid_rd(rd)) {
+               pr_err("Invalid regulatory domain detected:\n");
+               print_regdomain_info(rd);
+               return -EINVAL;
        }
 
-       return -EINVAL;
-}
+       request_wiphy = wiphy_idx_to_wiphy(country_ie_request->wiphy_idx);
+       if (!request_wiphy) {
+               schedule_delayed_work(&reg_timeout, 0);
+               return -ENODEV;
+       }
+
+       if (country_ie_request->intersect)
+               return -EINVAL;
 
+       reset_regdomains(false, rd);
+       return 0;
+}
 
 /*
  * Use this call to set the current regulatory domain. Conflicts with
@@ -2220,10 +2346,32 @@ int set_regdom(const struct ieee80211_regdomain *rd)
        struct regulatory_request *lr;
        int r;
 
+       if (!reg_is_valid_request(rd->alpha2)) {
+               kfree(rd);
+               return -EINVAL;
+       }
+
        lr = get_last_request();
 
        /* Note that this doesn't update the wiphys, this is done below */
-       r = __set_regdom(rd);
+       switch (lr->initiator) {
+       case NL80211_REGDOM_SET_BY_CORE:
+               r = reg_set_rd_core(rd);
+               break;
+       case NL80211_REGDOM_SET_BY_USER:
+               r = reg_set_rd_user(rd, lr);
+               break;
+       case NL80211_REGDOM_SET_BY_DRIVER:
+               r = reg_set_rd_driver(rd, lr);
+               break;
+       case NL80211_REGDOM_SET_BY_COUNTRY_IE:
+               r = reg_set_rd_country_ie(rd, lr);
+               break;
+       default:
+               WARN(1, "invalid initiator %d\n", lr->initiator);
+               return -EINVAL;
+       }
+
        if (r) {
                if (r == -EALREADY)
                        reg_set_request_processed();
index 9677e3c13da98da5b00f34e112b0562512b6fc65..cc4c2c0a67236cd2801f954e0a8e15dc4b5adea5 100644 (file)
@@ -18,8 +18,9 @@
 
 extern const struct ieee80211_regdomain __rcu *cfg80211_regdomain;
 
+bool reg_is_valid_request(const char *alpha2);
 bool is_world_regdom(const char *alpha2);
-bool reg_supported_dfs_region(u8 dfs_region);
+bool reg_supported_dfs_region(enum nl80211_dfs_regions dfs_region);
 
 int regulatory_hint_user(const char *alpha2,
                         enum nl80211_user_reg_hint_type user_reg_hint_type);
index ba5f0d6614d5d4cee4d08c609bb192dd501f0b34..f7aa7a72d9bc928aa7d24153d709e13634773b06 100644 (file)
@@ -1653,9 +1653,8 @@ TRACE_EVENT(rdev_cancel_remain_on_channel,
 
 TRACE_EVENT(rdev_mgmt_tx,
        TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
-                struct ieee80211_channel *chan, bool offchan,
-                unsigned int wait, bool no_cck, bool dont_wait_for_ack),
-       TP_ARGS(wiphy, wdev, chan, offchan, wait, no_cck, dont_wait_for_ack),
+                struct cfg80211_mgmt_tx_params *params),
+       TP_ARGS(wiphy, wdev, params),
        TP_STRUCT__entry(
                WIPHY_ENTRY
                WDEV_ENTRY
@@ -1668,11 +1667,11 @@ TRACE_EVENT(rdev_mgmt_tx,
        TP_fast_assign(
                WIPHY_ASSIGN;
                WDEV_ASSIGN;
-               CHAN_ASSIGN(chan);
-               __entry->offchan = offchan;
-               __entry->wait = wait;
-               __entry->no_cck = no_cck;
-               __entry->dont_wait_for_ack = dont_wait_for_ack;
+               CHAN_ASSIGN(params->chan);
+               __entry->offchan = params->offchan;
+               __entry->wait = params->wait;
+               __entry->no_cck = params->no_cck;
+               __entry->dont_wait_for_ack = params->dont_wait_for_ack;
        ),
        TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", " CHAN_PR_FMT ", offchan: %s,"
                  " wait: %u, no cck: %s, dont wait for ack: %s",