cfg80211: Stop calling crda if it is not responsive
authorIlan peer <ilan.peer@intel.com>
Mon, 30 Mar 2015 12:15:49 +0000 (15:15 +0300)
committerJohannes Berg <johannes.berg@intel.com>
Wed, 1 Apr 2015 09:22:38 +0000 (11:22 +0200)
Patch eeca9fce1d71a4955855ceb0c3b13c1eb9db27c1 (cfg80211: Schedule
timeout for all CRDA call) introduced a regression, where in case
that crda is not installed (or not configured properly etc.), the
regulatory core will needlessly continue to call it, polluting the
log with the following log:

"cfg80211: Calling CRDA to update world regulatory domain"

Fix this by limiting the number of continuous CRDA request failures.

Signed-off-by: Ilan Peer <ilan.peer@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/wireless/nl80211.c
net/wireless/reg.c
net/wireless/reg.h

index 6dd1ab3b10ea25c76e20a73998bb5f1ebc41b6b8..dd78445c7d50630524b7d33b96b73a2e416c662c 100644 (file)
@@ -5664,7 +5664,7 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
                }
        }
 
-       r = set_regdom(rd);
+       r = set_regdom(rd, REGD_SOURCE_CRDA);
        /* set_regdom took ownership */
        rd = NULL;
 
index be5f81caa488bf24a0bfc79c6ffb9ba534d1e4aa..0e347f888fe910d07e7a094058755f37bee9fcd9 100644 (file)
@@ -135,6 +135,11 @@ static spinlock_t reg_indoor_lock;
 /* Used to track the userspace process controlling the indoor setting */
 static u32 reg_is_indoor_portid;
 
+/* Max number of consecutive attempts to communicate with CRDA  */
+#define REG_MAX_CRDA_TIMEOUTS 10
+
+static u32 reg_crda_timeouts;
+
 static const struct ieee80211_regdomain *get_cfg80211_regdom(void)
 {
        return rtnl_dereference(cfg80211_regdomain);
@@ -485,7 +490,7 @@ static void reg_regdb_search(struct work_struct *work)
        mutex_unlock(&reg_regdb_search_mutex);
 
        if (!IS_ERR_OR_NULL(regdom))
-               set_regdom(regdom);
+               set_regdom(regdom, REGD_SOURCE_INTERNAL_DB);
 
        rtnl_unlock();
 }
@@ -535,15 +540,20 @@ static int call_crda(const char *alpha2)
        snprintf(country, sizeof(country), "COUNTRY=%c%c",
                 alpha2[0], alpha2[1]);
 
+       /* query internal regulatory database (if it exists) */
+       reg_regdb_query(alpha2);
+
+       if (reg_crda_timeouts > REG_MAX_CRDA_TIMEOUTS) {
+               pr_info("Exceeded CRDA call max attempts. Not calling CRDA\n");
+               return -EINVAL;
+       }
+
        if (!is_world_regdom((char *) alpha2))
                pr_info("Calling CRDA for country: %c%c\n",
                        alpha2[0], alpha2[1]);
        else
                pr_info("Calling CRDA to update world regulatory domain\n");
 
-       /* query internal regulatory database (if it exists) */
-       reg_regdb_query(alpha2);
-
        return kobject_uevent_env(&reg_pdev->dev.kobj, KOBJ_CHANGE, env);
 }
 
@@ -2293,6 +2303,9 @@ int regulatory_hint_user(const char *alpha2,
        request->initiator = NL80211_REGDOM_SET_BY_USER;
        request->user_reg_hint_type = user_reg_hint_type;
 
+       /* Allow calling CRDA again */
+       reg_crda_timeouts = 0;
+
        queue_regulatory_request(request);
 
        return 0;
@@ -2362,6 +2375,9 @@ int regulatory_hint(struct wiphy *wiphy, const char *alpha2)
        request->alpha2[1] = alpha2[1];
        request->initiator = NL80211_REGDOM_SET_BY_DRIVER;
 
+       /* Allow calling CRDA again */
+       reg_crda_timeouts = 0;
+
        queue_regulatory_request(request);
 
        return 0;
@@ -2415,6 +2431,9 @@ void regulatory_hint_country_ie(struct wiphy *wiphy, enum ieee80211_band band,
        request->initiator = NL80211_REGDOM_SET_BY_COUNTRY_IE;
        request->country_ie_env = env;
 
+       /* Allow calling CRDA again */
+       reg_crda_timeouts = 0;
+
        queue_regulatory_request(request);
        request = NULL;
 out:
@@ -2893,7 +2912,8 @@ static int reg_set_rd_country_ie(const struct ieee80211_regdomain *rd,
  * multiple drivers can be ironed out later. Caller must've already
  * kmalloc'd the rd structure.
  */
-int set_regdom(const struct ieee80211_regdomain *rd)
+int set_regdom(const struct ieee80211_regdomain *rd,
+              enum ieee80211_regd_source regd_src)
 {
        struct regulatory_request *lr;
        bool user_reset = false;
@@ -2904,6 +2924,9 @@ int set_regdom(const struct ieee80211_regdomain *rd)
                return -EINVAL;
        }
 
+       if (regd_src == REGD_SOURCE_CRDA)
+               reg_crda_timeouts = 0;
+
        lr = get_last_request();
 
        /* Note that this doesn't update the wiphys, this is done below */
@@ -3063,6 +3086,7 @@ static void reg_timeout_work(struct work_struct *work)
 {
        REG_DBG_PRINT("Timeout while waiting for CRDA to reply, restoring regulatory settings\n");
        rtnl_lock();
+       reg_crda_timeouts++;
        restore_regulatory_settings(true);
        rtnl_unlock();
 }
index a2c4e16459da06a3b6ebad974aaab665eda717f0..9f495d76eca075d6f779078196f9adddd98a34aa 100644 (file)
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+enum ieee80211_regd_source {
+       REGD_SOURCE_INTERNAL_DB,
+       REGD_SOURCE_CRDA,
+};
+
 extern const struct ieee80211_regdomain __rcu *cfg80211_regdomain;
 
 bool reg_is_valid_request(const char *alpha2);
@@ -46,7 +51,9 @@ void wiphy_regulatory_deregister(struct wiphy *wiphy);
 int __init regulatory_init(void);
 void regulatory_exit(void);
 
-int set_regdom(const struct ieee80211_regdomain *rd);
+int set_regdom(const struct ieee80211_regdomain *rd,
+              enum ieee80211_regd_source regd_src);
+
 unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd,
                                   const struct ieee80211_reg_rule *rule);