Hi,
Based on the IRC discussions I started implementing the required bits
for handling DFS states and channel flags in cfg/mac80211 and userspace.
This is WIP, so not really complete, just wanted to get that out so we
have something to discuss about on tomorrows meeting.
Implemented so far is the complete state machine, handling CAC and NOL
as well as starting appropriate action in hostapd. Note, this is based
on top of the 'dfs region support' work posted by Luis.
TODO:
- Documentation
- CSA
- unset beacon on CAC
- unset beacon if interference is detected
- prevent beacon from being set if channel is !CLEAR
- prevent frames from being sent if channel is !CLEAR
A few bits are already there, but by far not complete, e.g. we
discard auth responses but allow probe responses and deauth frames.
--
Best regards,
Dipl.-Inf. (FH) Bernhard Schmidt (software development)
saxnet GmbH, Willy-Brandt-Ring 1, 08606 Oelsnitz
Tel. +49 (0) 3741 300 6. 100 - Fax +49 (0) 3741 300 6. 101
managing director: Steffen Dreise - county court Chemnitz - HRB 23017
http://www.saxnet.de
On Mon, 2011-01-17 at 11:24 +0100, Bernhard Schmidt wrote:
> ---
> net/mac80211/radar.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++
> net/mac80211/radar.h | 4 +++
> 2 files changed, 69 insertions(+), 0 deletions(-)
>
> diff --git a/net/mac80211/radar.c b/net/mac80211/radar.c
> index e90b8bf..afb2ae1 100644
> --- a/net/mac80211/radar.c
> +++ b/net/mac80211/radar.c
> @@ -15,6 +15,66 @@
> #include "driver-ops.h"
> #include "radar.h"
>
> +static void cac_timer(unsigned long data)
> +{
> + struct ieee80211_local *local = (void *) data;
> + struct ieee80211_radar *radar = &local->radar;
> + struct ieee80211_channel *chan;
> +
> + printk(KERN_INFO "CAC done\n");
> +
> + chan = local->oper_channel;
> + mutex_lock(&radar->mtx);
Clearly, you haven't even tested this code. I'm not sure why I'm even
reviewing it.
johannes
---
net/mac80211/radar.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++
net/mac80211/radar.h | 4 +++
2 files changed, 69 insertions(+), 0 deletions(-)
diff --git a/net/mac80211/radar.c b/net/mac80211/radar.c
index e90b8bf..afb2ae1 100644
--- a/net/mac80211/radar.c
+++ b/net/mac80211/radar.c
@@ -15,6 +15,66 @@
#include "driver-ops.h"
#include "radar.h"
+static void cac_timer(unsigned long data)
+{
+ struct ieee80211_local *local = (void *) data;
+ struct ieee80211_radar *radar = &local->radar;
+ struct ieee80211_channel *chan;
+
+ printk(KERN_INFO "CAC done\n");
+
+ chan = local->oper_channel;
+ mutex_lock(&radar->mtx);
+ if ((chan->flags & IEEE80211_CHAN_RADAR_INTERFERENCE) == 0) {
+ chan->flags |= IEEE80211_CHAN_RADAR_CLEAR;
+ }
+ radar->cac = 0;
+ mutex_unlock(&radar->mtx);
+}
+
+int ieee80211_radar_cac(struct wiphy *wiphy, int enable)
+{
+ struct ieee80211_local *local = wiphy_priv(wiphy);
+ struct ieee80211_radar *radar = &local->radar;
+ struct ieee80211_channel *chan = local->oper_channel;
+ int ret;
+
+ ret = ieee80211_radar_detection_enable(local, chan);
+ if (ret != 0)
+ return ret;
+
+ if (!enable && !radar->cac)
+ return -EINVAL;
+ if (!enable && radar->cac) {
+ printk(KERN_INFO "stopping CAC\n");
+
+ del_timer_sync(&radar->cac_timer);
+ mutex_lock(&radar->mtx);
+ radar->cac = 0;
+ mutex_unlock(&radar->mtx);
+ return 0;
+ }
+ if (enable) {
+ if ((chan->flags & IEEE80211_CHAN_RADAR_INTERFERENCE))
+ return -EINVAL;
+
+ printk(KERN_INFO "starting CAC\n");
+
+ del_timer_sync(&radar->cac_timer);
+ mutex_lock(&radar->mtx);
+ if ((chan->flags & IEEE80211_CHAN_RADAR) &&
+ (chan->flags & IEEE80211_CHAN_RADAR_CLEAR)) {
+ chan->flags &= ~IEEE80211_CHAN_RADAR_CLEAR;
+ }
+ radar->cac = 1;
+ mutex_unlock(&radar->mtx);
+ mod_timer(&radar->cac_timer, jiffies +
+ msecs_to_jiffies(radar->params->cac_period * 1000));
+ }
+
+ return 0;
+}
+
static void nol_timer(unsigned long data)
{
struct ieee80211_local *local = (void *) data;
@@ -136,6 +196,9 @@ void ieee80211_radar_init(struct ieee80211_local *local)
mutex_init(&radar->mtx);
+ radar->cac = 0;
+ setup_timer(&radar->cac_timer, cac_timer, (unsigned long)local);
+
INIT_LIST_HEAD(&radar->nol_list);
setup_timer(&radar->nol_timer, nol_timer, (unsigned long)local);
mod_timer(&radar->nol_timer, jiffies + msecs_to_jiffies(1000));
@@ -146,6 +209,8 @@ void ieee80211_radar_deinit(struct ieee80211_local *local)
struct ieee80211_radar *radar = &local->radar;
struct ieee80211_radar_nol_list *nol, *tmp;
+ del_timer_sync(&radar->cac_timer);
+
del_timer_sync(&radar->nol_timer);
mutex_lock(&radar->mtx);
list_for_each_entry_safe(nol, tmp, &radar->nol_list, list) {
diff --git a/net/mac80211/radar.h b/net/mac80211/radar.h
index 79684b5..6e8bc36 100644
--- a/net/mac80211/radar.h
+++ b/net/mac80211/radar.h
@@ -31,10 +31,14 @@ struct ieee80211_radar {
struct mutex mtx;
struct ieee80211_radar_parameters *params;
+ int cac;
+ struct timer_list cac_timer;
+
struct timer_list nol_timer;
struct list_head nol_list;
};
+int ieee80211_radar_cac(struct wiphy *wiphy, int enable);
int ieee80211_radar_detection_enable(struct ieee80211_local *local,
struct ieee80211_channel *chan);
int ieee80211_radar_detection_disable(struct ieee80211_local *local,
--
1.5.6.5
Before a radar channel can be used, a full CAC has be done, the
IEEE80211_CHAN_RADAR_CLEAR flags indicates that this has been done. If either
during CAC or in-service monitoring interference is detected, the channel is
added to NOL and marked with IEEE80211_CHAN_RADAR_INTERFERENCE.
---
include/linux/nl80211.h | 6 ++++++
include/net/cfg80211.h | 18 ++++++++++++------
net/wireless/nl80211.c | 4 ++++
3 files changed, 22 insertions(+), 6 deletions(-)
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index e3c9ec7..acb3c33 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -1371,6 +1371,10 @@ enum nl80211_band_attr {
* (100 * dBm).
* @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
* currently defined
+ * @NL80211_FREQUENCY_ATTR_RADAR_CLEAR: during a full CAC no interference has
+ * been detected
+ * @NL80211_FREQUENCY_ATTR_RADAR_INTERFERENCE: either during a CAC or
+ * in-service monitoring radar interference was detected
* @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
*/
enum nl80211_frequency_attr {
@@ -1381,6 +1385,8 @@ enum nl80211_frequency_attr {
NL80211_FREQUENCY_ATTR_NO_IBSS,
NL80211_FREQUENCY_ATTR_RADAR,
NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
+ NL80211_FREQUENCY_ATTR_RADAR_CLEAR,
+ NL80211_FREQUENCY_ATTR_RADAR_INTERFERENCE,
/* keep last */
__NL80211_FREQUENCY_ATTR_AFTER_LAST,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 1322695..1e9a052 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -98,14 +98,20 @@ enum ieee80211_band {
* is not permitted.
* @IEEE80211_CHAN_NO_HT40MINUS: extension channel below this channel
* is not permitted.
+ * @IEEE80211_CHAN_RADAR_CLEAR: during a full CAC no interference has
+ * been detected
+ * @IEEE80211_CHAN_RADAR_INTERFERENCE: either during a CAC or
+ * in-service monitoring radar interference was detected
*/
enum ieee80211_channel_flags {
- IEEE80211_CHAN_DISABLED = 1<<0,
- IEEE80211_CHAN_PASSIVE_SCAN = 1<<1,
- IEEE80211_CHAN_NO_IBSS = 1<<2,
- IEEE80211_CHAN_RADAR = 1<<3,
- IEEE80211_CHAN_NO_HT40PLUS = 1<<4,
- IEEE80211_CHAN_NO_HT40MINUS = 1<<5,
+ IEEE80211_CHAN_DISABLED = 1<<0,
+ IEEE80211_CHAN_PASSIVE_SCAN = 1<<1,
+ IEEE80211_CHAN_NO_IBSS = 1<<2,
+ IEEE80211_CHAN_RADAR = 1<<3,
+ IEEE80211_CHAN_NO_HT40PLUS = 1<<4,
+ IEEE80211_CHAN_NO_HT40MINUS = 1<<5,
+ IEEE80211_CHAN_RADAR_CLEAR = 1<<6,
+ IEEE80211_CHAN_RADAR_INTERFERENCE = 1<<7,
};
#define IEEE80211_CHAN_NO_HT40 \
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index f4eb3ea..0524423 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -307,6 +307,10 @@ static int nl80211_msg_put_channel(struct sk_buff *msg,
NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_NO_IBSS);
if (chan->flags & IEEE80211_CHAN_RADAR)
NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_RADAR);
+ if (chan->flags & IEEE80211_CHAN_RADAR_CLEAR)
+ NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_RADAR_CLEAR);
+ if (chan->flags & IEEE80211_CHAN_RADAR_INTERFERENCE)
+ NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_RADAR_INTERFERENCE);
NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
DBM_TO_MBM(chan->max_power));
--
1.5.6.5
On Mon, 2011-01-17 at 09:31 +0100, Bernhard Schmidt wrote:
> Before a radar channel can be used, a full CAC has be done, the
> IEEE80211_CHAN_RADAR_CLEAR flags indicates that this has been done. If either
> during CAC or in-service monitoring interference is detected, the channel is
> added to NOL and marked with IEEE80211_CHAN_RADAR_INTERFERENCE.
Also, this is not mac80211, it's cfg80211.
johannes
On Tuesday, January 18, 2011 11:48:12 Johannes Berg wrote:
> I don't get this at all. How's the driver supported to report
> anything?!
ieee80211_radar_interference()
--
Best regards,
Dipl.-Inf. (FH) Bernhard Schmidt (software development)
saxnet GmbH, Willy-Brandt-Ring 1, 08606 Oelsnitz
Tel. +49 (0) 3741 300 6. 100 - Fax +49 (0) 3741 300 6. 101
managing director: Steffen Dreise - county court Chemnitz - HRB 23017
http://www.saxnet.de
On Mon, 2011-01-17 at 10:16 +0100, Bernhard Schmidt wrote:
> @@ -1241,6 +1244,8 @@ static int ieee80211_set_channel(struct wiphy *wiphy,
> if (sdata && sdata->vif.type != NL80211_IFTYPE_MONITOR)
> ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT);
>
> + ieee80211_radar_detection_enable(local, chan);
> +
So you're ignoring the return value -- that doesn't seem right at all.
Also, if the driver doesn't implement detection, you should probably
reject using the channel.
johannes
On Tuesday, January 18, 2011 11:45:15 Johannes Berg wrote:
> On Mon, 2011-01-17 at 11:24 +0100, Bernhard Schmidt wrote:
> > ---
> >
> > net/mac80211/radar.c | 65
> > ++++++++++++++++++++++++++++++++++++++++++++++++++
> > net/mac80211/radar.h | 4 +++
> > 2 files changed, 69 insertions(+), 0 deletions(-)
> >
> > diff --git a/net/mac80211/radar.c b/net/mac80211/radar.c
> > index e90b8bf..afb2ae1 100644
> > --- a/net/mac80211/radar.c
> > +++ b/net/mac80211/radar.c
> > @@ -15,6 +15,66 @@
> >
> > #include "driver-ops.h"
> > #include "radar.h"
> >
> > +static void cac_timer(unsigned long data)
> > +{
> > + struct ieee80211_local *local = (void *) data;
> > + struct ieee80211_radar *radar = &local->radar;
> > + struct ieee80211_channel *chan;
> > +
> > + printk(KERN_INFO "CAC done\n");
> > +
> > + chan = local->oper_channel;
> > + mutex_lock(&radar->mtx);
>
> Clearly, you haven't even tested this code. I'm not sure why I'm even
> reviewing it.
Granted, I did only some basic tests with only a few predefined
scenarios, not at all is just wrong. Anyways, I should have mentioned in
0/13 that preventing channel changes while in CAC should be considered
and chan should be assigned to local variable then.
--
Best regards,
Dipl.-Inf. (FH) Bernhard Schmidt (software development)
saxnet GmbH, Willy-Brandt-Ring 1, 08606 Oelsnitz
Tel. +49 (0) 3741 300 6. 100 - Fax +49 (0) 3741 300 6. 101
managing director: Steffen Dreise - county court Chemnitz - HRB 23017
http://www.saxnet.de
---
src/ap/hw_features.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++
src/ap/hw_features.h | 1 +
2 files changed, 55 insertions(+), 0 deletions(-)
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 133ed74..743d567 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -27,6 +27,58 @@
#include "hw_features.h"
+int hostapd_select_random_channel(struct hostapd_iface *iface)
+{
+ int i, j, ret;
+
+ if (iface->conf->channel_list == NULL ||
+ iface->conf->channel_list[0] == -1)
+ return -1;
+
+ ret = -1;
+ if (iface->conf->channel == 0 && iface->conf->channel_list != NULL) {
+ int *chans, chans_num = 1, hw_chans_num;
+ u8 buf;
+
+ for (i = 0; iface->conf->channel_list[i] > 0; i++)
+ chans_num++;
+
+ chans = os_malloc(sizeof(int) * chans_num);
+ if (chans == NULL)
+ return -1;
+ os_memcpy(chans, iface->conf->channel_list,
+ sizeof(int) * chans_num);
+
+ hw_chans_num = iface->current_mode->num_channels;
+ buf = chans_num;
+ do {
+ struct hostapd_channel_data *hchan = NULL;
+
+ for (i = j = 0; i < chans_num; i++, j++) {
+ if (i == buf)
+ j++;
+ chans[i] = chans[j];
+ }
+
+ os_get_random(&buf, 1);
+ buf %= chans_num;
+
+ for (i = 0; i < hw_chans_num; i++) {
+ hchan = &iface->current_mode->channels[i];
+ if (hchan->chan == chans[buf] &&
+ !(hchan->flag & HOSTAPD_CHAN_DISABLED)) {
+ iface->conf->channel = hchan->chan;
+ ret = 0;
+ break;
+ }
+ }
+ chans_num--;
+ } while (iface->conf->channel == 0 && chans_num > 0);
+ os_free(chans);
+ }
+ return ret;
+}
+
void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
size_t num_hw_features)
{
@@ -642,6 +694,8 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface)
break;
}
}
+ if (iface->conf->channel == 0 && !hostapd_select_random_channel(iface))
+ ok = 1;
if (ok && iface->conf->secondary_channel) {
int sec_ok = 0;
int sec_chan = iface->conf->channel +
diff --git a/src/ap/hw_features.h b/src/ap/hw_features.h
index 88c2322..f800562 100644
--- a/src/ap/hw_features.h
+++ b/src/ap/hw_features.h
@@ -17,6 +17,7 @@
#define HW_FEATURES_H
#ifdef NEED_AP_MLME
+int hostapd_select_random_channel(struct hostapd_iface *iface);
void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
size_t num_hw_features);
int hostapd_get_hw_features(struct hostapd_iface *iface);
--
1.5.6.5
---
src/ap/hostapd.c | 32 ++++++++++++++++++++++++++++++++
1 files changed, 32 insertions(+), 0 deletions(-)
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index a065fc9..1024d73 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -993,6 +993,34 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm);
}
+static void hostapd_radar_flags_cb(struct hostapd_data *hapd)
+{
+ struct hostapd_iface *iface = hapd->iface;
+ u32 flags;
+
+ iface->radar_cac_cb = NULL;
+ iface->radar_flags_cb = NULL;
+ flags = hostapd_hw_get_radar_flags(hapd, iface->conf->channel);
+ if ((flags & HOSTAPD_CHAN_RADAR_CLEAR)) {
+ hostapd_reload_bss(hapd);
+ } else if ((flags & HOSTAPD_CHAN_RADAR_INTERFERENCE)) {
+ int chan = iface->conf->channel;
+ u32 newflags;
+ iface->conf->channel = 0;
+ if (hostapd_select_random_channel(iface))
+ iface->conf->channel = chan;
+ newflags = hostapd_hw_get_radar_flags(hapd,
+ iface->conf->channel);
+ if ((newflags & HOSTAPD_CHAN_RADAR_INTERFERENCE))
+ iface->radar_flags_cb = hostapd_radar_flags_cb;
+ else
+ hostapd_radar_flags_cb(hapd);
+ } else {
+ hostapd_channel_availability_check(hapd);
+ iface->radar_cac_cb = hostapd_radar_flags_cb;
+ }
+}
+
void hostapd_radar_flags_changed(struct hostapd_data *hapd, int freq, u32 flags)
{
struct hostapd_iface *iface = hapd->iface;
@@ -1003,4 +1031,8 @@ void hostapd_radar_flags_changed(struct hostapd_data *hapd, int freq, u32 flags)
iface->radar_flags_cb(hapd);
return;
}
+ if (iface->radar_cac_cb || iface->freq != freq)
+ return;
+ else if ((flags & HOSTAPD_CHAN_RADAR_INTERFERENCE))
+ hostapd_radar_flags_cb(hapd);
}
--
1.5.6.5
On Tuesday, January 18, 2011 13:12:20 Johannes Berg wrote:
> On Tue, 2011-01-18 at 13:01 +0100, Bernhard Schmidt wrote:
> > > > + mutex_lock(&radar->mtx);
> > >
> > > Clearly, you haven't even tested this code. I'm not sure why I'm
> > > even reviewing it.
> >
> > Granted, I did only some basic tests with only a few predefined
> > scenarios, not at all is just wrong. Anyways, I should have
> > mentioned in 0/13 that preventing channel changes while in CAC
> > should be considered and chan should be assigned to local variable
> > then.
>
> I was more referring to the fact that you're trying to lock a mutex
> in a timer -- so you can't have executed this code path ever?!
I'm running it right now, the code path *is* executed, what am I missing
here?
--
Best regards,
Dipl.-Inf. (FH) Bernhard Schmidt (software development)
saxnet GmbH, Willy-Brandt-Ring 1, 08606 Oelsnitz
Tel. +49 (0) 3741 300 6. 100 - Fax +49 (0) 3741 300 6. 101
managing director: Steffen Dreise - county court Chemnitz - HRB 23017
http://www.saxnet.de
---
src/ap/drv_callbacks.c | 4 +++
src/ap/hostapd.c | 5 ++++
src/ap/hostapd.h | 2 +
src/ap/hw_features.c | 44 +++++++++++++++++++++++++++++++++++++++++-
src/ap/hw_features.h | 14 +++++++++++++
src/drivers/driver.h | 22 ++++++++++++++++++++-
src/drivers/driver_nl80211.c | 31 +++++++++++++++++++++++++++++
7 files changed, 120 insertions(+), 2 deletions(-)
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index a49248f..c55c42a 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -521,6 +521,10 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
break;
hostapd_event_sta_low_ack(hapd, data->low_ack.addr);
break;
+ case EVENT_RADAR_FLAGS_CHANGED:
+ hostapd_radar_flags_changed(hapd, data->radar.freq,
+ data->radar.flags);
+ break;
default:
wpa_printf(MSG_DEBUG, "Unknown event %d", event);
break;
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 16d7c45..592a01f 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -916,3 +916,8 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
} else
wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm);
}
+
+void hostapd_radar_flags_changed(struct hostapd_data *hapd, int freq, u32 flags)
+{
+ hostapd_hw_set_radar_flags(hapd, freq, flags);
+}
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 0346408..e2e4234 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -235,6 +235,8 @@ void hostapd_interface_deinit(struct hostapd_iface *iface);
void hostapd_interface_free(struct hostapd_iface *iface);
void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
int reassoc);
+void hostapd_radar_flags_changed(struct hostapd_data *hapd, int freq,
+ u32 flags);
/* utils.c */
int hostapd_register_probereq_cb(struct hostapd_data *hapd,
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 743d567..04bf210 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -66,7 +66,8 @@ int hostapd_select_random_channel(struct hostapd_iface *iface)
for (i = 0; i < hw_chans_num; i++) {
hchan = &iface->current_mode->channels[i];
if (hchan->chan == chans[buf] &&
- !(hchan->flag & HOSTAPD_CHAN_DISABLED)) {
+ !(hchan->flag & HOSTAPD_CHAN_DISABLED) &&
+ !(hchan->flag & HOSTAPD_CHAN_RADAR_INTERFERENCE)) {
iface->conf->channel = hchan->chan;
ret = 0;
break;
@@ -801,3 +802,44 @@ int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)
return 0;
}
+
+u32 hostapd_hw_get_radar_flags(struct hostapd_data *hapd, int chan)
+{
+ int i;
+
+ if (!hapd->iface->current_mode)
+ return 0;
+
+ for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
+ struct hostapd_channel_data *ch =
+ &hapd->iface->current_mode->channels[i];
+ if (ch->chan == chan) {
+ return (ch->flag & (HOSTAPD_CHAN_RADAR |
+ HOSTAPD_CHAN_RADAR_CLEAR |
+ HOSTAPD_CHAN_RADAR_INTERFERENCE));
+ }
+ }
+
+ return 0;
+}
+
+int hostapd_hw_set_radar_flags(struct hostapd_data *hapd, int freq, u32 flags)
+{
+ int i;
+
+ if (!hapd->iface->current_mode)
+ return 0;
+
+ for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
+ struct hostapd_channel_data *ch =
+ &hapd->iface->current_mode->channels[i];
+ if (ch->freq == freq) {
+ ch->flag &= ~(HOSTAPD_CHAN_RADAR_CLEAR |
+ HOSTAPD_CHAN_RADAR_INTERFERENCE);
+ ch->flag |= flags;
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/src/ap/hw_features.h b/src/ap/hw_features.h
index f800562..466b16b 100644
--- a/src/ap/hw_features.h
+++ b/src/ap/hw_features.h
@@ -25,6 +25,8 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface);
const char * hostapd_hw_mode_txt(int mode);
int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan);
int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq);
+u32 hostapd_hw_get_radar_flags(struct hostapd_data *hapd, int chan);
+int hostapd_hw_set_radar_flags(struct hostapd_data *hapd, int freq, u32 flags);
int hostapd_check_ht_capab(struct hostapd_iface *iface);
int hostapd_prepare_rates(struct hostapd_data *hapd,
struct hostapd_hw_modes *mode);
@@ -55,6 +57,18 @@ static inline int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan)
return -1;
}
+static inline u32 hostapd_hw_get_radar_flags(struct hostapd_data *hapd,
+ int chan)
+{
+ return 0;
+}
+
+static inline int hostapd_hw_set_radar_flags(struct hostapd_data *hapd,
+ int freq, u32 flags)
+{
+ return 0;
+}
+
static inline int hostapd_check_ht_capab(struct hostapd_iface *iface)
{
return 0;
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index b8684fa..777f854 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -34,6 +34,8 @@
#define HOSTAPD_CHAN_HT40PLUS 0x00000010
#define HOSTAPD_CHAN_HT40MINUS 0x00000020
#define HOSTAPD_CHAN_HT40 0x00000040
+#define HOSTAPD_CHAN_RADAR_CLEAR 0x00000080
+#define HOSTAPD_CHAN_RADAR_INTERFERENCE 0x00000100
/**
* struct hostapd_channel_data - Channel information
@@ -2577,7 +2579,9 @@ enum wpa_event_type {
EVENT_P2P_PROV_DISC_REQUEST,
EVENT_P2P_PROV_DISC_RESPONSE,
EVENT_P2P_SD_REQUEST,
- EVENT_P2P_SD_RESPONSE
+ EVENT_P2P_SD_RESPONSE,
+
+ EVENT_RADAR_FLAGS_CHANGED,
};
@@ -3091,6 +3095,22 @@ union wpa_event_data {
const u8 *tlvs;
size_t tlvs_len;
} p2p_sd_resp;
+
+ /**
+ * struct radar_flags - Data for radar related flag changes
+ */
+ struct radar_flags {
+ /**
+ * freq - Frequency (in MHz) of the channel which needs a
+ * flag update.
+ */
+ int freq;
+
+ /**
+ * flags - New HOSTAPD_CHAN_RADAR_* flags
+ */
+ u32 flags;
+ } radar;
};
/**
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index acb8f33..d919a73 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -1288,6 +1288,26 @@ static void nl80211_new_station_event(struct wpa_driver_nl80211_data *drv,
wpa_supplicant_event(drv->ctx, EVENT_IBSS_RSN_START, &data);
}
+static void nl80211_radar_event(struct wpa_driver_nl80211_data *drv, u32 cmd,
+ struct nlattr **tb)
+{
+ union wpa_event_data data;
+
+ switch (cmd) {
+ case NL80211_CMD_RADAR_FLAGS_CHANGED:
+ if (!tb[NL80211_FREQUENCY_ATTR_FREQ])
+ return;
+ data.radar.flags = 0;
+ data.radar.freq = nla_get_u32(tb[NL80211_FREQUENCY_ATTR_FREQ]);
+ if (tb[NL80211_FREQUENCY_ATTR_RADAR_CLEAR])
+ data.radar.flags |= HOSTAPD_CHAN_RADAR_CLEAR;
+ if (tb[NL80211_FREQUENCY_ATTR_RADAR_INTEFERENCE])
+ data.radar.flags |= HOSTAPD_CHAN_RADAR_INTERFERENCE;
+ wpa_supplicant_event(drv->ctx, EVENT_RADAR_FLAGS_CHANGED,
+ &data);
+ break;
+ }
+}
static int process_event(struct nl_msg *msg, void *arg)
{
@@ -1404,6 +1424,9 @@ static int process_event(struct nl_msg *msg, void *arg)
case NL80211_CMD_NEW_STATION:
nl80211_new_station_event(drv, tb);
break;
+ case NL80211_CMD_RADAR_FLAGS_CHANGED:
+ nl80211_radar_event(drv, gnlh->cmd, tb);
+ break;
default:
wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
"(cmd=%d)", gnlh->cmd);
@@ -3059,6 +3082,8 @@ static int phy_info_handler(struct nl_msg *msg, void *arg)
[NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG },
[NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 },
+ [NL80211_FREQUENCY_ATTR_RADAR_CLEAR] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_RADAR_INTEFERENCE] = { .type = NLA_FLAG },
};
struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1];
@@ -3172,6 +3197,12 @@ static int phy_info_handler(struct nl_msg *msg, void *arg)
if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR])
mode->channels[idx].flag |=
HOSTAPD_CHAN_RADAR;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR_CLEAR])
+ mode->channels[idx].flag |=
+ HOSTAPD_CHAN_RADAR_CLEAR;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR_INTEFERENCE])
+ mode->channels[idx].flag |=
+ HOSTAPD_CHAN_RADAR_INTERFERENCE;
if (tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] &&
!tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
--
1.5.6.5
NOL is a list of channels on which radar interference has been detected.
Such channels are not allowed to be used for a certain amount of time.
---
include/net/mac80211.h | 8 +++++
net/mac80211/radar.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++
net/mac80211/radar.h | 9 ++++++
3 files changed, 91 insertions(+), 0 deletions(-)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index b158be5..4ebc080 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -2773,6 +2773,14 @@ void ieee80211_remain_on_channel_expired(struct ieee80211_hw *hw);
void ieee80211_radar_update_params(struct ieee80211_hw *hw,
const struct ieee80211_regdomain *regd);
+/**
+ * ieee80211_radar_interference - report interference on a channel
+ * @hw: pointer as obtained from ieee80211_alloc_hw()
+ * @channel: the channel on which the event occurred
+ */
+int ieee80211_radar_interference(struct ieee80211_hw *hw,
+ struct ieee80211_channel *chan);
+
/* Rate control API */
/**
diff --git a/net/mac80211/radar.c b/net/mac80211/radar.c
index 9f41dd7..e90b8bf 100644
--- a/net/mac80211/radar.c
+++ b/net/mac80211/radar.c
@@ -15,6 +15,67 @@
#include "driver-ops.h"
#include "radar.h"
+static void nol_timer(unsigned long data)
+{
+ struct ieee80211_local *local = (void *) data;
+ struct ieee80211_radar *radar = &local->radar;
+ struct ieee80211_radar_nol_list *nol, *tmp;
+
+ list_for_each_entry_safe(nol, tmp, &radar->nol_list, list) {
+ if (time_is_before_jiffies(nol->timeout)) {
+ struct ieee80211_channel *chan = nol->chan;
+
+ printk(KERN_INFO "remove NOL chan %d\n",
+ chan->center_freq);
+
+ mutex_lock(&radar->mtx);
+ chan->flags &= ~IEEE80211_CHAN_RADAR_INTERFERENCE;
+ list_del(&nol->list);
+ mutex_unlock(&radar->mtx);
+ kfree(nol);
+ }
+ }
+
+ mod_timer(&radar->nol_timer, jiffies + msecs_to_jiffies(1000));
+}
+
+int ieee80211_radar_interference(struct ieee80211_hw *hw,
+ struct ieee80211_channel *chan)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct ieee80211_radar *radar = &local->radar;
+ struct ieee80211_radar_nol_list *nol, *tmp;
+
+ list_for_each_entry_safe(nol, tmp, &radar->nol_list, list) {
+ if (nol->chan == chan) {
+ mutex_lock(&radar->mtx);
+ list_del(&nol->list);
+ mutex_unlock(&radar->mtx);
+ kfree(nol);
+ break;
+ }
+ }
+
+ nol = kmalloc(sizeof(struct ieee80211_radar_nol_list), GFP_KERNEL);
+ if (nol == NULL)
+ return -ENOMEM;
+
+ nol->chan = chan;
+ nol->timeout = jiffies +
+ msecs_to_jiffies(radar->params->nol_period * 1000);
+
+ printk(KERN_INFO "add NOL chan %d\n", chan->center_freq);
+
+ mutex_lock(&radar->mtx);
+ chan->flags &= ~IEEE80211_CHAN_RADAR_CLEAR;
+ chan->flags |= IEEE80211_CHAN_RADAR_INTERFERENCE;
+ list_add_tail(&nol->list, &radar->nol_list);
+ mutex_unlock(&radar->mtx);
+
+ return 0;
+}
+EXPORT_SYMBOL(ieee80211_radar_interference);
+
int ieee80211_radar_detection_enable(struct ieee80211_local *local,
struct ieee80211_channel *chan)
{
@@ -74,11 +135,24 @@ void ieee80211_radar_init(struct ieee80211_local *local)
radar->params = ®domain_params[0];
mutex_init(&radar->mtx);
+
+ INIT_LIST_HEAD(&radar->nol_list);
+ setup_timer(&radar->nol_timer, nol_timer, (unsigned long)local);
+ mod_timer(&radar->nol_timer, jiffies + msecs_to_jiffies(1000));
}
void ieee80211_radar_deinit(struct ieee80211_local *local)
{
struct ieee80211_radar *radar = &local->radar;
+ struct ieee80211_radar_nol_list *nol, *tmp;
+
+ del_timer_sync(&radar->nol_timer);
+ mutex_lock(&radar->mtx);
+ list_for_each_entry_safe(nol, tmp, &radar->nol_list, list) {
+ list_del(&nol->list);
+ kfree(nol);
+ }
+ mutex_unlock(&radar->mtx);
mutex_destroy(&radar->mtx);
}
diff --git a/net/mac80211/radar.h b/net/mac80211/radar.h
index 6536e28..79684b5 100644
--- a/net/mac80211/radar.h
+++ b/net/mac80211/radar.h
@@ -21,9 +21,18 @@ struct ieee80211_radar_parameters {
int nol_period;
};
+struct ieee80211_radar_nol_list {
+ struct ieee80211_channel *chan;
+ unsigned long timeout;
+ struct list_head list;
+};
+
struct ieee80211_radar {
struct mutex mtx;
struct ieee80211_radar_parameters *params;
+
+ struct timer_list nol_timer;
+ struct list_head nol_list;
};
int ieee80211_radar_detection_enable(struct ieee80211_local *local,
--
1.5.6.5
On 01/18/2011 01:27 PM, Bernhard Schmidt wrote:
> On Tuesday, January 18, 2011 13:16:13 Johannes Berg wrote:
>> On Tue, 2011-01-18 at 12:59 +0100, Bernhard Schmidt wrote:
>>>> I'm not sure about this -- shouldn't that be global information?
>>>> If one device in the system records a radar on the channel, it
>>>> surely applies to other devices as well, even if they are
>>>> hot-plugged after the radar was found?
>>>
>>> True, I've based this on our IRC discussions, the consensus there
>>> was to do it per-wiphy only at first.
>>
>> I thought what we had discussed there (but I missed at least one
>> meeting) was that the *detector* state, for software-based detection,
>> should be per wiphy. I never heard anywhere that the result of that
>> should be local too.
>
> Hmm, ok, I might have got that wrong. We should discuss this today on
> IRC and whatever the consensus is, I will adjust the code.
>
We discussed that each wiphy needs to have its own pattern detector, due to a missing common time base for accurately time stamp the pulse events.
The channel states on the other hand should be system global, i.e. if one wiphy detected radars on some channel, that channel should not be used by other wiphys.
Ideally the state should be even regulatory specific to support pure radar scanning devices (johill already told that mac82011 does not support per wiphy multi-countrycode operation, but let's plan long term...)
Cheers
Zefir
On Tuesday, January 18, 2011 11:40:36 Johannes Berg wrote:
> On Mon, 2011-01-17 at 09:31 +0100, Bernhard Schmidt wrote:
> > Before a radar channel can be used, a full CAC has be done, the
> > IEEE80211_CHAN_RADAR_CLEAR flags indicates that this has been done.
> > If either during CAC or in-service monitoring interference is
> > detected, the channel is added to NOL and marked with
> > IEEE80211_CHAN_RADAR_INTERFERENCE.
>
> I'm not sure about this -- shouldn't that be global information? If
> one device in the system records a radar on the channel, it surely
> applies to other devices as well, even if they are hot-plugged after
> the radar was found?
True, I've based this on our IRC discussions, the consensus there was to
do it per-wiphy only at first.
--
Best regards,
Dipl.-Inf. (FH) Bernhard Schmidt (software development)
saxnet GmbH, Willy-Brandt-Ring 1, 08606 Oelsnitz
Tel. +49 (0) 3741 300 6. 100 - Fax +49 (0) 3741 300 6. 101
managing director: Steffen Dreise - county court Chemnitz - HRB 23017
http://www.saxnet.de
On Tuesday, January 18, 2011 13:16:13 Johannes Berg wrote:
> On Tue, 2011-01-18 at 12:59 +0100, Bernhard Schmidt wrote:
> > > I'm not sure about this -- shouldn't that be global information?
> > > If one device in the system records a radar on the channel, it
> > > surely applies to other devices as well, even if they are
> > > hot-plugged after the radar was found?
> >
> > True, I've based this on our IRC discussions, the consensus there
> > was to do it per-wiphy only at first.
>
> I thought what we had discussed there (but I missed at least one
> meeting) was that the *detector* state, for software-based detection,
> should be per wiphy. I never heard anywhere that the result of that
> should be local too.
Hmm, ok, I might have got that wrong. We should discuss this today on
IRC and whatever the consensus is, I will adjust the code.
--
Best regards,
Dipl.-Inf. (FH) Bernhard Schmidt (software development)
saxnet GmbH, Willy-Brandt-Ring 1, 08606 Oelsnitz
Tel. +49 (0) 3741 300 6. 100 - Fax +49 (0) 3741 300 6. 101
managing director: Steffen Dreise - county court Chemnitz - HRB 23017
http://www.saxnet.de
On Mon, 2011-01-17 at 11:05 +0100, Bernhard Schmidt wrote:
> NOL is a list of channels on which radar interference has been detected.
> Such channels are not allowed to be used for a certain amount of time.
I don't think this should be implemented in mac80211.
johannes
---
src/drivers/nl80211_copy.h | 17 +++++++++++++++++
1 files changed, 17 insertions(+), 0 deletions(-)
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index 7483a89..960341c 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -406,6 +406,12 @@
* notification. This event is used to indicate that an unprotected
* disassociation frame was dropped when MFP is in use.
*
+ * @NL80211_CMD_RADAR_CAC_START: Request a CAC
+ * @NL80211_CMD_RADAR_CAC_STOP: Stop as CAC earler
+ * @NL80211_CMD_RADAR_CAC_DONE: Notification sent if a CAC has completed.
+ * @NL80211_CMD_RADAR_FLAGS_CHANGED: Notification sent if channel flags
+ * have changed.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -518,6 +524,11 @@ enum nl80211_commands {
NL80211_CMD_UNPROT_DEAUTHENTICATE,
NL80211_CMD_UNPROT_DISASSOCIATE,
+ NL80211_CMD_RADAR_CAC_START,
+ NL80211_CMD_RADAR_CAC_STOP,
+ NL80211_CMD_RADAR_CAC_DONE,
+ NL80211_CMD_RADAR_FLAGS_CHANGED,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -1338,6 +1349,10 @@ enum nl80211_band_attr {
* (100 * dBm).
* @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
* currently defined
+ * @NL80211_FREQUENCY_ATTR_RADAR_CLEAR: during a full CAC no interference has
+ * been detected
+ * @NL80211_FREQUENCY_ATTR_RADAR_INTERFERENCE: either during a CAC or
+ * in-service monitoring radar interference was detected
* @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
*/
enum nl80211_frequency_attr {
@@ -1348,6 +1363,8 @@ enum nl80211_frequency_attr {
NL80211_FREQUENCY_ATTR_NO_IBSS,
NL80211_FREQUENCY_ATTR_RADAR,
NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
+ NL80211_FREQUENCY_ATTR_RADAR_CLEAR,
+ NL80211_FREQUENCY_ATTR_RADAR_INTEFERENCE,
/* keep last */
__NL80211_FREQUENCY_ATTR_AFTER_LAST,
--
1.5.6.5
On Tue, 2011-01-18 at 13:01 +0100, Bernhard Schmidt wrote:
> > > + mutex_lock(&radar->mtx);
> >
> > Clearly, you haven't even tested this code. I'm not sure why I'm even
> > reviewing it.
>
> Granted, I did only some basic tests with only a few predefined
> scenarios, not at all is just wrong. Anyways, I should have mentioned in
> 0/13 that preventing channel changes while in CAC should be considered
> and chan should be assigned to local variable then.
I was more referring to the fact that you're trying to lock a mutex in a
timer -- so you can't have executed this code path ever?!
johannes
- ieee80211_radar_update_params() can be used by drivers to update regdomain
related parameters on regulatory changes.
- radar_detection is used to identify if a driver has support for radar
detection or not. It is called when switching from and to a channel
marked as radar detection required.
---
include/net/mac80211.h | 11 ++++++
net/mac80211/Makefile | 3 +-
net/mac80211/cfg.c | 5 +++
net/mac80211/driver-ops.h | 14 +++++++
net/mac80211/driver-trace.h | 21 +++++++++++
net/mac80211/ieee80211_i.h | 3 ++
net/mac80211/main.c | 5 +++
net/mac80211/radar.c | 84 +++++++++++++++++++++++++++++++++++++++++++
net/mac80211/radar.h | 36 ++++++++++++++++++
9 files changed, 181 insertions(+), 1 deletions(-)
create mode 100644 net/mac80211/radar.c
create mode 100644 net/mac80211/radar.h
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 62c0ce2..b158be5 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1767,6 +1767,8 @@ enum ieee80211_ampdu_mlme_action {
* ieee80211_remain_on_channel_expired(). This callback may sleep.
* @cancel_remain_on_channel: Requests that an ongoing off-channel period is
* aborted before it expires. This callback may sleep.
+ *
+ * @radar_detection: Enable or disable radar detection on current channel.
*/
struct ieee80211_ops {
int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
@@ -1845,6 +1847,8 @@ struct ieee80211_ops {
enum nl80211_channel_type channel_type,
int duration);
int (*cancel_remain_on_channel)(struct ieee80211_hw *hw);
+
+ int (*radar_detection)(struct ieee80211_hw *hw, int enable);
};
/**
@@ -2762,6 +2766,13 @@ void ieee80211_ready_on_channel(struct ieee80211_hw *hw);
*/
void ieee80211_remain_on_channel_expired(struct ieee80211_hw *hw);
+/**
+ * ieee80211_radar_update_params - update regdomain related radar parameteters
+ * @hw: pointer as obtained from ieee80211_alloc_hw()
+ */
+void ieee80211_radar_update_params(struct ieee80211_hw *hw,
+ const struct ieee80211_regdomain *regd);
+
/* Rate control API */
/**
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile
index fdb54e6..deff05b 100644
--- a/net/mac80211/Makefile
+++ b/net/mac80211/Makefile
@@ -24,7 +24,8 @@ mac80211-y := \
util.o \
wme.o \
event.o \
- chan.o
+ chan.o \
+ radar.o
mac80211-$(CONFIG_MAC80211_LEDS) += led.o
mac80211-$(CONFIG_MAC80211_DEBUGFS) += \
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 4bc8a92..a6a2c0b 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -18,6 +18,7 @@
#include "cfg.h"
#include "rate.h"
#include "mesh.h"
+#include "radar.h"
static struct net_device *ieee80211_add_iface(struct wiphy *wiphy, char *name,
enum nl80211_iftype type,
@@ -1232,6 +1233,8 @@ static int ieee80211_set_channel(struct wiphy *wiphy,
break;
}
+ ieee80211_radar_detection_disable(local, local->oper_channel);
+
local->oper_channel = chan;
if (!ieee80211_set_channel_type(local, sdata, channel_type))
@@ -1241,6 +1244,8 @@ static int ieee80211_set_channel(struct wiphy *wiphy,
if (sdata && sdata->vif.type != NL80211_IFTYPE_MONITOR)
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT);
+ ieee80211_radar_detection_enable(local, chan);
+
return 0;
}
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 98d5899..b8bcf46 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -495,4 +495,18 @@ static inline int drv_cancel_remain_on_channel(struct ieee80211_local *local)
return ret;
}
+static inline int drv_radar_detection(struct ieee80211_local *local, int enable)
+{
+ int ret = -EOPNOTSUPP;
+
+ might_sleep();
+
+ trace_drv_radar_detection(local, enable);
+ if (local->ops->radar_detection)
+ ret = local->ops->radar_detection(&local->hw, enable);
+ trace_drv_return_int(local, ret);
+
+ return ret;
+}
+
#endif /* __MAC80211_DRIVER_OPS */
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h
index 49c8421..09cd205 100644
--- a/net/mac80211/driver-trace.h
+++ b/net/mac80211/driver-trace.h
@@ -1250,6 +1250,27 @@ TRACE_EVENT(api_remain_on_channel_expired,
)
);
+TRACE_EVENT(drv_radar_detection,
+ TP_PROTO(struct ieee80211_local *local, int enable),
+
+ TP_ARGS(local, enable),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(int, enable)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->enable = enable;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT " enable:%d",
+ LOCAL_PR_ARG, __entry->enable
+ )
+);
+
/*
* Tracing for internal functions
* (which may also be called in response to driver calls)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index c47d7c0..5c46b14 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -29,6 +29,7 @@
#include <net/mac80211.h>
#include "key.h"
#include "sta_info.h"
+#include "radar.h"
struct ieee80211_local;
@@ -929,6 +930,8 @@ struct ieee80211_local {
struct notifier_block network_latency_notifier;
struct notifier_block ifa_notifier;
+ struct ieee80211_radar radar;
+
/*
* The dynamic ps timeout configured from user space via WEXT -
* this will override whatever chosen by mac80211 internally.
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index a46ff06..5841920 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -32,6 +32,7 @@
#include "led.h"
#include "cfg.h"
#include "debugfs.h"
+#include "radar.h"
bool ieee80211_disable_40mhz_24ghz;
@@ -621,6 +622,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
ieee80211_hw_roc_setup(local);
+ ieee80211_radar_init(local);
+
return local_to_hw(local);
}
EXPORT_SYMBOL(ieee80211_alloc_hw);
@@ -891,6 +894,8 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
{
struct ieee80211_local *local = hw_to_local(hw);
+ ieee80211_radar_deinit(local);
+
tasklet_kill(&local->tx_pending_tasklet);
tasklet_kill(&local->tasklet);
diff --git a/net/mac80211/radar.c b/net/mac80211/radar.c
new file mode 100644
index 0000000..9f41dd7
--- /dev/null
+++ b/net/mac80211/radar.c
@@ -0,0 +1,84 @@
+/*
+ * Radar handling
+ *
+ * Copyright 2011 Bernhard Schmidt <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <net/mac80211.h>
+#include <net/rtnetlink.h>
+
+#include "ieee80211_i.h"
+#include "driver-ops.h"
+#include "radar.h"
+
+int ieee80211_radar_detection_enable(struct ieee80211_local *local,
+ struct ieee80211_channel *chan)
+{
+ int ret = 0;
+
+ if ((chan->flags & IEEE80211_CHAN_RADAR))
+ ret = drv_radar_detection(local, 1);
+
+ return ret;
+}
+
+int ieee80211_radar_detection_disable(struct ieee80211_local *local,
+ struct ieee80211_channel *chan)
+{
+ int ret = 0;
+
+ if ((chan->flags & IEEE80211_CHAN_RADAR))
+ ret = drv_radar_detection(local, 0);
+
+ return ret;
+}
+
+static struct ieee80211_radar_parameters regdomain_params[] = {
+ { .cac_period = 60, .nol_period = 1800 }, /* FCC, correct? */
+ { .cac_period = 60, .nol_period = 1800 }, /* ETSI */
+ { .cac_period = 60, .nol_period = 1800 }, /* JP, correct? */
+};
+
+void ieee80211_radar_update_params(struct ieee80211_hw *hw,
+ const struct ieee80211_regdomain *regd)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct ieee80211_radar *radar = &local->radar;
+
+ switch (regd->flags & NL80211_CFLAG_ALL_DFS_FLAGS) {
+ case NL80211_CFLAG_DFS_ETSI:
+ radar->params = ®domain_params[1];
+ break;
+ case NL80211_CFLAG_DFS_JP:
+ radar->params = ®domain_params[2];
+ break;
+ default:
+ radar->params = ®domain_params[0];
+ break;
+ }
+}
+EXPORT_SYMBOL(ieee80211_radar_update_params);
+
+void ieee80211_radar_init(struct ieee80211_local *local)
+{
+ struct ieee80211_radar *radar = &local->radar;
+
+ /*
+ * NB: use FCC by default, will be updated later once regulatory
+ * information are available.
+ */
+ radar->params = ®domain_params[0];
+
+ mutex_init(&radar->mtx);
+}
+
+void ieee80211_radar_deinit(struct ieee80211_local *local)
+{
+ struct ieee80211_radar *radar = &local->radar;
+
+ mutex_destroy(&radar->mtx);
+}
diff --git a/net/mac80211/radar.h b/net/mac80211/radar.h
new file mode 100644
index 0000000..6536e28
--- /dev/null
+++ b/net/mac80211/radar.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2011 Bernhard Schmidt <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef RADAR_H
+#define RADAR_H
+
+/*
+ * Regdomain related parameters.
+ */
+struct ieee80211_radar_parameters {
+
+ /* Time in seconds for a CAC period. */
+ int cac_period;
+
+ /* Time in seconds a channel is on the no operations list. */
+ int nol_period;
+};
+
+struct ieee80211_radar {
+ struct mutex mtx;
+ struct ieee80211_radar_parameters *params;
+};
+
+int ieee80211_radar_detection_enable(struct ieee80211_local *local,
+ struct ieee80211_channel *chan);
+int ieee80211_radar_detection_disable(struct ieee80211_local *local,
+ struct ieee80211_channel *chan);
+void ieee80211_radar_init(struct ieee80211_local *local);
+void ieee80211_radar_deinit(struct ieee80211_local *local);
+
+#endif
--
1.5.6.5
---
hostapd/config_file.c | 13 +++++++------
1 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 4938611..f6b9926 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -646,14 +646,14 @@ static int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx,
}
-static int hostapd_parse_rates(int **rate_list, char *val)
+static int hostapd_parse_int_list(int **int_list, char *val)
{
int *list;
int count;
char *pos, *end;
- os_free(*rate_list);
- *rate_list = NULL;
+ os_free(*int_list);
+ *int_list = NULL;
pos = val;
count = 0;
@@ -680,7 +680,7 @@ static int hostapd_parse_rates(int **rate_list, char *val)
}
list[count] = -1;
- *rate_list = list;
+ *int_list = list;
return 0;
}
@@ -1785,13 +1785,14 @@ struct hostapd_config * hostapd_config_read(const char *fname)
} else
conf->send_probe_response = val;
} else if (os_strcmp(buf, "supported_rates") == 0) {
- if (hostapd_parse_rates(&conf->supported_rates, pos)) {
+ if (hostapd_parse_int_list(&conf->supported_rates,
+ pos)) {
wpa_printf(MSG_ERROR, "Line %d: invalid rate "
"list", line);
errors++;
}
} else if (os_strcmp(buf, "basic_rates") == 0) {
- if (hostapd_parse_rates(&conf->basic_rates, pos)) {
+ if (hostapd_parse_int_list(&conf->basic_rates, pos)) {
wpa_printf(MSG_ERROR, "Line %d: invalid rate "
"list", line);
errors++;
--
1.5.6.5
On Tue, 2011-01-18 at 12:59 +0100, Bernhard Schmidt wrote:
> > I'm not sure about this -- shouldn't that be global information? If
> > one device in the system records a radar on the channel, it surely
> > applies to other devices as well, even if they are hot-plugged after
> > the radar was found?
>
> True, I've based this on our IRC discussions, the consensus there was to
> do it per-wiphy only at first.
I thought what we had discussed there (but I missed at least one
meeting) was that the *detector* state, for software-based detection,
should be per wiphy. I never heard anywhere that the result of that
should be local too.
johannes
---
src/ap/hw_features.c | 13 -------------
1 files changed, 0 insertions(+), 13 deletions(-)
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index a7f4eda..81caf63 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -126,19 +126,6 @@ int hostapd_get_hw_features(struct hostapd_iface *iface)
/* set flag for channels we can use in current regulatory
* domain */
for (j = 0; j < feature->num_channels; j++) {
- /*
- * Disable all channels that are marked not to allow
- * IBSS operation or active scanning. In addition,
- * disable all channels that require radar detection,
- * since that (in addition to full DFS) is not yet
- * supported.
- */
- if (feature->channels[j].flag &
- (HOSTAPD_CHAN_NO_IBSS |
- HOSTAPD_CHAN_PASSIVE_SCAN |
- HOSTAPD_CHAN_RADAR))
- feature->channels[j].flag |=
- HOSTAPD_CHAN_DISABLED;
if (feature->channels[j].flag & HOSTAPD_CHAN_DISABLED)
continue;
wpa_printf(MSG_MSGDUMP, "Allowed channel: mode=%d "
--
1.5.6.5
On Mon, 2011-01-17 at 10:16 +0100, Bernhard Schmidt wrote:
> +static struct ieee80211_radar_parameters regdomain_params[] = {
> + { .cac_period = 60, .nol_period = 1800 }, /* FCC, correct? */
> + { .cac_period = 60, .nol_period = 1800 }, /* ETSI */
> + { .cac_period = 60, .nol_period = 1800 }, /* JP, correct? */
> +};
These parameters really need to come from cfg80211/userspace.
johannes
---
hostapd/config_file.c | 7 +++++++
src/ap/ap_config.c | 1 +
src/ap/ap_config.h | 1 +
3 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index f6b9926..119a4bb 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -1736,6 +1736,13 @@ struct hostapd_config * hostapd_config_read(const char *fname)
}
} else if (os_strcmp(buf, "channel") == 0) {
conf->channel = atoi(pos);
+ } else if (os_strcmp(buf, "channel_list") == 0) {
+ if (hostapd_parse_int_list(&conf->channel_list,
+ pos)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid channel"
+ " list", line);
+ errors++;
+ }
} else if (os_strcmp(buf, "beacon_int") == 0) {
int val = atoi(pos);
/* MIB defines range as 1..65535, but very small values
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 702cb76..38e70fb 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -466,6 +466,7 @@ void hostapd_config_free(struct hostapd_config *conf)
os_free(conf->bss);
os_free(conf->supported_rates);
os_free(conf->basic_rates);
+ os_free(conf->channel_list);
os_free(conf);
}
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 0a929d6..57c977d 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -340,6 +340,7 @@ struct hostapd_config {
int fragm_threshold;
u8 send_probe_response;
u8 channel;
+ int *channel_list;
enum hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */
enum {
LONG_PREAMBLE = 0,
--
1.5.6.5
On Tuesday, January 18, 2011 11:43:22 Johannes Berg wrote:
> On Mon, 2011-01-17 at 10:16 +0100, Bernhard Schmidt wrote:
> > @@ -1241,6 +1244,8 @@ static int ieee80211_set_channel(struct wiphy
> > *wiphy,
> >
> > if (sdata && sdata->vif.type != NL80211_IFTYPE_MONITOR)
> >
> > ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT);
> >
> > + ieee80211_radar_detection_enable(local, chan);
> > +
>
> So you're ignoring the return value -- that doesn't seem right at
> all. Also, if the driver doesn't implement detection, you should
> probably reject using the channel.
Yeah right, I've missed that. I wasn't sure about how to proper handle
opmode and then forgot about it.. Point is, this should only fail on an
opmode which does involve sending beacons (or in other words, opmodes
which act as a master device) but not for sta. Will think about
something.
--
Best regards,
Dipl.-Inf. (FH) Bernhard Schmidt (software development)
saxnet GmbH, Willy-Brandt-Ring 1, 08606 Oelsnitz
Tel. +49 (0) 3741 300 6. 100 - Fax +49 (0) 3741 300 6. 101
managing director: Steffen Dreise - county court Chemnitz - HRB 23017
http://www.saxnet.de
---
src/ap/ap_drv_ops.c | 7 ++++
src/ap/ap_drv_ops.h | 1 +
src/ap/drv_callbacks.c | 4 ++
src/ap/hostapd.c | 83 ++++++++++++++++++++++++++++++++++++++++++
src/ap/hostapd.h | 5 +++
src/ap/hw_features.c | 2 +-
src/drivers/driver.h | 9 +++++
src/drivers/driver_nl80211.c | 35 ++++++++++++++++++
8 files changed, 145 insertions(+), 1 deletions(-)
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 7f9522a..4d260ac 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -429,6 +429,13 @@ int hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq,
return hapd->driver->set_freq(hapd->drv_priv, &data);
}
+int hostapd_radar_cac(struct hostapd_data *hapd, int enable)
+{
+ if (hapd->driver == NULL || hapd->driver->radar_cac == NULL)
+ return -1;
+ return hapd->driver->radar_cac(hapd->drv_priv, enable);
+}
+
int hostapd_set_rts(struct hostapd_data *hapd, int rts)
{
if (hapd->driver == NULL || hapd->driver->set_rts == NULL)
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 5bc9d01..3c51422 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -53,6 +53,7 @@ int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd,
int hostapd_flush(struct hostapd_data *hapd);
int hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq,
int channel, int ht_enabled, int sec_channel_offset);
+int hostapd_radar_cac(struct hostapd_data *hapd, int enable);
int hostapd_set_rts(struct hostapd_data *hapd, int rts);
int hostapd_set_frag(struct hostapd_data *hapd, int frag);
int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index c55c42a..1006bc0 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -521,6 +521,10 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
break;
hostapd_event_sta_low_ack(hapd, data->low_ack.addr);
break;
+ case EVENT_RADAR_CAC_DONE:
+ if (hapd->iface->radar_cac_cb)
+ hapd->iface->radar_cac_cb(hapd);
+ break;
case EVENT_RADAR_FLAGS_CHANGED:
hostapd_radar_flags_changed(hapd, data->radar.freq,
data->radar.flags);
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 592a01f..a065fc9 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -695,6 +695,82 @@ static int setup_interface(struct hostapd_iface *iface)
return 0;
}
}
+ return hostapd_setup_radar_complete(iface);
+}
+
+static int hostapd_channel_availability_check(struct hostapd_data *hapd)
+{
+ struct hostapd_iface *iface = hapd->iface;
+
+ iface->freq = hostapd_hw_get_freq(hapd, hapd->iconf->channel);
+ if (hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq,
+ hapd->iconf->channel,
+ hapd->iconf->ieee80211n,
+ hapd->iconf->secondary_channel)) {
+ wpa_printf(MSG_ERROR, "Could not set channel for "
+ "kernel driver");
+ return -1;
+ }
+
+ if (hostapd_radar_cac(hapd, 1))
+ return -1;
+
+ return 0;
+}
+
+static void hostapd_cac_done(struct hostapd_data *hapd)
+{
+ struct hostapd_iface *iface = hapd->iface;
+ u32 flags;
+
+ iface->radar_cac_cb = NULL;
+ iface->radar_flags_cb = NULL;
+ flags = hostapd_hw_get_radar_flags(hapd, iface->conf->channel);
+ if ((flags & HOSTAPD_CHAN_RADAR_CLEAR)) {
+ hostapd_setup_interface_complete(iface, 0);
+ return;
+ }
+ if ((flags & HOSTAPD_CHAN_RADAR_INTERFERENCE)) {
+ int chan = iface->conf->channel;
+ u32 newflags;
+ iface->conf->channel = 0;
+ if (hostapd_select_random_channel(iface))
+ iface->conf->channel = chan;
+ newflags = hostapd_hw_get_radar_flags(hapd,
+ iface->conf->channel);
+ if ((newflags & HOSTAPD_CHAN_RADAR_INTERFERENCE))
+ iface->radar_flags_cb = hostapd_cac_done;
+ else
+ hostapd_cac_done(hapd);
+ } else {
+ if (hostapd_channel_availability_check(hapd))
+ hostapd_setup_interface_complete(iface, 1);
+ iface->radar_cac_cb = hostapd_cac_done;
+ }
+}
+
+int hostapd_setup_radar_complete(struct hostapd_iface *iface)
+{
+ struct hostapd_data *hapd = iface->bss[0];
+ u32 flags;
+
+ flags = hostapd_hw_get_radar_flags(hapd, iface->conf->channel);
+ if ((flags & HOSTAPD_CHAN_RADAR) == 0)
+ return hostapd_setup_interface_complete(iface, 0);
+ if ((flags & HOSTAPD_CHAN_RADAR_INTERFERENCE)) {
+ hapd->iface->radar_flags_cb = hostapd_cac_done;
+ wpa_printf(MSG_DEBUG, "Interface initialization will "
+ "be completed in a callback");
+ return 0;
+ }
+ if ((flags & HOSTAPD_CHAN_RADAR_CLEAR) == 0) {
+ if (hostapd_channel_availability_check(hapd))
+ return hostapd_setup_interface_complete(iface, 1);
+ iface->radar_cac_cb = hostapd_cac_done;
+ wpa_printf(MSG_DEBUG, "Interface initialization will "
+ "be completed in a callback");
+ return 0;
+ }
return hostapd_setup_interface_complete(iface, 0);
}
@@ -919,5 +995,12 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
void hostapd_radar_flags_changed(struct hostapd_data *hapd, int freq, u32 flags)
{
+ struct hostapd_iface *iface = hapd->iface;
+
hostapd_hw_set_radar_flags(hapd, freq, flags);
+
+ if (iface->radar_flags_cb) {
+ iface->radar_flags_cb(hapd);
+ return;
+ }
}
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index e2e4234..b38a91d 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -215,6 +215,10 @@ struct hostapd_iface {
u16 ht_op_mode;
void (*scan_cb)(struct hostapd_iface *iface);
+ /* Radar handling callbacks */
+ void (*radar_cac_cb)(struct hostapd_data *hapd);
+ void (*radar_flags_cb)(struct hostapd_data *hapd);
+
int (*ctrl_iface_init)(struct hostapd_data *hapd);
void (*ctrl_iface_deinit)(struct hostapd_data *hapd);
@@ -230,6 +234,7 @@ hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
struct hostapd_config *conf,
struct hostapd_bss_config *bss);
int hostapd_setup_interface(struct hostapd_iface *iface);
+int hostapd_setup_radar_complete(struct hostapd_iface *iface);
int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err);
void hostapd_interface_deinit(struct hostapd_iface *iface);
void hostapd_interface_free(struct hostapd_iface *iface);
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 04bf210..a7f4eda 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -505,7 +505,7 @@ static void ieee80211n_check_scan(struct hostapd_iface *iface)
iface->conf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
}
- hostapd_setup_interface_complete(iface, 0);
+ hostapd_setup_radar_complete(iface);
}
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 777f854..0bbf4bd 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -1498,6 +1498,14 @@ struct wpa_driver_ops {
int (*set_freq)(void *priv, struct hostapd_freq_params *freq);
/**
+ * radar_cac - Start/stop CAC (AP only)
+ * @priv: Private driver interface data
+ * @enable: Enable/disable CAC (0 = disable, 1 = enable)
+ * Returns 0 on success, -1 on failure
+ */
+ int (*radar_cac)(void *priv, int enable);
+
+ /**
* set_rts - Set RTS threshold
* @priv: Private driver interface data
* @rts: RTS threshold in octets
@@ -2581,6 +2589,7 @@ enum wpa_event_type {
EVENT_P2P_SD_REQUEST,
EVENT_P2P_SD_RESPONSE,
+ EVENT_RADAR_CAC_DONE,
EVENT_RADAR_FLAGS_CHANGED,
};
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index d919a73..b7b7bdb 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -1294,6 +1294,9 @@ static void nl80211_radar_event(struct wpa_driver_nl80211_data *drv, u32 cmd,
union wpa_event_data data;
switch (cmd) {
+ case NL80211_CMD_RADAR_CAC_DONE:
+ wpa_supplicant_event(drv->ctx, EVENT_RADAR_CAC_DONE, NULL);
+ break;
case NL80211_CMD_RADAR_FLAGS_CHANGED:
if (!tb[NL80211_FREQUENCY_ATTR_FREQ])
return;
@@ -1424,6 +1427,7 @@ static int process_event(struct nl_msg *msg, void *arg)
case NL80211_CMD_NEW_STATION:
nl80211_new_station_event(drv, tb);
break;
+ case NL80211_CMD_RADAR_CAC_DONE:
case NL80211_CMD_RADAR_FLAGS_CHANGED:
nl80211_radar_event(drv, gnlh->cmd, tb);
break;
@@ -5102,6 +5106,36 @@ static int i802_set_freq(void *priv, struct hostapd_freq_params *freq)
#ifdef HOSTAPD
+static int i802_radar_cac(void *priv, int enable)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int cmd, ret;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ if (enable)
+ cmd = NL80211_CMD_RADAR_CAC_START;
+ else
+ cmd = NL80211_CMD_RADAR_CAC_STOP;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, cmd, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret != 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to start CAC: %d (%s)",
+ ret, strerror(-ret));
+ }
+ return ret;
+
+ nla_put_failure:
+ return -1;
+}
+
static int i802_set_rts(void *priv, int rts)
{
struct i802_bss *bss = priv;
@@ -6424,6 +6458,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.hapd_deinit = i802_deinit,
.get_seqnum = i802_get_seqnum,
.flush = i802_flush,
+ .radar_cac = i802_radar_cac,
.read_sta_data = i802_read_sta_data,
.sta_deauth = i802_sta_deauth,
.sta_disassoc = i802_sta_disassoc,
--
1.5.6.5
On Tuesday, January 18, 2011 13:13:05 Johannes Berg wrote:
> On Tue, 2011-01-18 at 13:01 +0100, Bernhard Schmidt wrote:
> > On Tuesday, January 18, 2011 11:43:46 Johannes Berg wrote:
> > > On Mon, 2011-01-17 at 11:05 +0100, Bernhard Schmidt wrote:
> > > > NOL is a list of channels on which radar interference has been
> > > > detected. Such channels are not allowed to be used for a
> > > > certain amount of time.
> > >
> > > I don't think this should be implemented in mac80211.
> >
> > In cfg80211 then? I'd really prefer to keep all flag-handling
> > together instead of splitting it up between mac80211/userspace.
>
> Yeah, cfg80211 sounds much saner, with APIs there etc.
Ok, will move it there.
--
Best regards,
Dipl.-Inf. (FH) Bernhard Schmidt (software development)
saxnet GmbH, Willy-Brandt-Ring 1, 08606 Oelsnitz
Tel. +49 (0) 3741 300 6. 100 - Fax +49 (0) 3741 300 6. 101
managing director: Steffen Dreise - county court Chemnitz - HRB 23017
http://www.saxnet.de
---
include/linux/nl80211.h | 11 +++++
include/net/cfg80211.h | 18 ++++++++
net/mac80211/cfg.c | 1 +
net/mac80211/radar.c | 21 +++++++++
net/wireless/nl80211.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++
net/wireless/nl80211.h | 4 ++
net/wireless/util.c | 20 +++++++++
7 files changed, 179 insertions(+), 0 deletions(-)
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index acb3c33..fa65287 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -410,6 +410,12 @@
* notification. This event is used to indicate that an unprotected
* disassociation frame was dropped when MFP is in use.
*
+ * @NL80211_CMD_RADAR_CAC_START: Request a CAC
+ * @NL80211_CMD_RADAR_CAC_STOP: Stop as CAC earler
+ * @NL80211_CMD_RADAR_CAC_DONE: Notification sent if a CAC has completed.
+ * @NL80211_CMD_RADAR_FLAGS_CHANGED: Notification sent if channel flags
+ * have changed.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -522,6 +528,11 @@ enum nl80211_commands {
NL80211_CMD_UNPROT_DEAUTHENTICATE,
NL80211_CMD_UNPROT_DISASSOCIATE,
+ NL80211_CMD_RADAR_CAC_START,
+ NL80211_CMD_RADAR_CAC_STOP,
+ NL80211_CMD_RADAR_CAC_DONE,
+ NL80211_CMD_RADAR_FLAGS_CHANGED,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 1e9a052..4f77662 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1200,6 +1200,8 @@ struct cfg80211_pmksa {
* (also see nl80211.h @NL80211_ATTR_WIPHY_ANTENNA_TX).
*
* @get_antenna: Get current antenna configuration from device (tx_ant, rx_ant).
+ *
+ * @radar_cac: Request CAC.
*/
struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy);
@@ -1367,6 +1369,8 @@ struct cfg80211_ops {
int (*set_antenna)(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant);
int (*get_antenna)(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant);
+
+ int (*radar_cac)(struct wiphy *wiphy, int enable);
};
/*
@@ -2720,6 +2724,20 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
void cfg80211_cqm_pktloss_notify(struct net_device *dev,
const u8 *peer, u32 num_packets, gfp_t gfp);
+/**
+ * cfg80211_radar_cac_done - notify userspace that a CAC has been done.
+ * @wiphy: the wireless device to give the hint
+ */
+int cfg80211_radar_cac_done(struct wiphy *wiphy);
+
+/**
+ * cfg80211_radar_flags_changed - notify userspace about channel flag changes
+ * @wiphy: the wireless device to give the hint
+ * @channel: the channel on which flag changes occurred
+ */
+int cfg80211_radar_flags_changed(struct wiphy *wiphy,
+ struct ieee80211_channel *channel);
+
/* Logging, debugging and troubleshooting/diagnostic helpers. */
/* wiphy_printk helpers, similar to dev_printk */
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index a6a2c0b..43f657d 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1999,4 +1999,5 @@ struct cfg80211_ops mac80211_config_ops = {
.mgmt_frame_register = ieee80211_mgmt_frame_register,
.set_antenna = ieee80211_set_antenna,
.get_antenna = ieee80211_get_antenna,
+ .radar_cac = ieee80211_radar_cac,
};
diff --git a/net/mac80211/radar.c b/net/mac80211/radar.c
index afb2ae1..d825e3c 100644
--- a/net/mac80211/radar.c
+++ b/net/mac80211/radar.c
@@ -18,8 +18,10 @@
static void cac_timer(unsigned long data)
{
struct ieee80211_local *local = (void *) data;
+ struct wiphy *wiphy = local->hw.wiphy;
struct ieee80211_radar *radar = &local->radar;
struct ieee80211_channel *chan;
+ int changed = 0;
printk(KERN_INFO "CAC done\n");
@@ -27,9 +29,16 @@ static void cac_timer(unsigned long data)
mutex_lock(&radar->mtx);
if ((chan->flags & IEEE80211_CHAN_RADAR_INTERFERENCE) == 0) {
chan->flags |= IEEE80211_CHAN_RADAR_CLEAR;
+ changed = 1;
}
+ mutex_unlock(&radar->mtx);
+ if (changed)
+ cfg80211_radar_flags_changed(wiphy, chan);
+
+ mutex_lock(&radar->mtx);
radar->cac = 0;
mutex_unlock(&radar->mtx);
+ cfg80211_radar_cac_done(wiphy);
}
int ieee80211_radar_cac(struct wiphy *wiphy, int enable)
@@ -52,9 +61,12 @@ int ieee80211_radar_cac(struct wiphy *wiphy, int enable)
mutex_lock(&radar->mtx);
radar->cac = 0;
mutex_unlock(&radar->mtx);
+ cfg80211_radar_cac_done(wiphy);
return 0;
}
if (enable) {
+ int changed = 0;
+
if ((chan->flags & IEEE80211_CHAN_RADAR_INTERFERENCE))
return -EINVAL;
@@ -65,7 +77,12 @@ int ieee80211_radar_cac(struct wiphy *wiphy, int enable)
if ((chan->flags & IEEE80211_CHAN_RADAR) &&
(chan->flags & IEEE80211_CHAN_RADAR_CLEAR)) {
chan->flags &= ~IEEE80211_CHAN_RADAR_CLEAR;
+ changed = 1;
}
+ mutex_unlock(&radar->mtx);
+ if (changed)
+ cfg80211_radar_flags_changed(wiphy, chan);
+ mutex_lock(&radar->mtx);
radar->cac = 1;
mutex_unlock(&radar->mtx);
mod_timer(&radar->cac_timer, jiffies +
@@ -78,6 +95,7 @@ int ieee80211_radar_cac(struct wiphy *wiphy, int enable)
static void nol_timer(unsigned long data)
{
struct ieee80211_local *local = (void *) data;
+ struct wiphy *wiphy = local->hw.wiphy;
struct ieee80211_radar *radar = &local->radar;
struct ieee80211_radar_nol_list *nol, *tmp;
@@ -93,6 +111,7 @@ static void nol_timer(unsigned long data)
list_del(&nol->list);
mutex_unlock(&radar->mtx);
kfree(nol);
+ cfg80211_radar_flags_changed(wiphy, chan);
}
}
@@ -103,6 +122,7 @@ int ieee80211_radar_interference(struct ieee80211_hw *hw,
struct ieee80211_channel *chan)
{
struct ieee80211_local *local = hw_to_local(hw);
+ struct wiphy *wiphy = local->hw.wiphy;
struct ieee80211_radar *radar = &local->radar;
struct ieee80211_radar_nol_list *nol, *tmp;
@@ -131,6 +151,7 @@ int ieee80211_radar_interference(struct ieee80211_hw *hw,
chan->flags |= IEEE80211_CHAN_RADAR_INTERFERENCE;
list_add_tail(&nol->list, &radar->nol_list);
mutex_unlock(&radar->mtx);
+ cfg80211_radar_flags_changed(wiphy, chan);
return 0;
}
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 0524423..2f43b6e 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -4729,6 +4729,26 @@ out:
return err;
}
+static int nl80211_radar_start_cac(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+
+ if (!rdev->ops->radar_cac)
+ return -EOPNOTSUPP;
+
+ return rdev->ops->radar_cac(&rdev->wiphy, 1);
+}
+
+static int nl80211_radar_stop_cac(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+
+ if (!rdev->ops->radar_cac)
+ return -EOPNOTSUPP;
+
+ return rdev->ops->radar_cac(&rdev->wiphy, 0);
+}
+
static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
@@ -5271,6 +5291,22 @@ static struct genl_ops nl80211_ops[] = {
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
NL80211_FLAG_NEED_RTNL,
},
+ {
+ .cmd = NL80211_CMD_RADAR_CAC_START,
+ .doit = nl80211_radar_start_cac,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV |
+ NL80211_FLAG_NEED_RTNL,
+ },
+ {
+ .cmd = NL80211_CMD_RADAR_CAC_STOP,
+ .doit = nl80211_radar_stop_cac,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV |
+ NL80211_FLAG_NEED_RTNL,
+ },
};
static struct genl_multicast_group nl80211_mlme_mcgrp = {
@@ -6128,6 +6164,74 @@ nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
nlmsg_free(msg);
}
+void nl80211_radar_cac_done(struct cfg80211_registered_device *rdev)
+{
+ struct sk_buff *msg;
+ void *hdr;
+
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!msg)
+ return;
+
+ hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_RADAR_CAC_DONE);
+ if (!hdr) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+
+ if (genlmsg_end(msg, hdr) < 0) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+ nl80211_mlme_mcgrp.id, GFP_KERNEL);
+ return;
+
+ nla_put_failure:
+ genlmsg_cancel(msg, hdr);
+ nlmsg_free(msg);
+}
+
+void nl80211_radar_flags_changed(struct cfg80211_registered_device *rdev,
+ struct ieee80211_channel *chan)
+{
+ struct sk_buff *msg;
+ void *hdr;
+
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!msg)
+ return;
+
+ hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_RADAR_FLAGS_CHANGED);
+ if (!hdr) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+ NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_FREQ, chan->center_freq);
+ if ((chan->flags & IEEE80211_CHAN_RADAR_CLEAR))
+ NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_RADAR_CLEAR);
+ if ((chan->flags & IEEE80211_CHAN_RADAR_INTERFERENCE))
+ NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_RADAR_INTERFERENCE);
+
+ if (genlmsg_end(msg, hdr) < 0) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+ nl80211_mlme_mcgrp.id, GFP_KERNEL);
+ return;
+
+ nla_put_failure:
+ genlmsg_cancel(msg, hdr);
+ nlmsg_free(msg);
+}
+
static int nl80211_netlink_notify(struct notifier_block * nb,
unsigned long state,
void *_notify)
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index e3f7fa8..e7f84d8 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -98,4 +98,8 @@ nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
struct net_device *netdev, const u8 *peer,
u32 num_packets, gfp_t gfp);
+void nl80211_radar_cac_done(struct cfg80211_registered_device *rdev);
+void nl80211_radar_flags_changed(struct cfg80211_registered_device *rdev,
+ struct ieee80211_channel *chan);
+
#endif /* __NET_WIRELESS_NL80211_H */
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 7620ae2..3c87c2f 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -9,6 +9,7 @@
#include <net/cfg80211.h>
#include <net/ip.h>
#include "core.h"
+#include "nl80211.h"
struct ieee80211_rate *
ieee80211_get_response_rate(struct ieee80211_supported_band *sband,
@@ -885,3 +886,22 @@ u16 cfg80211_calculate_bitrate(struct rate_info *rate)
/* do NOT round down here */
return (bitrate + 50000) / 100000;
}
+
+int cfg80211_radar_cac_done(struct wiphy *wiphy)
+{
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+ nl80211_radar_cac_done(rdev);
+ return 0;
+}
+EXPORT_SYMBOL(cfg80211_radar_cac_done);
+
+int cfg80211_radar_flags_changed(struct wiphy *wiphy,
+ struct ieee80211_channel *chan)
+{
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+ nl80211_radar_flags_changed(rdev, chan);
+ return 0;
+}
+EXPORT_SYMBOL(cfg80211_radar_flags_changed);
--
1.5.6.5
On Tue, 2011-01-18 at 13:01 +0100, Bernhard Schmidt wrote:
> On Tuesday, January 18, 2011 11:43:46 Johannes Berg wrote:
> > On Mon, 2011-01-17 at 11:05 +0100, Bernhard Schmidt wrote:
> > > NOL is a list of channels on which radar interference has been
> > > detected. Such channels are not allowed to be used for a certain
> > > amount of time.
> >
> > I don't think this should be implemented in mac80211.
>
> In cfg80211 then? I'd really prefer to keep all flag-handling together
> instead of splitting it up between mac80211/userspace.
Yeah, cfg80211 sounds much saner, with APIs there etc.
johannes
On Mon, 2011-01-17 at 09:31 +0100, Bernhard Schmidt wrote:
> Before a radar channel can be used, a full CAC has be done, the
> IEEE80211_CHAN_RADAR_CLEAR flags indicates that this has been done. If either
> during CAC or in-service monitoring interference is detected, the channel is
> added to NOL and marked with IEEE80211_CHAN_RADAR_INTERFERENCE.
I'm not sure about this -- shouldn't that be global information? If one
device in the system records a radar on the channel, it surely applies
to other devices as well, even if they are hot-plugged after the radar
was found?
johannes
On Tuesday, January 18, 2011 11:43:46 Johannes Berg wrote:
> On Mon, 2011-01-17 at 11:05 +0100, Bernhard Schmidt wrote:
> > NOL is a list of channels on which radar interference has been
> > detected. Such channels are not allowed to be used for a certain
> > amount of time.
>
> I don't think this should be implemented in mac80211.
In cfg80211 then? I'd really prefer to keep all flag-handling together
instead of splitting it up between mac80211/userspace.
--
Best regards,
Dipl.-Inf. (FH) Bernhard Schmidt (software development)
saxnet GmbH, Willy-Brandt-Ring 1, 08606 Oelsnitz
Tel. +49 (0) 3741 300 6. 100 - Fax +49 (0) 3741 300 6. 101
managing director: Steffen Dreise - county court Chemnitz - HRB 23017
http://www.saxnet.de
I don't get this at all. How's the driver supported to report anything?!
johannes