summary refs log tree commit diff
path: root/net/wireless
diff options
context:
space:
mode:
authorJanusz Dziedzic <janusz.dziedzic@tieto.com>2014-02-14 08:54:00 +0100
committerJohannes Berg <johannes.berg@intel.com>2014-02-25 16:27:04 +0100
commit092008abeed1e4168c08826262695ea67657e1aa (patch)
tree68705af45715df5cbc38b77bba2f6a23f9eeb874 /net/wireless
parent963a1852fbac4f75a2d938fa2e734ef1e6d4c044 (diff)
downloadlinux-092008abeed1e4168c08826262695ea67657e1aa.tar.gz
cfg80211: regulatory: reset regdomain in case of error
Reset regdomain to world regdomain in case
of errors in set_regdom() function.

This will fix a problem with such scenario:
- iw reg set US
- iw reg set 00
- iw reg set US
The last step always fail and we get deadlock
in kernel regulatory code. Next setting new
regulatory wasn't possible due to:

Pending regulatory request, waiting for it to be processed...

Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
Acked-by: Luis R. Rodriguez <mcgrof@do-not-panic.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/wireless')
-rw-r--r--net/wireless/reg.c10
1 files changed, 9 insertions, 1 deletions
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 4c50c21d6f52..f0541370e68e 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -2373,6 +2373,7 @@ static int reg_set_rd_country_ie(const struct ieee80211_regdomain *rd,
 int set_regdom(const struct ieee80211_regdomain *rd)
 {
 	struct regulatory_request *lr;
+	bool user_reset = false;
 	int r;
 
 	if (!reg_is_valid_request(rd->alpha2)) {
@@ -2389,6 +2390,7 @@ int set_regdom(const struct ieee80211_regdomain *rd)
 		break;
 	case NL80211_REGDOM_SET_BY_USER:
 		r = reg_set_rd_user(rd, lr);
+		user_reset = true;
 		break;
 	case NL80211_REGDOM_SET_BY_DRIVER:
 		r = reg_set_rd_driver(rd, lr);
@@ -2402,8 +2404,14 @@ int set_regdom(const struct ieee80211_regdomain *rd)
 	}
 
 	if (r) {
-		if (r == -EALREADY)
+		switch (r) {
+		case -EALREADY:
 			reg_set_request_processed();
+			break;
+		default:
+			/* Back to world regulatory in case of errors */
+			restore_regulatory_settings(user_reset);
+		}
 
 		kfree(rd);
 		return r;