2010-05-21 10:42:27

by Juuso Oikarinen

[permalink] [raw]
Subject: [RFC PATCH 0/1] cfg80211: Fix user-space crda query stall

When the user-space crda daemon fails to respond to kernel queries, the kernel
crda subsystem will stall, refusing any further regulatory hints. Details are
in the description of the patch itself.

The patch proposes a fix to the problem by adding a timeout to the user-space
crda accesses, reverting to the 00 domain if user space fails to respond. This
seems safe assuming we don't know what the rules of the requested domain and
allows further regulatory hints to be processed again.

In my testing, this patch appears to function in the various scenarios I can
produce (user hints and 11d hints.) My understanding of the crda subsystem is
still relatively shallow, so I'm asking for your thoughts on this approach.

Comments will be appreaciated!


Juuso Oikarinen (1):
cfg80211: Fix user-space crda query stall

net/wireless/reg.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 45 insertions(+), 0 deletions(-)



2010-05-21 10:42:45

by Juuso Oikarinen

[permalink] [raw]
Subject: [RFC PATCH 1/1] cfg80211: Fix user-space crda query stall

The userspace crda utility can fail to respond to kernel requests in (at least)
two scenarios: it is not runnable for any reason, or it is invoked with a
country code not in its database.

When the userspace crda utility fails to respond to kernel requests (i.e. it
does not use NL80211_CMD_SET_REG to provide the kernel regulatory information
for the requested country) the kernel crda subsystem will stall. It will
refuse to process any further regulatory hints. This is easiest demonstrated
by using for instance the "iw" tool:

iw reg set EU
iw reg set US

"EU" is not a country code present in the database, so user space crda will
not respond. Attempting to define US after that will be silently ignored
(internally, an -EAGAIN is the result, as the "EU" request is still
"being processed".)

To fix this issue, this patch implements timeout protection for the userspace
crda invocation. If there is no response for five seconds, the crda code will
force itself to the world regulatory domain for maximum safety.

Signed-off-by: Juuso Oikarinen <[email protected]>
---
net/wireless/reg.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 45 insertions(+), 0 deletions(-)

diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 8f0d97d..6e72f90 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -385,6 +385,41 @@ static inline void reg_regdb_query(const char *alpha2) {}
#endif /* CONFIG_CFG80211_INTERNAL_REGDB */

/*
+ * This gets invoked if crda in userspace is not responding (it's not getting
+ * executed or the country code in the hint is not in the database.
+ */
+
+static void call_crda_timeout_work(struct work_struct *work)
+{
+ if (!last_request)
+ return;
+
+ printk(KERN_INFO "cfg80211: Call crda daemon timed out for country: "
+ "%c%c\n", last_request->alpha2[0], last_request->alpha2[1]);
+
+ mutex_lock(&cfg80211_mutex);
+
+ /*
+ * As we are not getting data for the current country, force us back
+ * to the world regdomain.
+ */
+ last_request->alpha2[0] = '0';
+ last_request->alpha2[1] = '0';
+ set_regdom(cfg80211_world_regdom);
+ mutex_unlock(&cfg80211_mutex);
+}
+
+static DECLARE_WORK(crda_uevent_timeout_work, call_crda_timeout_work);
+
+#define CRDA_UEVENT_TIMEOUT 5000
+static void crda_uevent_timeout(unsigned long data)
+{
+ schedule_work(&crda_uevent_timeout_work);
+}
+
+static DEFINE_TIMER(crda_uevent_timer, crda_uevent_timeout, 0, 0);
+
+/*
* This lets us keep regulatory code which is updated on a regulatory
* basis in userspace.
*/
@@ -409,6 +444,10 @@ static int call_crda(const char *alpha2)
country_env[8] = alpha2[0];
country_env[9] = alpha2[1];

+ /* start timeout timer */
+ mod_timer(&crda_uevent_timer,
+ jiffies + msecs_to_jiffies(CRDA_UEVENT_TIMEOUT));
+
return kobject_uevent_env(&reg_pdev->dev.kobj, KOBJ_CHANGE, envp);
}

@@ -2581,6 +2620,9 @@ int set_regdom(const struct ieee80211_regdomain *rd)

assert_cfg80211_lock();

+ /* cancel timeout */
+ del_timer(&crda_uevent_timer);
+
mutex_lock(&reg_mutex);

/* Note that this doesn't update the wiphys, this is done below */
@@ -2683,6 +2725,9 @@ void regulatory_exit(void)

cancel_work_sync(&reg_work);

+ del_timer_sync(&crda_uevent_timer);
+ cancel_work_sync(&crda_uevent_timeout_work);
+
mutex_lock(&cfg80211_mutex);
mutex_lock(&reg_mutex);

--
1.6.3.3


2010-05-22 14:06:16

by Kalle Valo

[permalink] [raw]
Subject: Re: [RFC PATCH 1/1] cfg80211: Fix user-space crda query stall

Moi Juuso,

Juuso Oikarinen <[email protected]> writes:

> The userspace crda utility can fail to respond to kernel requests in (at least)
> two scenarios: it is not runnable for any reason, or it is invoked with a
> country code not in its database.
>

[...]

> + printk(KERN_INFO "cfg80211: Call crda daemon timed out for country: "
> + "%c%c\n", last_request->alpha2[0], last_request->alpha2[1]);

I would prefer to mention in the print that kernel will revert back to
world domain. Nicer for the users.

--
Kalle Valo

2010-05-24 05:22:35

by Juuso Oikarinen

[permalink] [raw]
Subject: Re: [RFC PATCH 1/1] cfg80211: Fix user-space crda query stall

On Sat, 2010-05-22 at 16:06 +0200, ext Kalle Valo wrote:
> Moi Juuso,
>
> Juuso Oikarinen <[email protected]> writes:
>
> > The userspace crda utility can fail to respond to kernel requests in (at least)
> > two scenarios: it is not runnable for any reason, or it is invoked with a
> > country code not in its database.
> >
>
> [...]
>
> > + printk(KERN_INFO "cfg80211: Call crda daemon timed out for country: "
> > + "%c%c\n", last_request->alpha2[0], last_request->alpha2[1]);
>
> I would prefer to mention in the print that kernel will revert back to
> world domain. Nicer for the users.
>

That actually happens, because as the code forces the change to the
world domain, there will that "world reg domain updated" trace.

I could also adjust this trace to indicate, what is going to happen.

-Juuso