Track CRDA request and handle timeout when no answer from CRDA. This could happen when crda is not available yet (not mounted fs), eg. during OS startup and cfg80211 built-in to the kernel or when CRDA is not available at all in user mode. Signed-off-by: Janusz Dziedzic <janusz.dziedzic@xxxxxxxxx> --- V2: added counter of crda calls without an answer. After get maximum tries print warning. include/net/regulatory.h | 2 ++ net/wireless/reg.c | 53 +++++++++++++++++++++++++++++++++++++--------- 2 files changed, 45 insertions(+), 10 deletions(-) diff --git a/include/net/regulatory.h b/include/net/regulatory.h index 75fc1f5..30c34c4 100644 --- a/include/net/regulatory.h +++ b/include/net/regulatory.h @@ -72,6 +72,7 @@ enum environment_cap { * @country_ie_env: lets us know if the AP is telling us we are outdoor, * indoor, or if it doesn't matter * @list: used to insert into the reg_requests_list linked list + * @crda_call_count: count of crda calls without an answer */ struct regulatory_request { struct rcu_head rcu_head; @@ -84,6 +85,7 @@ struct regulatory_request { bool processed; enum environment_cap country_ie_env; struct list_head list; + unsigned char crda_call_count; }; /** diff --git a/net/wireless/reg.c b/net/wireless/reg.c index f59aaac..11804e8 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -479,6 +479,7 @@ static void reg_regdb_size_check(void) WARN_ONCE(!reg_regdb_size, "db.txt is empty, you should update it..."); } #else +#define REG_CRDA_CALL_COUNT_MAX 5 static inline void reg_regdb_size_check(void) {} static inline void reg_regdb_query(const char *alpha2) {} #endif /* CONFIG_CFG80211_INTERNAL_REGDB */ @@ -512,6 +513,10 @@ reg_call_crda(struct regulatory_request *request) { if (call_crda(request->alpha2)) return REG_REQ_IGNORE; + + /* Setup timeout to check regdb configuration */ + queue_delayed_work(system_power_efficient_wq, + ®_timeout, msecs_to_jiffies(3142)); return REG_REQ_OK; } @@ -1535,8 +1540,7 @@ static void reg_set_request_processed(void) need_more_processing = true; spin_unlock(®_requests_lock); - if (lr->initiator == NL80211_REGDOM_SET_BY_USER) - cancel_delayed_work(®_timeout); + cancel_delayed_work(®_timeout); if (need_more_processing) schedule_work(®_work); @@ -1803,6 +1807,9 @@ static void reg_process_hint(struct regulatory_request *reg_request) struct wiphy *wiphy = NULL; enum reg_request_treatment treatment; + REG_DBG_PRINT("Process regulatory hint called by %s\n", + reg_initiator_name(reg_request->initiator)); + if (reg_request->wiphy_idx != WIPHY_IDX_INVALID) wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx); @@ -1811,12 +1818,7 @@ static void reg_process_hint(struct regulatory_request *reg_request) reg_process_hint_core(reg_request); return; case NL80211_REGDOM_SET_BY_USER: - treatment = reg_process_hint_user(reg_request); - if (treatment == REG_REQ_IGNORE || - treatment == REG_REQ_ALREADY_SET) - return; - queue_delayed_work(system_power_efficient_wq, - ®_timeout, msecs_to_jiffies(3142)); + reg_process_hint_user(reg_request); return; case NL80211_REGDOM_SET_BY_DRIVER: if (!wiphy) @@ -2608,9 +2610,40 @@ void wiphy_regulatory_deregister(struct wiphy *wiphy) static void reg_timeout_work(struct work_struct *work) { - REG_DBG_PRINT("Timeout while waiting for CRDA to reply, restoring regulatory settings\n"); + struct regulatory_request *lr; + rtnl_lock(); - restore_regulatory_settings(true); + + lr = get_last_request(); + REG_DBG_PRINT("Timeout while waiting for CRDA to reply %s request\n", + reg_initiator_name(lr->initiator)); + + switch (lr->initiator) { + case NL80211_REGDOM_SET_BY_CORE: + case NL80211_REGDOM_SET_BY_DRIVER: +#ifdef CONFIG_CFG80211_INTERNAL_REGDB + pr_warn("invalid db.txt file, will use limited/restricted regulatory settings\n"); + break; +#else + if (lr->crda_call_count < REG_CRDA_CALL_COUNT_MAX) { + /* Call CRDA again for last request */ + lr->crda_call_count++; + reg_process_hint(lr); + } else + pr_warn("CRDA not available, will use limited/restricted regulatory settings\n"); + + break; +#endif /* CONFIG_CFG80211_INTERNAL_REGDB */ + case NL80211_REGDOM_SET_BY_USER: + restore_regulatory_settings(true); + break; + case NL80211_REGDOM_SET_BY_COUNTRY_IE: + restore_regulatory_settings(false); + break; + default: + WARN_ON(1); + break; + } rtnl_unlock(); } -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html