Hi,
This is second version of state/userspace handling, the main diff to v1
is that state are no global and no per wiphy.
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.
I don't include the hostapd patches this time, because there are no
real changes compared to the last series.
If you want to test this code on hardware which has no radar detection
support (well, currently there is none with support), skip patch 3/9
and use the ieee80211/radar/bang debugfs file. Writing a frequency
there will simulate interference on the channel.
--
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
When switching to channels requiring radar detection, enable it
if the current mode is one which requires beaconing. In all other
cases the radar detection is disabled.
Note, drivers which do not support radar detection are not allowed
to switch to those channels.
Signed-off-by: Bernhard Schmidt <[email protected]>
---
include/net/mac80211.h | 4 ++++
net/mac80211/cfg.c | 15 +++++++++++++++
net/mac80211/driver-ops.h | 14 ++++++++++++++
net/mac80211/driver-trace.h | 21 +++++++++++++++++++++
4 files changed, 54 insertions(+), 0 deletions(-)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 2b072fa..495b0c5 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1804,6 +1804,8 @@ enum ieee80211_ampdu_mlme_action {
* return value is 1, then the @remain_on_channel will be used with a
* regular transmission (if supported.)
* @offchannel_tx_cancel_wait: cancel wait associated with offchannel TX
+ *
+ * @radar_detection: Enable or disable radar detection on current channel.
*/
struct ieee80211_ops {
void (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
@@ -1888,6 +1890,8 @@ struct ieee80211_ops {
enum nl80211_channel_type channel_type,
unsigned int wait);
int (*offchannel_tx_cancel_wait)(struct ieee80211_hw *hw);
+
+ int (*radar_detection)(struct ieee80211_hw *hw, int enable);
};
/**
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 4a07e67..e50ecaa 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1245,6 +1245,21 @@ static int ieee80211_set_channel(struct wiphy *wiphy,
old_vif_oper_type = sdata->vif.bss_conf.channel_type;
old_oper_type = local->_oper_channel_type;
+ if (sdata && (sdata->vif.type == NL80211_IFTYPE_ADHOC ||
+ sdata->vif.type == NL80211_IFTYPE_AP ||
+ sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
+ sdata->vif.type == NL80211_IFTYPE_MESH_POINT ||
+ sdata->vif.type == NL80211_IFTYPE_P2P_GO) &&
+ (chan->flags & IEEE80211_CHAN_RADAR)) {
+ /*
+ * Do not allow switching to channels requiring radar
+ * detection if hardware doesn't support detection.
+ */
+ if (drv_radar_detection(local, true))
+ return -EINVAL;
+ } else
+ drv_radar_detection(local, false);
+
if (!ieee80211_set_channel_type(local, sdata, channel_type))
return -EBUSY;
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 3729296..a2bef0c 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -526,4 +526,18 @@ static inline int drv_offchannel_tx_cancel_wait(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 520fe24..aa2c833 100644
--- a/net/mac80211/driver-trace.h
+++ b/net/mac80211/driver-trace.h
@@ -1150,6 +1150,27 @@ DEFINE_EVENT(local_only_evt, api_remain_on_channel_expired,
TP_ARGS(local)
);
+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)
--
1.7.2.3
Enable drivers to report interference. Same functionality is
available through debugfs for testing purposes.
Signed-off-by: Bernhard Schmidt <[email protected]>
---
include/net/cfg80211.h | 6 +++++
net/wireless/core.c | 2 +
net/wireless/radar.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 59 insertions(+), 0 deletions(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 5636c0a..909bae3 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -2723,6 +2723,12 @@ 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_interference - report radar interference.
+ * @freq: the affected channel frequency
+ */
+int cfg80211_radar_interference(u16 freq);
+
/* Logging, debugging and troubleshooting/diagnostic helpers. */
/* wiphy_printk helpers, similar to dev_printk */
diff --git a/net/wireless/core.c b/net/wireless/core.c
index eb517a2..e14fab4 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -491,6 +491,8 @@ int wiphy_register(struct wiphy *wiphy)
/* set up regulatory info */
wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE);
+ radar_set_interference_flag(rdev);
+
list_add_rcu(&rdev->list, &cfg80211_rdev_list);
cfg80211_rdev_list_generation++;
diff --git a/net/wireless/radar.c b/net/wireless/radar.c
index d8911d3..88080de 100644
--- a/net/wireless/radar.c
+++ b/net/wireless/radar.c
@@ -284,6 +284,21 @@ static void radar_nol(struct work_struct *work)
}
static DECLARE_WORK(nol_work, radar_nol);
+int cfg80211_radar_interference(u16 freq)
+{
+ int error;
+
+ error = nol_add_chan(freq);
+ if (error)
+ return error;
+ mod_timer(&radar.timer, jiffies + msecs_to_jiffies(100));
+ error = cc_add_chan(freq);
+ if (error)
+ return error;
+ return 0;
+}
+EXPORT_SYMBOL(cfg80211_radar_interference);
+
void radar_set_interference_flag(struct cfg80211_registered_device *rdev)
{
struct radar_nol_list *nol;
@@ -463,6 +478,41 @@ static const struct file_operations nol_ops = {
.llseek = default_llseek,
};
+static ssize_t radar_debugfs_bang(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct cfg80211_registered_device *rdev;
+ struct ieee80211_channel *chan = NULL;
+ unsigned long long freq;
+ char buf[100];
+ size_t len;
+
+ len = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len))
+ return -EFAULT;
+ buf[len] = '\0';
+
+ freq = simple_strtoul(buf, NULL, 0);
+
+ list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
+ chan = ieee80211_get_channel(&rdev->wiphy, freq);
+ if (chan != NULL)
+ break;
+ }
+
+ if (chan != NULL)
+ cfg80211_radar_interference(freq);
+
+ return count;
+}
+
+static const struct file_operations bang_ops = {
+ .write = radar_debugfs_bang,
+ .open = radar_open_file_generic,
+ .llseek = default_llseek,
+};
+
static struct dentry *radar_debugfs_dir;
#define DEBUGFS_ADD(name) \
@@ -474,6 +524,7 @@ void radar_debugfs_add(struct dentry *ieee80211_debugfs_dir)
radar_debugfs_dir = debugfs_create_dir("radar", ieee80211_debugfs_dir);
DEBUGFS_ADD(cac);
DEBUGFS_ADD(nol);
+ DEBUGFS_ADD(bang);
}
void radar_debugfs_remove()
--
1.7.2.3
I'm really not sure about this.. is there another/better way to
access the current channel last set on a wiphy?
Signed-off-by: Bernhard Schmidt <[email protected]>
---
include/net/cfg80211.h | 2 ++
net/mac80211/cfg.c | 8 ++++++++
net/wireless/chan.c | 2 +-
3 files changed, 11 insertions(+), 1 deletions(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 679a049..8300699 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1121,6 +1121,7 @@ struct cfg80211_pmksa {
* doesn't verify much. Note, however, that the passed netdev may be
* %NULL as well if the user requested changing the channel for the
* device itself, or for a monitor interface.
+ * @get_channel: Get current channel for a given wireless interface.
*
* @scan: Request to do a scan. If returning zero, the scan request is given
* the driver, and will be valid until passed to cfg80211_scan_done().
@@ -1276,6 +1277,7 @@ struct cfg80211_ops {
int (*set_channel)(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type);
+ struct ieee80211_channel *(*get_channel)(struct wiphy *wiphy);
int (*scan)(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_scan_request *request);
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 8b436c7..2a05b31 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1257,6 +1257,13 @@ static int ieee80211_set_channel(struct wiphy *wiphy,
return 0;
}
+static struct ieee80211_channel *ieee80211_get_oper_channel(struct wiphy *wiphy)
+{
+ struct ieee80211_local *local = wiphy_priv(wiphy);
+
+ return local->oper_channel;
+}
+
#ifdef CONFIG_PM
static int ieee80211_suspend(struct wiphy *wiphy)
{
@@ -2027,6 +2034,7 @@ struct cfg80211_ops mac80211_config_ops = {
.change_bss = ieee80211_change_bss,
.set_txq_params = ieee80211_set_txq_params,
.set_channel = ieee80211_set_channel,
+ .get_channel = ieee80211_get_oper_channel,
.suspend = ieee80211_suspend,
.resume = ieee80211_resume,
.scan = ieee80211_scan,
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 17cd0c0..4e63e67 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -93,7 +93,7 @@ int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
return -ENETDOWN;
}
- if (!rdev->ops->set_channel)
+ if (!rdev->ops->set_channel || !rdev->ops->get_channel)
return -EOPNOTSUPP;
chan = rdev_freq_to_chan(rdev, freq, channel_type);
--
1.7.2.3
Every channel on which interference is detected has to be added
to a list which indicates that those channels are not to be used.
A channel has to stay for at least the no operation period (NOP)
on that list before it will again become available channel.
Signed-off-by: Bernhard Schmidt <[email protected]>
---
net/wireless/radar.c | 140 +++++++++++++++++++++++++++++++++++++++++++++++++-
net/wireless/radar.h | 8 +++
2 files changed, 147 insertions(+), 1 deletions(-)
diff --git a/net/wireless/radar.c b/net/wireless/radar.c
index 361070c..5a1ceab 100644
--- a/net/wireless/radar.c
+++ b/net/wireless/radar.c
@@ -10,6 +10,7 @@
#include <linux/ieee80211.h>
#include <net/cfg80211.h>
+#include "core.h"
#include "radar.h"
#include "nl80211.h"
@@ -128,6 +129,93 @@ static void radar_cac(struct work_struct *work)
}
static DECLARE_WORK(cac_work, radar_cac);
+static void update_all_interference_flags(u16 freq, bool set)
+{
+ struct cfg80211_registered_device *rdev;
+ struct ieee80211_channel *chan;
+
+ list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
+ chan = ieee80211_get_channel(&rdev->wiphy, freq);
+ if (chan == NULL)
+ continue;
+ chan->flags &= ~IEEE80211_CHAN_RADAR_INTERFERENCE;
+ if (set)
+ chan->flags |= IEEE80211_CHAN_RADAR_INTERFERENCE;
+ }
+}
+
+static int nol_add_chan(u16 freq)
+{
+ struct radar_nol_list *nol;
+
+ printk(KERN_INFO "DFS: add freq %u MHz to the NOL list\n", freq);
+
+ list_for_each_entry(nol, &radar.nol_list, list) {
+ if (nol->freq == freq) {
+ mutex_lock(&radar.lock);
+ nol->timeout = jiffies + msecs_to_jiffies(
+ radar.params->nol_period * 1000);
+ mutex_unlock(&radar.lock);
+ return 0;
+ }
+ }
+
+ nol = kmalloc(sizeof(struct radar_nol_list), GFP_KERNEL);
+ if (nol == NULL)
+ return -ENOMEM;
+
+ mutex_lock(&radar.lock);
+ nol->freq = freq;
+ nol->timeout = jiffies +
+ msecs_to_jiffies(radar.params->nol_period * 1000);
+ list_add_tail(&nol->list, &radar.nol_list);
+ update_all_interference_flags(freq, true);
+ mutex_unlock(&radar.lock);
+ return 0;
+}
+
+static void radar_nol(struct work_struct *work)
+{
+ struct radar_nol_list *nol, *tmp;
+
+ mutex_lock(&radar.lock);
+ list_for_each_entry_safe(nol, tmp, &radar.nol_list, list) {
+ if (!time_is_before_jiffies(nol->timeout))
+ continue;
+
+ printk(KERN_INFO "DFS: remove freq %u from the NOL list\n",
+ nol->freq);
+
+ update_all_interference_flags(nol->freq, false);
+ list_del(&nol->list);
+ mutex_unlock(&radar.lock);
+
+ kfree(nol);
+ return;
+ }
+ mutex_unlock(&radar.lock);
+}
+static DECLARE_WORK(nol_work, radar_nol);
+
+void radar_set_interference_flag(struct cfg80211_registered_device *rdev)
+{
+ struct radar_nol_list *nol;
+
+ if (list_empty(&radar.nol_list))
+ return;
+
+ mutex_lock(&radar.lock);
+ list_for_each_entry(nol, &radar.nol_list, list) {
+ struct ieee80211_channel *chan;
+
+ chan = ieee80211_get_channel(&rdev->wiphy, nol->freq);
+ if (chan == NULL)
+ continue;
+ chan->flags |= IEEE80211_CHAN_RADAR_INTERFERENCE;
+ }
+ mutex_unlock(&radar.lock);
+}
+
void radar_update_params(u8 dfs_region)
{
mutex_lock(&radar.lock);
@@ -149,8 +237,11 @@ static void radar_timer(unsigned long data)
{
if (!list_empty(&radar.cac_list))
schedule_work(&cac_work);
+ if (!list_empty(&radar.nol_list))
+ schedule_work(&nol_work);
- if (!list_empty(&radar.cac_list))
+ if (!list_empty(&radar.cac_list) ||
+ !list_empty(&radar.nol_list))
mod_timer(&radar.timer, jiffies + msecs_to_jiffies(100));
}
@@ -164,12 +255,14 @@ void radar_init(void)
mutex_init(&radar.lock);
INIT_LIST_HEAD(&radar.cac_list);
+ INIT_LIST_HEAD(&radar.nol_list);
setup_timer(&radar.timer, radar_timer, (unsigned long)0);
}
void radar_deinit(void)
{
struct radar_cac_list *cac, *cactmp;
+ struct radar_nol_list *nol, *noltmp;
del_timer_sync(&radar.timer);
mutex_lock(&radar.lock);
@@ -177,6 +270,10 @@ void radar_deinit(void)
list_del(&cac->list);
kfree(cac);
}
+ list_for_each_entry_safe(nol, noltmp, &radar.nol_list, list) {
+ list_del(&nol->list);
+ kfree(nol);
+ }
mutex_unlock(&radar.lock);
mutex_destroy(&radar.lock);
}
@@ -230,6 +327,46 @@ static const struct file_operations cac_ops = {
.llseek = default_llseek,
};
+static ssize_t radar_debugfs_nol_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct radar_nol_list *nol;
+ char *buf;
+ unsigned int offset = 0, buf_size = PAGE_SIZE, r;
+
+ buf = kzalloc(buf_size, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ if (!list_empty(&radar.nol_list)) {
+ mutex_lock(&radar.lock);
+ list_for_each_entry(nol, &radar.nol_list, list) {
+ int remaining;
+
+ remaining = jiffies_to_msecs(nol->timeout - jiffies);
+ remaining /= 1000;
+ offset += snprintf(buf + offset,
+ buf_size - offset,
+ "%u MHz: %u secs remaining\n",
+ nol->freq, remaining);
+ }
+ mutex_unlock(&radar.lock);
+ }
+
+ r = simple_read_from_buffer(user_buf, count, ppos, buf, offset);
+
+ kfree(buf);
+
+ return r;
+}
+
+static const struct file_operations nol_ops = {
+ .read = radar_debugfs_nol_read,
+ .open = radar_open_file_generic,
+ .llseek = default_llseek,
+};
+
static struct dentry *radar_debugfs_dir;
#define DEBUGFS_ADD(name) \
@@ -240,6 +377,7 @@ void radar_debugfs_add(struct dentry *ieee80211_debugfs_dir)
{
radar_debugfs_dir = debugfs_create_dir("radar", ieee80211_debugfs_dir);
DEBUGFS_ADD(cac);
+ DEBUGFS_ADD(nol);
}
void radar_debugfs_remove()
diff --git a/net/wireless/radar.h b/net/wireless/radar.h
index 89cc73d..4ec1aae 100644
--- a/net/wireless/radar.h
+++ b/net/wireless/radar.h
@@ -33,16 +33,24 @@ struct radar_cac_list {
struct list_head list;
};
+struct radar_nol_list {
+ u16 freq;
+ unsigned long timeout;
+ struct list_head list;
+};
+
struct radar {
struct radar_parameters *params;
struct mutex lock;
struct timer_list timer;
struct list_head cac_list;
+ struct list_head nol_list;
};
bool radar_cac_in_progress(struct cfg80211_registered_device *rdev);
int radar_cac_start(struct cfg80211_registered_device *rdev);
int radar_cac_stop(struct cfg80211_registered_device *rdev);
+void radar_set_interference_flag(struct cfg80211_registered_device *rdev);
void radar_update_params(u8 dfs_region);
void radar_init(void);
void radar_deinit(void);
--
1.7.2.3
DFS introduces 2 new flags a channel requiring radar detection
might take. The interference flag indicates that interference was
detected either during CAC or in-service monitoring and the
channel is not to be used for the NOP period. The clear flag
indicates that during a full CAC no interference was detected and
it is allowed to open a BSS on that channel. The case were both
flags are set is used to indicate that interference has been
detected and we are in progress of closing on that channel.
Signed-off-by: Bernhard Schmidt <[email protected]>
---
include/linux/nl80211.h | 6 ++++++
include/net/cfg80211.h | 18 ++++++++++++------
net/mac80211/cfg.c | 6 ++++++
net/mac80211/tx.c | 6 ++++--
net/wireless/nl80211.c | 4 ++++
5 files changed, 32 insertions(+), 8 deletions(-)
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index e3c9ec7..2282f56 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 8300699..5636c0a 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/mac80211/cfg.c b/net/mac80211/cfg.c
index 2a05b31..4a07e67 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -436,11 +436,17 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
{
struct beacon_data *new, *old;
int new_head_len, new_tail_len;
+ u32 flags;
int size;
int err = -EINVAL;
old = sdata->u.ap.beacon;
+ flags = sdata->local->hw.conf.channel->flags;
+ if ((flags & IEEE80211_CHAN_RADAR) &&
+ !(flags & IEEE80211_CHAN_RADAR_CLEAR))
+ return -EINVAL;
+
/* head must not be zero-length */
if (params->head && !params->head_len)
return -EINVAL;
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 081dcaf..c8b5e05 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1629,8 +1629,10 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
* radar detection by itself. We can do that later by adding a
* monitor flag interfaces used for AP support.
*/
- if ((chan->flags & (IEEE80211_CHAN_NO_IBSS | IEEE80211_CHAN_RADAR |
- IEEE80211_CHAN_PASSIVE_SCAN)))
+ if ((chan->flags & (IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_PASSIVE_SCAN)) ||
+ ((chan->flags & IEEE80211_CHAN_RADAR) &&
+ !(chan->flags & IEEE80211_CHAN_RADAR_CLEAR)))
goto fail;
/* check for not even having the fixed radiotap header part */
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index f4facba..52b76e7 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.7.2.3
Signed-off-by: Bernhard Schmidt <[email protected]>
---
net/wireless/Makefile | 2 +-
net/wireless/core.c | 6 +++
net/wireless/radar.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++
net/wireless/radar.h | 48 +++++++++++++++++++++++++++
net/wireless/reg.c | 2 +
5 files changed, 143 insertions(+), 1 deletions(-)
create mode 100644 net/wireless/radar.c
create mode 100644 net/wireless/radar.h
diff --git a/net/wireless/Makefile b/net/wireless/Makefile
index 55a28ab..2d29d06 100644
--- a/net/wireless/Makefile
+++ b/net/wireless/Makefile
@@ -10,7 +10,7 @@ obj-$(CONFIG_WEXT_SPY) += wext-spy.o
obj-$(CONFIG_WEXT_PRIV) += wext-priv.o
cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o
-cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o
+cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o radar.o
cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o
cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o
cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o
diff --git a/net/wireless/core.c b/net/wireless/core.c
index fe01de2..55984ca 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -26,6 +26,7 @@
#include "debugfs.h"
#include "wext-compat.h"
#include "ethtool.h"
+#include "radar.h"
/* name for sysfs, %d is appended */
#define PHY_NAME "phy"
@@ -912,6 +913,9 @@ static int __init cfg80211_init(void)
if (err)
goto out_fail_reg;
+ radar_init();
+ radar_debugfs_add(ieee80211_debugfs_dir);
+
cfg80211_wq = create_singlethread_workqueue("cfg80211");
if (!cfg80211_wq)
goto out_fail_wq;
@@ -935,7 +939,9 @@ subsys_initcall(cfg80211_init);
static void __exit cfg80211_exit(void)
{
+ radar_debugfs_remove();
debugfs_remove(ieee80211_debugfs_dir);
+ radar_deinit();
nl80211_exit();
unregister_netdevice_notifier(&cfg80211_netdev_notifier);
wiphy_sysfs_exit();
diff --git a/net/wireless/radar.c b/net/wireless/radar.c
new file mode 100644
index 0000000..779fd8c
--- /dev/null
+++ b/net/wireless/radar.c
@@ -0,0 +1,86 @@
+/*
+ * 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 <linux/ieee80211.h>
+#include <net/cfg80211.h>
+#include "radar.h"
+
+static struct radar_parameters regdomain_params[] = {
+ { 60, 1800, 1000 }, /* FCC, correct? */
+ { 60, 1800, 1000 }, /* ETSI */
+ { 60, 1800, 1000 }, /* JP, correct? */
+};
+
+static struct radar radar;
+
+void radar_update_params(u8 dfs_region)
+{
+ mutex_lock(&radar.lock);
+ switch (dfs_region) {
+ 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;
+ }
+ mutex_unlock(&radar.lock);
+}
+
+static void radar_timer(unsigned long data)
+{
+}
+
+void radar_init(void)
+{
+ /*
+ * NB: use FCC by default, will be updated later once regulatory
+ * information are available.
+ */
+ radar.params = ®domain_params[0];
+
+ mutex_init(&radar.lock);
+ setup_timer(&radar.timer, radar_timer, (unsigned long)0);
+}
+
+void radar_deinit(void)
+{
+ del_timer_sync(&radar.timer);
+ mutex_destroy(&radar.lock);
+}
+
+#ifdef CONFIG_CFG80211_DEBUGFS
+
+static int radar_open_file_generic(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static struct dentry *radar_debugfs_dir;
+
+#define DEBUGFS_ADD(name) \
+ debugfs_create_file(#name, S_IRUGO, radar_debugfs_dir, NULL, \
+ &name## _ops);
+
+void radar_debugfs_add(struct dentry *ieee80211_debugfs_dir)
+{
+ radar_debugfs_dir = debugfs_create_dir("radar", ieee80211_debugfs_dir);
+}
+
+void radar_debugfs_remove()
+{
+ debugfs_remove_recursive(radar_debugfs_dir);
+}
+
+#endif
diff --git a/net/wireless/radar.h b/net/wireless/radar.h
new file mode 100644
index 0000000..053ceb6
--- /dev/null
+++ b/net/wireless/radar.h
@@ -0,0 +1,48 @@
+/*
+ * 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 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;
+
+ /*
+ * Time in ms after which a channel must be closed (=no transmission)
+ * when interference has been detected.
+ */
+ int close_time;
+};
+
+struct radar {
+ struct radar_parameters *params;
+ struct mutex lock;
+ struct timer_list timer;
+};
+
+void radar_update_params(u8 dfs_region);
+void radar_init(void);
+void radar_deinit(void);
+
+#ifdef CONFIG_CFG80211_DEBUGFS
+void radar_debugfs_add(struct dentry *ieee80211_debugfs_dir);
+void radar_debugfs_remove(void);
+#else
+static inline void radar_debugfs_add(struct dentry *ieee80211_debugfs_dir) {}
+static inline void radar_debugfs_remove() {}
+#endif
+
+#endif
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 1f1312f..ca76b8d 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -47,6 +47,7 @@
#include "reg.h"
#include "regdb.h"
#include "nl80211.h"
+#include "radar.h"
#ifdef CONFIG_CFG80211_REG_DEBUG
#define REG_DBG_PRINT(format, args...) \
@@ -1140,6 +1141,7 @@ void wiphy_update_regulatory(struct wiphy *wiphy,
out:
reg_process_beacons(wiphy);
reg_process_ht_flags(wiphy);
+ radar_update_params(last_request->dfs_region);
if (wiphy->reg_notifier)
wiphy->reg_notifier(wiphy, last_request);
}
--
1.7.2.3
DFS requires that if interference has been detected, transmission on
a channel is stopped latest after the channel closing time. During
this period it must still be possible to at least send beacons, e.g.
for CSAs.
Signed-off-by: Bernhard Schmidt <[email protected]>
---
net/wireless/radar.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++
net/wireless/radar.h | 7 ++++
2 files changed, 99 insertions(+), 0 deletions(-)
diff --git a/net/wireless/radar.c b/net/wireless/radar.c
index 5a1ceab..df2d03b 100644
--- a/net/wireless/radar.c
+++ b/net/wireless/radar.c
@@ -129,6 +129,89 @@ static void radar_cac(struct work_struct *work)
}
static DECLARE_WORK(cac_work, radar_cac);
+static int cc_add_chan(u16 freq)
+{
+ struct radar_cc_list *cc;
+
+ printk(KERN_INFO "DFS: enable CC for freq %u MHz\n", freq);
+
+ mutex_lock(&radar.lock);
+ list_for_each_entry(cc, &radar.cc_list, list) {
+ if (cc->freq == freq) {
+ mutex_unlock(&radar.lock);
+ return 0;
+ }
+ }
+ mutex_unlock(&radar.lock);
+
+ cc = kmalloc(sizeof(struct radar_cc_list), GFP_KERNEL);
+ if (cc == NULL)
+ return -ENOMEM;
+
+ mutex_lock(&radar.lock);
+ cc->freq = freq;
+ cc->timeout = jiffies + msecs_to_jiffies(radar.params->close_time);
+ list_add_tail(&cc->list, &radar.cc_list);
+ mutex_unlock(&radar.lock);
+ return 0;
+}
+
+static void close_channel(u16 freq)
+{
+ struct cfg80211_registered_device *rdev;
+
+ list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
+ struct wireless_dev *wdev;
+ struct ieee80211_channel *chan, *c;
+
+ chan = ieee80211_get_channel(&rdev->wiphy, freq);
+ if (chan == NULL)
+ continue;
+ chan->flags &= ~IEEE80211_CHAN_RADAR_CLEAR;
+
+ c = rdev->ops->get_channel(&rdev->wiphy);
+ if (c->center_freq != chan->center_freq)
+ continue;
+
+ list_for_each_entry(wdev, &rdev->netdev_list, list) {
+ if (wdev->iftype == NL80211_IFTYPE_ADHOC ||
+ wdev->iftype == NL80211_IFTYPE_AP ||
+ wdev->iftype == NL80211_IFTYPE_AP_VLAN ||
+ wdev->iftype == NL80211_IFTYPE_MESH_POINT ||
+ wdev->iftype == NL80211_IFTYPE_P2P_GO)
+ rdev->ops->del_beacon(&rdev->wiphy,
+ wdev->netdev);
+ }
+ }
+}
+
+static void radar_cc(struct work_struct *work)
+{
+ struct radar_cc_list *cc, *tmp;
+
+ mutex_lock(&radar.lock);
+ list_for_each_entry_safe(cc, tmp, &radar.cc_list, list) {
+ unsigned long timeout = cc->timeout;
+
+ /* the next interation might already be to late. */
+ cc->timeout -= msecs_to_jiffies(100);
+
+ if (time_is_before_jiffies(timeout)) {
+ printk(KERN_INFO "DFS: transmission close time "
+ "on freq %u MHz reached\n", cc->freq);
+
+ close_channel(cc->freq);
+ list_del(&cc->list);
+ mutex_unlock(&radar.lock);
+
+ kfree(cc);
+ return;
+ }
+ }
+ mutex_unlock(&radar.lock);
+}
+static DECLARE_WORK(cc_work, radar_cc);
+
static void update_all_interference_flags(u16 freq, bool set)
{
struct cfg80211_registered_device *rdev;
@@ -237,10 +320,13 @@ static void radar_timer(unsigned long data)
{
if (!list_empty(&radar.cac_list))
schedule_work(&cac_work);
+ if (!list_empty(&radar.cc_list))
+ schedule_work(&cc_work);
if (!list_empty(&radar.nol_list))
schedule_work(&nol_work);
if (!list_empty(&radar.cac_list) ||
+ !list_empty(&radar.cc_list) ||
!list_empty(&radar.nol_list))
mod_timer(&radar.timer, jiffies + msecs_to_jiffies(100));
}
@@ -255,6 +341,7 @@ void radar_init(void)
mutex_init(&radar.lock);
INIT_LIST_HEAD(&radar.cac_list);
+ INIT_LIST_HEAD(&radar.cc_list);
INIT_LIST_HEAD(&radar.nol_list);
setup_timer(&radar.timer, radar_timer, (unsigned long)0);
}
@@ -262,6 +349,7 @@ void radar_init(void)
void radar_deinit(void)
{
struct radar_cac_list *cac, *cactmp;
+ struct radar_cc_list *cc, *cctmp;
struct radar_nol_list *nol, *noltmp;
del_timer_sync(&radar.timer);
@@ -270,6 +358,10 @@ void radar_deinit(void)
list_del(&cac->list);
kfree(cac);
}
+ list_for_each_entry_safe(cc, cctmp, &radar.cac_list, list) {
+ list_del(&cc->list);
+ kfree(cc);
+ }
list_for_each_entry_safe(nol, noltmp, &radar.nol_list, list) {
list_del(&nol->list);
kfree(nol);
diff --git a/net/wireless/radar.h b/net/wireless/radar.h
index 4ec1aae..23214dd 100644
--- a/net/wireless/radar.h
+++ b/net/wireless/radar.h
@@ -33,6 +33,12 @@ struct radar_cac_list {
struct list_head list;
};
+struct radar_cc_list {
+ u16 freq;
+ unsigned long timeout;
+ struct list_head list;
+};
+
struct radar_nol_list {
u16 freq;
unsigned long timeout;
@@ -44,6 +50,7 @@ struct radar {
struct mutex lock;
struct timer_list timer;
struct list_head cac_list;
+ struct list_head cc_list;
struct list_head nol_list;
};
--
1.7.2.3
Signed-off-by: Bernhard Schmidt <[email protected]>
---
include/linux/nl80211.h | 3 ++
net/wireless/nl80211.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++
net/wireless/nl80211.h | 2 +
net/wireless/radar.c | 4 +++
4 files changed, 60 insertions(+), 0 deletions(-)
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index e14b2dd..1355865 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -413,6 +413,8 @@
* @NL80211_CMD_RADAR_CAC_START: Request a CAC.
* @NL80211_CMD_RADAR_CAC_STOP: Stop a CAC early.
* @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
@@ -529,6 +531,7 @@ enum nl80211_commands {
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 */
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 20a24f4..4d6d2ad 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -6205,6 +6205,57 @@ void nl80211_radar_cac_done(struct cfg80211_registered_device *rdev)
rcu_read_unlock();
}
+static void radar_flags_changed_wdev(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev,
+ 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_IFINDEX, wdev->netdev->ifindex);
+ 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);
+}
+
+void nl80211_radar_flags_changed(struct cfg80211_registered_device *rdev,
+ struct ieee80211_channel *chan)
+{
+ struct wireless_dev *wdev;
+
+ rcu_read_lock();
+
+ list_for_each_entry_rcu(wdev, &rdev->netdev_list, list)
+ radar_flags_changed_wdev(rdev, wdev, chan);
+
+ rcu_read_unlock();
+}
+
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 aa3c926..e7f84d8 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -99,5 +99,7 @@ nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
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/radar.c b/net/wireless/radar.c
index df2d03b..d8911d3 100644
--- a/net/wireless/radar.c
+++ b/net/wireless/radar.c
@@ -62,6 +62,7 @@ int radar_cac_start(struct cfg80211_registered_device *rdev)
}
chan->flags &= ~IEEE80211_CHAN_RADAR_CLEAR;
mutex_unlock(&radar.lock);
+ nl80211_radar_flags_changed(rdev, chan);
printk(KERN_INFO "DFS: starting CAC (%p)\n", rdev);
@@ -121,6 +122,7 @@ static void radar_cac(struct work_struct *work)
mutex_unlock(&radar.lock);
kfree(cac);
+ nl80211_radar_flags_changed(rdev, chan);
nl80211_radar_cac_done(rdev);
return;
}
@@ -168,6 +170,7 @@ static void close_channel(u16 freq)
if (chan == NULL)
continue;
chan->flags &= ~IEEE80211_CHAN_RADAR_CLEAR;
+ nl80211_radar_flags_changed(rdev, chan);
c = rdev->ops->get_channel(&rdev->wiphy);
if (c->center_freq != chan->center_freq)
@@ -224,6 +227,7 @@ static void update_all_interference_flags(u16 freq, bool set)
chan->flags &= ~IEEE80211_CHAN_RADAR_INTERFERENCE;
if (set)
chan->flags |= IEEE80211_CHAN_RADAR_INTERFERENCE;
+ nl80211_radar_flags_changed(rdev, chan);
}
}
--
1.7.2.3
This includes 3 new commands. On to fire of a CAC, one to stop it
and a notification which is sent after the CAC period is over.
During a CAC we block any channel changes to ensure that the full
period is done while on the channel for which it has been started.
After the CAC the channel is marked as clear.
Note, I decided to do CACs per wiphy, because it is not possible to
ensure that the device doing the radar detection is able to detect
all interferences in the range of other devices (sector antennas,
..).
Signed-off-by: Bernhard Schmidt <[email protected]>
---
include/linux/nl80211.h | 8 ++
net/wireless/chan.c | 10 +++
net/wireless/core.c | 2 +
net/wireless/nl80211.c | 75 +++++++++++++++++++++
net/wireless/nl80211.h | 2 +
net/wireless/radar.c | 164 +++++++++++++++++++++++++++++++++++++++++++++++
net/wireless/radar.h | 10 +++
7 files changed, 271 insertions(+), 0 deletions(-)
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 2282f56..e14b2dd 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -410,6 +410,10 @@
* 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 a CAC early.
+ * @NL80211_CMD_RADAR_CAC_DONE: Notification sent if a CAC has completed.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -522,6 +526,10 @@ 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,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 4e63e67..8ab9e96 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -8,6 +8,7 @@
#include <net/cfg80211.h>
#include "core.h"
+#include "radar.h"
struct ieee80211_channel *
rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
@@ -122,6 +123,15 @@ int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
}
}
+ if (wdev && (wdev->iftype == NL80211_IFTYPE_ADHOC ||
+ wdev->iftype == NL80211_IFTYPE_AP ||
+ wdev->iftype == NL80211_IFTYPE_AP_VLAN ||
+ wdev->iftype == NL80211_IFTYPE_MESH_POINT ||
+ wdev->iftype == NL80211_IFTYPE_P2P_GO) &&
+ radar_cac_in_progress(rdev) &&
+ rdev->ops->get_channel(&rdev->wiphy) != chan)
+ return -EINVAL;
+
result = rdev->ops->set_channel(&rdev->wiphy,
wdev ? wdev->netdev : NULL,
chan, channel_type);
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 55984ca..eb517a2 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -554,6 +554,8 @@ void wiphy_unregister(struct wiphy *wiphy)
{
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+ radar_cac_stop(rdev);
+
rfkill_unregister(rdev->rfkill);
/* protect the device list */
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 52b76e7..20a24f4 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -22,6 +22,7 @@
#include "core.h"
#include "nl80211.h"
#include "reg.h"
+#include "radar.h"
static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb,
struct genl_info *info);
@@ -4775,6 +4776,20 @@ static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info)
return cfg80211_leave_mesh(rdev, dev);
}
+static int nl80211_radar_start_cac(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+
+ return radar_cac_start(rdev);
+}
+
+static int nl80211_radar_stop_cac(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+
+ return radar_cac_stop(rdev);
+}
+
#define NL80211_FLAG_NEED_WIPHY 0x01
#define NL80211_FLAG_NEED_NETDEV 0x02
#define NL80211_FLAG_NEED_RTNL 0x04
@@ -5273,6 +5288,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 = {
@@ -6130,6 +6161,50 @@ nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
nlmsg_free(msg);
}
+static void radar_cac_done_wdev(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev)
+{
+ 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_IFINDEX, wdev->netdev->ifindex);
+
+ 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_cac_done(struct cfg80211_registered_device *rdev)
+{
+ struct wireless_dev *wdev;
+
+ rcu_read_lock();
+
+ list_for_each_entry_rcu(wdev, &rdev->netdev_list, list)
+ radar_cac_done_wdev(rdev, wdev);
+
+ rcu_read_unlock();
+}
+
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..aa3c926 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -98,4 +98,6 @@ 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);
+
#endif /* __NET_WIRELESS_NL80211_H */
diff --git a/net/wireless/radar.c b/net/wireless/radar.c
index 779fd8c..361070c 100644
--- a/net/wireless/radar.c
+++ b/net/wireless/radar.c
@@ -11,6 +11,7 @@
#include <linux/ieee80211.h>
#include <net/cfg80211.h>
#include "radar.h"
+#include "nl80211.h"
static struct radar_parameters regdomain_params[] = {
{ 60, 1800, 1000 }, /* FCC, correct? */
@@ -20,6 +21,113 @@ static struct radar_parameters regdomain_params[] = {
static struct radar radar;
+/*
+ * radar_cac_in_progress - returns true if rdev is doing a CAC.
+ */
+bool radar_cac_in_progress(struct cfg80211_registered_device *rdev)
+{
+ struct radar_cac_list *cac;
+
+ mutex_lock(&radar.lock);
+ list_for_each_entry(cac, &radar.cac_list, list) {
+ if (cac->rdev == rdev) {
+ mutex_unlock(&radar.lock);
+ return true;
+ }
+ }
+ mutex_unlock(&radar.lock);
+ return false;
+}
+
+/*
+ * radar_cac_start - start CAC on the current channel
+ */
+int radar_cac_start(struct cfg80211_registered_device *rdev)
+{
+ struct radar_cac_list *cac;
+ struct ieee80211_channel *chan;
+
+ if (radar_cac_in_progress(rdev))
+ return 0;
+
+ if (!rdev->ops->get_channel)
+ return -EINVAL;
+
+ chan = rdev->ops->get_channel(&rdev->wiphy);
+ mutex_lock(&radar.lock);
+ if ((chan->flags & IEEE80211_CHAN_RADAR_INTERFERENCE)) {
+ mutex_unlock(&radar.lock);
+ return -EINVAL;
+ }
+ chan->flags &= ~IEEE80211_CHAN_RADAR_CLEAR;
+ mutex_unlock(&radar.lock);
+
+ printk(KERN_INFO "DFS: starting CAC (%p)\n", rdev);
+
+ cac = kmalloc(sizeof(struct radar_cac_list), GFP_KERNEL);
+ if (cac == NULL)
+ return -ENOMEM;
+
+ mutex_lock(&radar.lock);
+ cac->rdev = rdev;
+ cac->timeout = jiffies +
+ msecs_to_jiffies(radar.params->cac_period * 1000);
+ list_add_tail(&cac->list, &radar.cac_list);
+ mutex_unlock(&radar.lock);
+ mod_timer(&radar.timer, jiffies + msecs_to_jiffies(100));
+ return 0;
+}
+
+/*
+ * radar_cac_stop - stop CAC in one is in progess
+ */
+int radar_cac_stop(struct cfg80211_registered_device *rdev)
+{
+ struct radar_cac_list *cac, *tmp;
+
+ mutex_lock(&radar.lock);
+ list_for_each_entry_safe(cac, tmp, &radar.cac_list, list) {
+ if (cac->rdev == rdev) {
+ printk(KERN_INFO "DFS: stop CAC (%p)\n", rdev);
+
+ list_del(&cac->list);
+ mutex_unlock(&radar.lock);
+
+ kfree(cac);
+ nl80211_radar_cac_done(rdev);
+ return 0;
+ }
+ }
+ mutex_unlock(&radar.lock);
+ return 0;
+}
+
+static void radar_cac(struct work_struct *work)
+{
+ struct radar_cac_list *cac, *tmp;
+
+ mutex_lock(&radar.lock);
+ list_for_each_entry_safe(cac, tmp, &radar.cac_list, list) {
+ if (time_is_before_jiffies(cac->timeout)) {
+ struct cfg80211_registered_device *rdev = cac->rdev;
+ struct ieee80211_channel *chan;
+
+ printk(KERN_INFO "DFS: CAC done (%p)\n", rdev);
+
+ chan = rdev->ops->get_channel(&rdev->wiphy);
+ chan->flags |= IEEE80211_CHAN_RADAR_CLEAR;
+ list_del(&cac->list);
+ mutex_unlock(&radar.lock);
+
+ kfree(cac);
+ nl80211_radar_cac_done(rdev);
+ return;
+ }
+ }
+ mutex_unlock(&radar.lock);
+}
+static DECLARE_WORK(cac_work, radar_cac);
+
void radar_update_params(u8 dfs_region)
{
mutex_lock(&radar.lock);
@@ -39,6 +147,11 @@ void radar_update_params(u8 dfs_region)
static void radar_timer(unsigned long data)
{
+ if (!list_empty(&radar.cac_list))
+ schedule_work(&cac_work);
+
+ if (!list_empty(&radar.cac_list))
+ mod_timer(&radar.timer, jiffies + msecs_to_jiffies(100));
}
void radar_init(void)
@@ -50,12 +163,21 @@ void radar_init(void)
radar.params = ®domain_params[0];
mutex_init(&radar.lock);
+ INIT_LIST_HEAD(&radar.cac_list);
setup_timer(&radar.timer, radar_timer, (unsigned long)0);
}
void radar_deinit(void)
{
+ struct radar_cac_list *cac, *cactmp;
+
del_timer_sync(&radar.timer);
+ mutex_lock(&radar.lock);
+ list_for_each_entry_safe(cac, cactmp, &radar.cac_list, list) {
+ list_del(&cac->list);
+ kfree(cac);
+ }
+ mutex_unlock(&radar.lock);
mutex_destroy(&radar.lock);
}
@@ -67,6 +189,47 @@ static int radar_open_file_generic(struct inode *inode, struct file *file)
return 0;
}
+static ssize_t radar_debugfs_cac_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct radar_cac_list *cac;
+ char *buf;
+ unsigned int offset = 0, buf_size = PAGE_SIZE, r;
+
+ buf = kzalloc(buf_size, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ if (!list_empty(&radar.cac_list)) {
+ mutex_lock(&radar.lock);
+ list_for_each_entry(cac, &radar.cac_list, list) {
+ int remaining;
+
+ remaining = jiffies_to_msecs(cac->timeout - jiffies);
+ remaining /= 1000;
+ offset += snprintf(buf + offset,
+ buf_size - offset,
+ "%s: %u secs remaining\n",
+ wiphy_name(&cac->rdev->wiphy),
+ remaining);
+ }
+ mutex_unlock(&radar.lock);
+ }
+
+ r = simple_read_from_buffer(user_buf, count, ppos, buf, offset);
+
+ kfree(buf);
+
+ return r;
+}
+
+static const struct file_operations cac_ops = {
+ .read = radar_debugfs_cac_read,
+ .open = radar_open_file_generic,
+ .llseek = default_llseek,
+};
+
static struct dentry *radar_debugfs_dir;
#define DEBUGFS_ADD(name) \
@@ -76,6 +239,7 @@ static struct dentry *radar_debugfs_dir;
void radar_debugfs_add(struct dentry *ieee80211_debugfs_dir)
{
radar_debugfs_dir = debugfs_create_dir("radar", ieee80211_debugfs_dir);
+ DEBUGFS_ADD(cac);
}
void radar_debugfs_remove()
diff --git a/net/wireless/radar.h b/net/wireless/radar.h
index 053ceb6..89cc73d 100644
--- a/net/wireless/radar.h
+++ b/net/wireless/radar.h
@@ -27,12 +27,22 @@ struct radar_parameters {
int close_time;
};
+struct radar_cac_list {
+ struct cfg80211_registered_device *rdev;
+ unsigned long timeout;
+ struct list_head list;
+};
+
struct radar {
struct radar_parameters *params;
struct mutex lock;
struct timer_list timer;
+ struct list_head cac_list;
};
+bool radar_cac_in_progress(struct cfg80211_registered_device *rdev);
+int radar_cac_start(struct cfg80211_registered_device *rdev);
+int radar_cac_stop(struct cfg80211_registered_device *rdev);
void radar_update_params(u8 dfs_region);
void radar_init(void);
void radar_deinit(void);
--
1.7.2.3
On Mon, Feb 28, 2011 at 08:48:49AM -0800, Bernhard Schmidt wrote:
> --- /dev/null
> +++ b/net/wireless/radar.c
> @@ -0,0 +1,86 @@
> +/*
> + * 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 <linux/ieee80211.h>
> +#include <net/cfg80211.h>
> +#include "radar.h"
> +
> +static struct radar_parameters regdomain_params[] = {
> + { 60, 1800, 1000 }, /* FCC, correct? */
> + { 60, 1800, 1000 }, /* ETSI */
> + { 60, 1800, 1000 }, /* JP, correct? */
> +};
If FCC or JP are not supported, I rather code not be present for it, or some
sort of flag for now to allow the radar enablement thingy to fail all the
time. In fact if FCC / JP regions are not supported you should not even
be able to operate in the mode of operation desired if your target channel
is a DFS one. If you do enter into an allowed non-DFS channel for that region
and you later try to switch to a DFS chanel then we'd hit another failure.
Luis
On Mon, Feb 28, 2011 at 08:47:06AM -0800, Bernhard Schmidt wrote:
> DFS introduces 2 new flags a channel requiring radar detection
> might take. The interference flag indicates that interference was
> detected either during CAC or in-service monitoring and the
> channel is not to be used for the NOP period. The clear flag
> indicates that during a full CAC no interference was detected and
> it is allowed to open a BSS on that channel. The case were both
> flags are set is used to indicate that interference has been
> detected and we are in progress of closing on that channel.
What does closing mean?
> Signed-off-by: Bernhard Schmidt <[email protected]>
> ---
> include/linux/nl80211.h | 6 ++++++
> include/net/cfg80211.h | 18 ++++++++++++------
> net/mac80211/cfg.c | 6 ++++++
> net/mac80211/tx.c | 6 ++++--
> net/wireless/nl80211.c | 4 ++++
> 5 files changed, 32 insertions(+), 8 deletions(-)
>
> diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
> index e3c9ec7..2282f56 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.
Why do you need a flag for clear, can you simply count on the
lack of the flag as the "clear" state?
Luis
On Tue, Mar 1, 2011 at 11:32 PM, Bernhard Schmidt
<[email protected]> wrote:
> On Tuesday, March 01, 2011 22:58:56 Luis R. Rodriguez wrote:
>> On Mon, Feb 28, 2011 at 08:48:49AM -0800, Bernhard Schmidt wrote:
>> > --- /dev/null
>> > +++ b/net/wireless/radar.c
>> > @@ -0,0 +1,86 @@
>> > +/*
>> > + * 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 <linux/ieee80211.h>
>> > +#include <net/cfg80211.h>
>> > +#include "radar.h"
>> > +
>> > +static struct radar_parameters regdomain_params[] = {
>> > + { 60, 1800, 1000 }, /* FCC, correct? */
>> > + { 60, 1800, 1000 }, /* ETSI */
>> > + { 60, 1800, 1000 }, /* JP, correct? */
>> > +};
>>
>> If FCC or JP are not supported, I rather code not be present for it, or some
>> sort of flag for now to allow the radar enablement thingy to fail all the
>> time. In fact if FCC / JP regions are not supported you should not even
>> be able to operate in the mode of operation desired if your target channel
>> is a DFS one. If you do enter into an allowed non-DFS channel for that region
>> and you later try to switch to a DFS chanel then we'd hit another failure.
>
> That just means that I hadn't yet looked up the correct values, those
> are not available on the wiki either.
Either way, disable them if not supported yet.
Luis
On Tuesday, March 01, 2011 22:54:12 Luis R. Rodriguez wrote:
> On Mon, Feb 28, 2011 at 08:47:06AM -0800, Bernhard Schmidt wrote:
> > DFS introduces 2 new flags a channel requiring radar detection
> > might take. The interference flag indicates that interference was
> > detected either during CAC or in-service monitoring and the
> > channel is not to be used for the NOP period. The clear flag
> > indicates that during a full CAC no interference was detected and
> > it is allowed to open a BSS on that channel. The case were both
> > flags are set is used to indicate that interference has been
> > detected and we are in progress of closing on that channel.
>
> What does closing mean?
Channel closing time is the period between radar interference and the
last transmission on a channel. After detected the interferences there
must be short time frame where you can notify stations about switching
to another channel (CSA).
> > Signed-off-by: Bernhard Schmidt <[email protected]>
>
> > ---
> > include/linux/nl80211.h | 6 ++++++
> > include/net/cfg80211.h | 18 ++++++++++++------
> > net/mac80211/cfg.c | 6 ++++++
> > net/mac80211/tx.c | 6 ++++--
> > net/wireless/nl80211.c | 4 ++++
> > 5 files changed, 32 insertions(+), 8 deletions(-)
> >
> > diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
> > index e3c9ec7..2282f56 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.
>
> Why do you need a flag for clear, can you simply count on the
> lack of the flag as the "clear" state?
No. There are 3 states a channel can be in, "usable", "available" and
"unavailable" (as definied in ETSI v1.5.1). On initialization all
channels are "usable", this is indicated by no flag at all. Only after
a full CAC can a channel get "available" (the CLEAR flag) and is now
allowed to be used for beaconing. "unavailable" channels are those
on which interference has been detected, those are marked with
INTERFERENCE, this channel becomes a "usable" (no flag) channel again
after the non-occupancy period.
--
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, March 01, 2011 14:15:21 Johannes Berg wrote:
> On Tue, 2011-03-01 at 14:07 +0100, Bernhard Schmidt wrote:
>
> > Sorry about that.. it should have read:
> > "..that states are *now* global and no per wiphy.."
> >
> > What I mean with that is that the interference flag/reporting, as
> > well as the NOL is shared between all wiphys contrary to the previous
> > version.
>
> Oh, ok.
>
> > > Finally, I think your code split is a little hard to understand. Is
> > > there really any point in adding the code bit by bit into both cfg80211
> > > and mac80211 at the same time? I'd rather see a few patches to make
> > > cfg80211 complete and then implement it all in mac80211.
> >
> > I tried to group them by functionality and not by subsystem. But if
> > you prefer that I can make a large blob for cfg80211.
>
> No, splitting them up seems alright, I just wouldn't split up the
> mac80211 bits across. You'll also find that when it comes to advertising
> capabilities, you need mac80211 to advertise them to cfg80211, and then
> you only want to advertise it once all functionality is in place.
I see, so, basically, given there is an alternative for [PATCH 1/9]
(get_channel) the only thing touching mac80211 is [PATCH 3/9], so, am
I doing the right thing?
> Now, for applying it might later make sense to just have a single patch
> adding it, but it doesn't really matter as long as the code isn't really
> used anyway since no driver advertises the capability.
>
> > > Which brings me to another point -- there's no way to detect from
> > > userspace whether or not this is all available.
> >
> > True, the only thing available right now is checking the error code
> > for CAC_START. I'll fix that.
>
> One thing to keep in mind: I don't typically trust drivers, that is if
> they don't advertise something cfg80211 won't allow it even if it might
> still succeed. For example, if the driver doesn't advertise IBSS, but
> would still permit adding IBSS, cfg80211 doesn't allow it. This makes
> things more consistent and makes driver authors realise right away that
> they need to advertise things.
Got it, will add some kind of "radar-capability" flag for drivers.
--
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-02-28 at 17:46 +0100, Bernhard Schmidt wrote:
> I'm really not sure about this.. is there another/better way to
> access the current channel last set on a wiphy?
Very soon, there will not be a single operating channel. So this needs
to be per netdev. But for most interface types, cfg80211 already knows
the channel.
Also: This isn't a mac80211 patch. Please name patches after the
subsystem that gets new API, not after the subsystem that implements it
-- a simple implementation is fine in the same patch, a more complex one
might warrant a separate patch.
johannes
On Tue, 2011-03-01 at 13:54 -0800, Luis R. Rodriguez wrote:
> > + * @NL80211_FREQUENCY_ATTR_RADAR_CLEAR: during a full CAC no interference has
> > + * been detected.
>
> Why do you need a flag for clear, can you simply count on the
> lack of the flag as the "clear" state?
This really means CAC_DONE_AND_FOUND_CLEAR.
Though now that has me wondering, maybe it should be CAC_DONE and BUSY
as separate flags? But then the checks have to be (CAC_DONE && !BUSY),
which is more expressive but also more complex and error prone.
johannes
On Tuesday, March 01, 2011 13:28:06 Johannes Berg wrote:
> On Mon, 2011-02-28 at 17:40 +0100, Bernhard Schmidt wrote:
>
> > 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.
>
> I'm not quite sure about all of this. First of all, you don't really
> explain the global state vs. local state but you did say that you no
> longer had global state, which clearly isn't true.
Sorry about that.. it should have read:
"..that states are *now* global and no per wiphy.."
What I mean with that is that the interference flag/reporting, as
well as the NOL is shared between all wiphys contrary to the previous
version.
> Also, what's the point in "struct radar" if there's only a single
> instance of that, which is global? I'd rather have multiple global
> variables I think -- but that might just be a matter of personal taste
> or choice.
Yeah, that 'struct radar' can be split up and moved into radar.c as
static vars.
> Finally, I think your code split is a little hard to understand. Is
> there really any point in adding the code bit by bit into both cfg80211
> and mac80211 at the same time? I'd rather see a few patches to make
> cfg80211 complete and then implement it all in mac80211.
I tried to group them by functionality and not by subsystem. But if
you prefer that I can make a large blob for cfg80211.
> Which brings me to another point -- there's no way to detect from
> userspace whether or not this is all available.
True, the only thing available right now is checking the error code
for CAC_START. I'll fix that.
> Finally, such details like not needing a timer -- a delayed work should
> be sufficient, etc.
>
> johannes
>
>
--
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, March 01, 2011 22:58:56 Luis R. Rodriguez wrote:
> On Mon, Feb 28, 2011 at 08:48:49AM -0800, Bernhard Schmidt wrote:
> > --- /dev/null
> > +++ b/net/wireless/radar.c
> > @@ -0,0 +1,86 @@
> > +/*
> > + * 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 <linux/ieee80211.h>
> > +#include <net/cfg80211.h>
> > +#include "radar.h"
> > +
> > +static struct radar_parameters regdomain_params[] = {
> > + { 60, 1800, 1000 }, /* FCC, correct? */
> > + { 60, 1800, 1000 }, /* ETSI */
> > + { 60, 1800, 1000 }, /* JP, correct? */
> > +};
>
> If FCC or JP are not supported, I rather code not be present for it, or some
> sort of flag for now to allow the radar enablement thingy to fail all the
> time. In fact if FCC / JP regions are not supported you should not even
> be able to operate in the mode of operation desired if your target channel
> is a DFS one. If you do enter into an allowed non-DFS channel for that region
> and you later try to switch to a DFS chanel then we'd hit another failure.
That just means that I hadn't yet looked up the correct values, those
are not available on the wiki either.
--
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, Feb 28, 2011 at 08:47:44AM -0800, Bernhard Schmidt wrote:
> + if (sdata && (sdata->vif.type == NL80211_IFTYPE_ADHOC ||
> + sdata->vif.type == NL80211_IFTYPE_AP ||
> + sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
> + sdata->vif.type == NL80211_IFTYPE_MESH_POINT ||
> + sdata->vif.type == NL80211_IFTYPE_P2P_GO) &&
How about adding a helper as a separate patch that checks this
for us and then sprinkling in other areas of code we have that uses
the same check?
Some thing like ieee80211_sdata_can_beacon(sdata) or whatever.
Luis
On Tue, 2011-03-01 at 14:07 +0100, Bernhard Schmidt wrote:
> Sorry about that.. it should have read:
> "..that states are *now* global and no per wiphy.."
>
> What I mean with that is that the interference flag/reporting, as
> well as the NOL is shared between all wiphys contrary to the previous
> version.
Oh, ok.
> > Finally, I think your code split is a little hard to understand. Is
> > there really any point in adding the code bit by bit into both cfg80211
> > and mac80211 at the same time? I'd rather see a few patches to make
> > cfg80211 complete and then implement it all in mac80211.
>
> I tried to group them by functionality and not by subsystem. But if
> you prefer that I can make a large blob for cfg80211.
No, splitting them up seems alright, I just wouldn't split up the
mac80211 bits across. You'll also find that when it comes to advertising
capabilities, you need mac80211 to advertise them to cfg80211, and then
you only want to advertise it once all functionality is in place.
Now, for applying it might later make sense to just have a single patch
adding it, but it doesn't really matter as long as the code isn't really
used anyway since no driver advertises the capability.
> > Which brings me to another point -- there's no way to detect from
> > userspace whether or not this is all available.
>
> True, the only thing available right now is checking the error code
> for CAC_START. I'll fix that.
One thing to keep in mind: I don't typically trust drivers, that is if
they don't advertise something cfg80211 won't allow it even if it might
still succeed. For example, if the driver doesn't advertise IBSS, but
would still permit adding IBSS, cfg80211 doesn't allow it. This makes
things more consistent and makes driver authors realise right away that
they need to advertise things.
johannes
On Mon, 2011-02-28 at 17:40 +0100, Bernhard Schmidt wrote:
> 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.
I'm not quite sure about all of this. First of all, you don't really
explain the global state vs. local state but you did say that you no
longer had global state, which clearly isn't true.
Also, what's the point in "struct radar" if there's only a single
instance of that, which is global? I'd rather have multiple global
variables I think -- but that might just be a matter of personal taste
or choice.
Finally, I think your code split is a little hard to understand. Is
there really any point in adding the code bit by bit into both cfg80211
and mac80211 at the same time? I'd rather see a few patches to make
cfg80211 complete and then implement it all in mac80211.
Which brings me to another point -- there's no way to detect from
userspace whether or not this is all available.
Finally, such details like not needing a timer -- a delayed work should
be sufficient, etc.
johannes
On Mon, 2011-02-28 at 17:49 +0100, Bernhard Schmidt wrote:
> + chan->flags &= ~IEEE80211_CHAN_RADAR_INTERFERENCE;
> + if (set)
> + chan->flags |= IEEE80211_CHAN_RADAR_INTERFERENCE;
else would be better (not racy)
johannes
On Mon, 2011-02-28 at 17:48 +0100, Bernhard Schmidt wrote:
> +static struct radar radar;
Didn't you just say you no longer had any global state???
johannes