cfg80211: fix a locking issue (#20098)
authorFelix Fietkau <nbd@openwrt.org>
Sat, 18 Jul 2015 19:10:38 +0000 (19:10 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Sat, 18 Jul 2015 19:10:38 +0000 (19:10 +0000)
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
SVN-Revision: 46413

package/kernel/mac80211/patches/308-cfg80211-use-RTNL-locked-reg_can_beacon-for-IR-relax.patch [new file with mode: 0644]
package/kernel/mac80211/patches/522-mac80211_configure_antenna_gain.patch
package/kernel/mac80211/patches/862-brcmfmac-workaround-bug-with-some-inconsistent-BSSes.patch
package/kernel/mac80211/patches/863-brcmfmac-set-wiphy-s-addresses-to-provide-valid-MACs.patch
package/kernel/mac80211/patches/921-ath10k_init_devices_synchronously.patch

diff --git a/package/kernel/mac80211/patches/308-cfg80211-use-RTNL-locked-reg_can_beacon-for-IR-relax.patch b/package/kernel/mac80211/patches/308-cfg80211-use-RTNL-locked-reg_can_beacon-for-IR-relax.patch
new file mode 100644 (file)
index 0000000..d2a1cdc
--- /dev/null
@@ -0,0 +1,216 @@
+From: Arik Nemtsov <arik@wizery.com>
+Date: Wed, 8 Jul 2015 15:41:44 +0300
+Subject: [PATCH] cfg80211: use RTNL locked reg_can_beacon for IR-relaxation
+
+The RTNL is required to check for IR-relaxation conditions that allow
+more channels to beacon. Export an RTNL locked version of reg_can_beacon
+and use it where possible in AP/STA interface type flows, where
+IR-relaxation may be applicable.
+
+Fixes: 06f207fc5418 ("cfg80211: change GO_CONCURRENT to IR_CONCURRENT for STA")
+Signed-off-by: Arik Nemtsov <arikx.nemtsov@intel.com>
+Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
+---
+
+--- a/include/net/cfg80211.h
++++ b/include/net/cfg80211.h
+@@ -4871,6 +4871,23 @@ bool cfg80211_reg_can_beacon(struct wiph
+                            struct cfg80211_chan_def *chandef,
+                            enum nl80211_iftype iftype);
++/**
++ * cfg80211_reg_can_beacon_relax - check if beaconing is allowed with relaxation
++ * @wiphy: the wiphy
++ * @chandef: the channel definition
++ * @iftype: interface type
++ *
++ * Return: %true if there is no secondary channel or the secondary channel(s)
++ * can be used for beaconing (i.e. is not a radar channel etc.). This version
++ * also checks if IR-relaxation conditions apply, to allow beaconing under
++ * more permissive conditions.
++ *
++ * Requires the RTNL to be held.
++ */
++bool cfg80211_reg_can_beacon_relax(struct wiphy *wiphy,
++                                 struct cfg80211_chan_def *chandef,
++                                 enum nl80211_iftype iftype);
++
+ /*
+  * cfg80211_ch_switch_notify - update wdev channel and notify userspace
+  * @dev: the device which switched channels
+--- a/net/mac80211/tdls.c
++++ b/net/mac80211/tdls.c
+@@ -69,6 +69,7 @@ ieee80211_tdls_add_subband(struct ieee80
+       struct ieee80211_channel *ch;
+       struct cfg80211_chan_def chandef;
+       int i, subband_start;
++      struct wiphy *wiphy = sdata->local->hw.wiphy;
+       for (i = start; i <= end; i += spacing) {
+               if (!ch_cnt)
+@@ -79,9 +80,8 @@ ieee80211_tdls_add_subband(struct ieee80
+                       /* we will be active on the channel */
+                       cfg80211_chandef_create(&chandef, ch,
+                                               NL80211_CHAN_NO_HT);
+-                      if (cfg80211_reg_can_beacon(sdata->local->hw.wiphy,
+-                                                  &chandef,
+-                                                  sdata->wdev.iftype)) {
++                      if (cfg80211_reg_can_beacon_relax(wiphy, &chandef,
++                                                        sdata->wdev.iftype)) {
+                               ch_cnt++;
+                               /*
+                                * check if the next channel is also part of
+--- a/net/wireless/chan.c
++++ b/net/wireless/chan.c
+@@ -797,23 +797,18 @@ static bool cfg80211_ir_permissive_chan(
+       return false;
+ }
+-bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
+-                           struct cfg80211_chan_def *chandef,
+-                           enum nl80211_iftype iftype)
++static bool _cfg80211_reg_can_beacon(struct wiphy *wiphy,
++                                   struct cfg80211_chan_def *chandef,
++                                   enum nl80211_iftype iftype,
++                                   bool check_no_ir)
+ {
+       bool res;
+       u32 prohibited_flags = IEEE80211_CHAN_DISABLED |
+                              IEEE80211_CHAN_RADAR;
+-      trace_cfg80211_reg_can_beacon(wiphy, chandef, iftype);
++      trace_cfg80211_reg_can_beacon(wiphy, chandef, iftype, check_no_ir);
+-      /*
+-       * Under certain conditions suggested by some regulatory bodies a
+-       * GO/STA can IR on channels marked with IEEE80211_NO_IR. Set this flag
+-       * only if such relaxations are not enabled and the conditions are not
+-       * met.
+-       */
+-      if (!cfg80211_ir_permissive_chan(wiphy, iftype, chandef->chan))
++      if (check_no_ir)
+               prohibited_flags |= IEEE80211_CHAN_NO_IR;
+       if (cfg80211_chandef_dfs_required(wiphy, chandef, iftype) > 0 &&
+@@ -827,8 +822,36 @@ bool cfg80211_reg_can_beacon(struct wiph
+       trace_cfg80211_return_bool(res);
+       return res;
+ }
++
++bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
++                           struct cfg80211_chan_def *chandef,
++                           enum nl80211_iftype iftype)
++{
++      return _cfg80211_reg_can_beacon(wiphy, chandef, iftype, true);
++}
+ EXPORT_SYMBOL(cfg80211_reg_can_beacon);
++bool cfg80211_reg_can_beacon_relax(struct wiphy *wiphy,
++                                 struct cfg80211_chan_def *chandef,
++                                 enum nl80211_iftype iftype)
++{
++      bool check_no_ir;
++
++      ASSERT_RTNL();
++
++      /*
++       * Under certain conditions suggested by some regulatory bodies a
++       * GO/STA can IR on channels marked with IEEE80211_NO_IR. Set this flag
++       * only if such relaxations are not enabled and the conditions are not
++       * met.
++       */
++      check_no_ir = !cfg80211_ir_permissive_chan(wiphy, iftype,
++                                                 chandef->chan);
++
++      return _cfg80211_reg_can_beacon(wiphy, chandef, iftype, check_no_ir);
++}
++EXPORT_SYMBOL(cfg80211_reg_can_beacon_relax);
++
+ int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
+                                struct cfg80211_chan_def *chandef)
+ {
+--- a/net/wireless/nl80211.c
++++ b/net/wireless/nl80211.c
+@@ -2007,7 +2007,8 @@ static int __nl80211_set_channel(struct
+       switch (iftype) {
+       case NL80211_IFTYPE_AP:
+       case NL80211_IFTYPE_P2P_GO:
+-              if (!cfg80211_reg_can_beacon(&rdev->wiphy, &chandef, iftype)) {
++              if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &chandef,
++                                                 iftype)) {
+                       result = -EINVAL;
+                       break;
+               }
+@@ -3408,8 +3409,8 @@ static int nl80211_start_ap(struct sk_bu
+       } else if (!nl80211_get_ap_channel(rdev, &params))
+               return -EINVAL;
+-      if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef,
+-                                   wdev->iftype))
++      if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &params.chandef,
++                                         wdev->iftype))
+               return -EINVAL;
+       if (info->attrs[NL80211_ATTR_ACL_POLICY]) {
+@@ -6500,8 +6501,8 @@ skip_beacons:
+       if (err)
+               return err;
+-      if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef,
+-                                   wdev->iftype))
++      if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &params.chandef,
++                                         wdev->iftype))
+               return -EINVAL;
+       err = cfg80211_chandef_dfs_required(wdev->wiphy,
+@@ -10188,7 +10189,8 @@ static int nl80211_tdls_channel_switch(s
+               return -EINVAL;
+       /* we will be active on the TDLS link */
+-      if (!cfg80211_reg_can_beacon(&rdev->wiphy, &chandef, wdev->iftype))
++      if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &chandef,
++                                         wdev->iftype))
+               return -EINVAL;
+       /* don't allow switching to DFS channels */
+--- a/net/wireless/reg.c
++++ b/net/wireless/reg.c
+@@ -1589,7 +1589,7 @@ static bool reg_wdev_chan_valid(struct w
+       case NL80211_IFTYPE_AP:
+       case NL80211_IFTYPE_P2P_GO:
+       case NL80211_IFTYPE_ADHOC:
+-              return cfg80211_reg_can_beacon(wiphy, &chandef, iftype);
++              return cfg80211_reg_can_beacon_relax(wiphy, &chandef, iftype);
+       case NL80211_IFTYPE_STATION:
+       case NL80211_IFTYPE_P2P_CLIENT:
+               return cfg80211_chandef_usable(wiphy, &chandef,
+--- a/net/wireless/trace.h
++++ b/net/wireless/trace.h
+@@ -2358,20 +2358,23 @@ TRACE_EVENT(cfg80211_cqm_rssi_notify,
+ TRACE_EVENT(cfg80211_reg_can_beacon,
+       TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef,
+-               enum nl80211_iftype iftype),
+-      TP_ARGS(wiphy, chandef, iftype),
++               enum nl80211_iftype iftype, bool check_no_ir),
++      TP_ARGS(wiphy, chandef, iftype, check_no_ir),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               CHAN_DEF_ENTRY
+               __field(enum nl80211_iftype, iftype)
++              __field(bool, check_no_ir)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               CHAN_DEF_ASSIGN(chandef);
+               __entry->iftype = iftype;
++              __entry->check_no_ir = check_no_ir;
+       ),
+-      TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT ", iftype=%d",
+-                WIPHY_PR_ARG, CHAN_DEF_PR_ARG, __entry->iftype)
++      TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT ", iftype=%d check_no_ir=%s",
++                WIPHY_PR_ARG, CHAN_DEF_PR_ARG, __entry->iftype,
++                BOOL_TO_STR(__entry->check_no_ir))
+ );
+ TRACE_EVENT(cfg80211_chandef_dfs_required,
index 309b50a39a8ae40c1b94f9b6fc4cc33ff3aca40c..829c572d274e87436d61f461d263f49c0d0e186f 100644 (file)
  };
  
  /* policy for the key attributes */
-@@ -2206,6 +2207,20 @@ static int nl80211_set_wiphy(struct sk_b
+@@ -2207,6 +2208,20 @@ static int nl80211_set_wiphy(struct sk_b
                if (result)
                        return result;
        }
index 5d806343d98ada35272ec1a53fe5af5cbfa7fbdc..49b223d7242ebd8cc1e5933f9e9ff882b4d1c5ab 100644 (file)
@@ -10,7 +10,7 @@ Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
 
 --- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
 +++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
-@@ -662,8 +662,36 @@ static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
+@@ -662,8 +662,36 @@ static struct wireless_dev *brcmf_cfg802
                                                     u32 *flags,
                                                     struct vif_params *params)
  {
index e8771af68c86f55c4eeecaf8d28bbdc233ad613d..32989eb69d0a68888018c40cf8139e7181e8e37b 100644 (file)
@@ -20,7 +20,7 @@ Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
 
 --- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
 +++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
-@@ -5813,6 +5813,7 @@ static void brcmf_wiphy_wowl_params(struct wiphy *wiphy)
+@@ -5813,6 +5813,7 @@ static void brcmf_wiphy_wowl_params(stru
  
  static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
  {
@@ -28,7 +28,7 @@ Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
        struct ieee80211_supported_band *band;
        __le32 bandlist[3];
        u32 n_bands;
-@@ -5826,6 +5827,19 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
+@@ -5826,6 +5827,19 @@ static int brcmf_setup_wiphy(struct wiph
        if (err)
                return err;
  
index a6586666fc385cb9ecae8f13c8b3e801e1bc27a7..43b2448ff22c470739fd20734323b8ebba2bee8a 100644 (file)
@@ -14,7 +14,7 @@ Signed-off-by: Sven Eckelmann <sven@open-mesh.com>
 
 --- a/drivers/net/wireless/ath/ath10k/core.c
 +++ b/drivers/net/wireless/ath/ath10k/core.c
-@@ -1422,6 +1422,16 @@ int ath10k_core_register(struct ath10k *
+@@ -1417,6 +1417,16 @@ int ath10k_core_register(struct ath10k *
        ar->chip_id = chip_id;
        queue_work(ar->workqueue, &ar->register_work);