2010-12-21 15:24:18

by Zefir Kurtisi

[permalink] [raw]
Subject: [PATCH 2/4] DFS: simple pattern detector



Provides a very basic pattern detector to test the proposed design.

Implements detection for ETSI 1.5.1 single PRI radar test signals. It is
usable only for off-channel-scans, i.e. does not tolerate false pulses.

Signed-off-by: Zefir Kurtisi <[email protected]>
---
net/wireless/Makefile | 9 +
net/wireless/core.c | 47 ++
.../net/wireless/dfs/dfs_common.h | 20 +
.../net/wireless/dfs/dfs_debug.c | 16 +
.../net/wireless/dfs/dfs_debug.h | 107 ++++
.../net/wireless/dfs/dfs_debugfs.c | 301 +++++++++++
.../net/wireless/dfs/dfs_debugfs.h | 9 +
.../net/wireless/dfs/dfs_handler.c | 94 ++++
.../net/wireless/dfs/dfs_pattern_detector.c | 559 ++++++++++++++++++++
.../net/wireless/dfs/dfs_pattern_detector.h | 46 ++
.../net/wireless/dfs/dfs_radar_types.h | 47 ++
11 files changed, 1255 insertions(+), 0 deletions(-)
create mode 100644 net/wireless/dfs/dfs_common.h
create mode 100644 net/wireless/dfs/dfs_debug.c
create mode 100644 net/wireless/dfs/dfs_debug.h
create mode 100644 net/wireless/dfs/dfs_debugfs.c
create mode 100644 net/wireless/dfs/dfs_debugfs.h
create mode 100644 net/wireless/dfs/dfs_handler.c
create mode 100644 net/wireless/dfs/dfs_pattern_detector.c
create mode 100644 net/wireless/dfs/dfs_pattern_detector.h
create mode 100644 net/wireless/dfs/dfs_radar_types.h

diff --git a/net/wireless/Makefile b/net/wireless/Makefile
index 37d70ce..3d6207f 100644
--- a/net/wireless/Makefile
+++ b/net/wireless/Makefile
@@ -10,6 +10,15 @@ cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o
cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o
cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o

+# DFS detector, to be made configurable
+
+cfg80211-y += \
+ dfs/dfs_pattern_detector.o \
+ dfs/dfs_handler.o \
+ dfs/dfs_debug.o \
+ dfs/dfs_debugfs.o
+
+
ccflags-y += -D__CHECK_ENDIAN__

$(obj)/regdb.c: $(src)/db.txt $(src)/genregdb.awk
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 79febd2..25cb99b 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -28,6 +28,14 @@
#include "wext-compat.h"
#include "ethtool.h"

+/*
+ * DFS handler
+ *
+ * for this proof-of-concept let's have a global instance of the handler
+ */
+#include "net/dfs.h"
+static struct dfs_handler *cfg80211_dfs_handler;
+
/* name for sysfs, %d is appended */
#define PHY_NAME "phy"

@@ -886,6 +894,33 @@ static struct pernet_operations cfg80211_pernet_ops = {
};
#endif

+
+
+/**
+ * DFS
+ */
+
+void ieee80211_add_radar_pulse(u16 freq, u64 ts, u8 rssi, u8 width)
+{
+ if (cfg80211_dfs_handler != NULL) {
+ struct pulse_event event;
+ event.width = width;
+ event.ts = ts;
+ event.rssi = rssi;
+ event.freq = freq;
+ cfg80211_dfs_handler->add_pulse(cfg80211_dfs_handler, &event);
+ }
+}
+EXPORT_SYMBOL(ieee80211_add_radar_pulse);
+
+void ieee80211_radar_detected(u16 freq)
+{
+ printk(KERN_INFO "Radar detected at freq=%d\n", freq);
+ /* TODO: whatever needs to be done after radar detection */
+}
+EXPORT_SYMBOL(ieee80211_radar_detected);
+
+
static int __init cfg80211_init(void)
{
int err;
@@ -918,6 +953,14 @@ static int __init cfg80211_init(void)
if (!cfg80211_wq)
goto out_fail_wq;

+ /**
+ * DFS handler initialization
+ *
+ * TODO: set the real domain given by countrycode
+ */
+ cfg80211_dfs_handler = dfs_handler_init(DFS_ETSI_DOMAIN);
+
+
return 0;

out_fail_wq:
@@ -939,6 +982,10 @@ subsys_initcall(cfg80211_init);

static void __exit cfg80211_exit(void)
{
+ /* release DFS handler */
+ if (cfg80211_dfs_handler != NULL)
+ cfg80211_dfs_handler->exit(cfg80211_dfs_handler);
+
debugfs_remove(ieee80211_debugfs_dir);
nl80211_exit();
unregister_netdevice_notifier(&cfg80211_netdev_notifier);
diff --git a/net/wireless/dfs/dfs_common.h b/net/wireless/dfs/dfs_common.h
new file mode 100644
index 0000000..9b71efd
--- /dev/null
+++ b/net/wireless/dfs/dfs_common.h
@@ -0,0 +1,20 @@
+#ifndef DFS_COMMON_H
+#define DFS_COMMON_H
+
+#include "net/dfs.h"
+
+
+/**
+ * struct dfs_data - DFS handler private data
+ *
+ * @dfs_handler: instance back-reference
+ * @dfs_domain: DFS domain the handler is currently working
+ * @pattern_detector: instance reference to pattern detector
+ */
+struct dfs_data {
+ struct dfs_handler *dfs_handler;
+ enum dfs_domain dfs_domain;
+ struct dfs_pattern_detector *pattern_detector;
+};
+
+#endif /* DFS_COMMON_H */
diff --git a/net/wireless/dfs/dfs_debug.c b/net/wireless/dfs/dfs_debug.c
new file mode 100644
index 0000000..ba756de
--- /dev/null
+++ b/net/wireless/dfs/dfs_debug.c
@@ -0,0 +1,16 @@
+#include "dfs_debug.h"
+
+#define USE_FULL_DEBUG 0
+
+u32 dfs_debug_level = 0
+ | DFS_DEBUG_ERROR
+ | DFS_DEBUG_WARN
+ | DFS_DEBUG_INFO
+#if USE_FULL_DEBUG
+ | DFS_DEBUG_TRACE
+ | DFS_DEBUG_LOG
+#endif
+;
+
+char dbg_buff[MAX_DEBUG_SPRINTF + 1] = {0};
+
diff --git a/net/wireless/dfs/dfs_debug.h b/net/wireless/dfs/dfs_debug.h
new file mode 100644
index 0000000..eda2735
--- /dev/null
+++ b/net/wireless/dfs/dfs_debug.h
@@ -0,0 +1,107 @@
+#ifndef DFS_DEBUG_H
+#define DFS_DEBUG_H
+
+enum {
+ DFS_DEBUG_ERROR = 0x000100,
+ DFS_DEBUG_WARN = 0x000200,
+ DFS_DEBUG_INFO = 0x000400,
+ DFS_DEBUG_TRACE = 0x000800,
+ DFS_DEBUG_LOG = 0x001000,
+};
+
+extern u32 dfs_debug_level;
+#define MAX_DEBUG_SPRINTF 511
+extern char dbg_buff[MAX_DEBUG_SPRINTF + 1];
+
+#define __SHORT_FILE__ \
+ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
+
+
+#ifdef __KERNEL__
+#include <linux/kernel.h>
+
+#define DFS_DPRINTK(LEVEL, FMT, ...) \
+do { \
+ if ((LEVEL) & dfs_debug_level) \
+ printk(FMT, ##__VA_ARGS__); \
+} while (0)
+
+#define ASSERT(expr) \
+if (unlikely(!(expr))) { \
+ panic(KERN_ERR "Assertion failed! %s,%s,%s,line=%d\n", \
+ #expr, __SHORT_FILE__, __func__, __LINE__); \
+}
+
+#else
+#include <stdio.h>
+
+#define DFS_DPRINTK(LEVEL, FMT, ...) \
+do { \
+ if ((LEVEL) & dfs_debug_level) \
+ printf(FMT, ##__VA_ARGS__); \
+} while (0)
+
+#define ASSERT(expr) \
+do { \
+ if (!(expr)) { \
+ printf("Assertion failed! %s,%s,%s,line=%d\n", \
+ #expr, __SHORT_FILE__, __func__, __LINE__); \
+ } \
+} while (0)
+
+#endif
+
+#define DTRACE(...) \
+do { \
+ DFS_DPRINTK(DFS_DEBUG_TRACE, "TRACE: %s\n", __func__); \
+} while (0)
+
+#define DLOG(FMT, ...) \
+do { \
+ snprintf(dbg_buff, MAX_DEBUG_SPRINTF, "LOG: %s\n", FMT); \
+ DFS_DPRINTK(DFS_DEBUG_LOG, dbg_buff, ##__VA_ARGS__); \
+} while (0)
+
+#define DINFO(FMT, ...) \
+do { \
+ snprintf(dbg_buff, MAX_DEBUG_SPRINTF, "INFO: %s\n", FMT); \
+ DFS_DPRINTK(DFS_DEBUG_INFO, dbg_buff, ##__VA_ARGS__); \
+} while (0)
+
+#define DWARN(FMT, ...) \
+do { \
+ snprintf(dbg_buff, MAX_DEBUG_SPRINTF, \
+ "WARN: %s: %s\n", __func__, FMT); \
+ DFS_DPRINTK(DFS_DEBUG_WARN, dbg_buff, ##__VA_ARGS__); \
+} while (0)
+
+#define DERROR(FMT, ...) \
+do { \
+ snprintf(dbg_buff, MAX_DEBUG_SPRINTF, \
+ "WARN: %s: %s\n", __func__, FMT); \
+ DFS_DPRINTK(DFS_DEBUG_ERROR, dbg_buff, ##__VA_ARGS__); \
+} while (0)
+
+#define DFATAL(FMT, ...) \
+do { \
+ snprintf(dbg_buff, MAX_DEBUG_SPRINTF, \
+ "FATAL: %s: %s\n", __func__, FMT); \
+ DFS_DPRINTK(DFS_DEBUG_ERROR, dbg_buff, ##__VA_ARGS__); \
+} while (0)
+
+
+#define DINIT(FMT, ...) \
+do { \
+ snprintf(dbg_buff, MAX_DEBUG_SPRINTF, \
+ "INIT: %s: %s\n", __func__, FMT); \
+ DFS_DPRINTK(DFS_DEBUG_ERROR, dbg_buff, ##__VA_ARGS__); \
+} while (0)
+
+#define DINFO_OK(FMT, ...) \
+do { \
+ snprintf(dbg_buff, MAX_DEBUG_SPRINTF, "OK: %s: %s\n", __func__, FMT); \
+ DFS_DPRINTK(DFS_DEBUG_INFO, dbg_buff, ##__VA_ARGS__); \
+} while (0)
+
+
+#endif /* DFS_DEBUG_H */
diff --git a/net/wireless/dfs/dfs_debugfs.c b/net/wireless/dfs/dfs_debugfs.c
new file mode 100644
index 0000000..2610bdb
--- /dev/null
+++ b/net/wireless/dfs/dfs_debugfs.c
@@ -0,0 +1,301 @@
+#include "dfs_common.h"
+
+
+#if defined(__KERNEL__)
+
+#include <linux/debugfs.h>
+
+#include "net/dfs.h"
+#include "net/cfg80211.h"
+#include "dfs_debugfs.h"
+#include "dfs_debug.h"
+
+static int dfs_debugfs_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+
+/* generic */
+static ssize_t read_dfs_generic(char __user *user_buf, size_t count,
+ loff_t *ppos, const char *fmt, int val)
+{
+ char buf[32];
+ unsigned int len;
+
+ sprintf(buf, fmt, val);
+ strcat(buf, "\n");
+ len = strlen(buf);
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_dfs_generic(const char __user *user_buf, size_t count,
+ unsigned int *val)
+{
+ char buf[32];
+ ssize_t len;
+
+ unsigned long my_val;
+
+ len = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len))
+ return -EFAULT;
+
+ buf[len] = '\0';
+ if (strict_strtoul(buf, 0, &my_val))
+ return -EINVAL;
+ *val = my_val;
+ return count;
+}
+
+
+/********* debug_level */
+static ssize_t read_dfs_debug_level(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ return read_dfs_generic(user_buf, count, ppos, "0x%.8x",
+ dfs_debug_level);
+}
+
+static ssize_t write_dfs_debug_level(struct file *file,
+ const char __user *user_buf, size_t count, loff_t *ppos)
+{
+ return write_dfs_generic(user_buf, count, &dfs_debug_level);
+}
+
+static const struct file_operations fops_dfs_debug_level = {
+ .read = read_dfs_debug_level,
+ .write = write_dfs_debug_level,
+ .open = dfs_debugfs_open,
+ .owner = THIS_MODULE,
+};
+
+
+/********* radar */
+
+#include <linux/ktime.h>
+
+#define R1_WIDTH 1
+#define R1_PPS 700
+#define R1_PPB 18
+#define R1_RSSI 30
+#define R1_FREQ 5500
+
+static int radar_pps = R1_PPS;
+static int radar_ppb = R1_PPB;
+static int radar_width = R1_WIDTH;
+static int radar_rssi = R1_RSSI;
+static int radar_freq = R1_FREQ;
+
+
+/********* radar_width */
+static ssize_t read_dfs_radar_width(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ return read_dfs_generic(user_buf, count, ppos, "%d", radar_width);
+}
+
+static ssize_t write_dfs_radar_width(struct file *file,
+ const char __user *user_buf, size_t count, loff_t *ppos)
+{
+ return write_dfs_generic(user_buf, count, &radar_width);
+}
+
+static const struct file_operations fops_dfs_radar_width = {
+ .read = read_dfs_radar_width,
+ .write = write_dfs_radar_width,
+ .open = dfs_debugfs_open,
+ .owner = THIS_MODULE
+};
+
+
+/********* radar_prf */
+static ssize_t read_dfs_radar_pps(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ return read_dfs_generic(user_buf, count, ppos, "%d", radar_pps);
+}
+
+static ssize_t write_dfs_radar_pps(struct file *file,
+ const char __user *user_buf, size_t count, loff_t *ppos)
+{
+ return write_dfs_generic(user_buf, count, &radar_pps);
+}
+
+static const struct file_operations fops_dfs_radar_pps = {
+ .read = read_dfs_radar_pps,
+ .write = write_dfs_radar_pps,
+ .open = dfs_debugfs_open,
+ .owner = THIS_MODULE
+};
+
+/********* radar_ppb */
+static ssize_t read_dfs_radar_ppb(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ return read_dfs_generic(user_buf, count, ppos, "%d", radar_ppb);
+}
+
+static ssize_t write_dfs_radar_ppb(struct file *file,
+ const char __user *user_buf, size_t count, loff_t *ppos)
+{
+ return write_dfs_generic(user_buf, count, &radar_ppb);
+}
+
+static const struct file_operations fops_dfs_radar_ppb = {
+ .read = read_dfs_radar_ppb,
+ .write = write_dfs_radar_ppb,
+ .open = dfs_debugfs_open,
+ .owner = THIS_MODULE
+};
+
+
+/********* radar_rssi */
+static ssize_t read_dfs_radar_rssi(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ return read_dfs_generic(user_buf, count, ppos, "%d", radar_rssi);
+}
+
+static ssize_t write_dfs_radar_rssi(struct file *file,
+ const char __user *user_buf, size_t count, loff_t *ppos)
+{
+ return write_dfs_generic(user_buf, count, &radar_rssi);
+}
+
+static const struct file_operations fops_dfs_radar_rssi = {
+ .read = read_dfs_radar_rssi,
+ .write = write_dfs_radar_rssi,
+ .open = dfs_debugfs_open,
+ .owner = THIS_MODULE
+};
+
+
+/********* radar_freq */
+static ssize_t read_dfs_radar_freq(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ return read_dfs_generic(user_buf, count, ppos, "%d", radar_freq);
+}
+
+static ssize_t write_dfs_radar_freq(struct file *file,
+ const char __user *user_buf, size_t count, loff_t *ppos)
+{
+ return write_dfs_generic(user_buf, count, &radar_rssi);
+}
+
+static const struct file_operations fops_dfs_radar_freq = {
+ .read = read_dfs_radar_freq,
+ .write = write_dfs_radar_freq,
+ .open = dfs_debugfs_open,
+ .owner = THIS_MODULE
+};
+
+
+static void generate_radar(void)
+{
+ int i;
+ s64 tsf_sim = ktime_to_us(ktime_get_real());
+ u32 deltaUs = USEC_PER_SEC / radar_pps;
+
+ DTRACE();
+
+ for (i = 0; i < radar_ppb; i++) {
+ ieee80211_add_radar_pulse(radar_freq, tsf_sim,
+ radar_rssi, radar_width);
+ tsf_sim += deltaUs;
+ }
+}
+
+
+static ssize_t write_dfs_generate_radar(struct file *file,
+ const char __user *user_buf, size_t count, loff_t *ppos)
+{
+ unsigned long val;
+ char buf[32];
+ ssize_t len;
+
+ len = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len))
+ return -EFAULT;
+
+ buf[len] = '\0';
+ if (strict_strtoul(buf, 0, &val))
+ return -EINVAL;
+
+ if (val == 1)
+ generate_radar();
+
+ return count;
+}
+
+static const struct file_operations fops_dfs_generate_radar = {
+ .read = NULL,
+ .write = write_dfs_generate_radar,
+ .open = dfs_debugfs_open,
+ .owner = THIS_MODULE
+};
+
+
+
+static struct dentry *dfs_debugfs_root;
+
+void dfs_debugfs_exit(struct dfs_data *dfs_data)
+{
+ ASSERT(dfs_data != NULL);
+ debugfs_remove_recursive(dfs_debugfs_root);
+ debugfs_remove(dfs_debugfs_root);
+ dfs_debugfs_root = NULL;
+}
+
+int dfs_debugfs_init(struct dfs_data *dfs_data)
+{
+ if (dfs_debugfs_root) {
+ printk(KERN_INFO
+ "dfs_init_debug(): debugfs-root already set\n");
+ dfs_debugfs_exit(dfs_data);
+ }
+
+ dfs_debugfs_root = debugfs_create_dir("dfs", NULL);
+ if (!dfs_debugfs_root)
+ return -ENOENT;
+
+ if (!debugfs_create_file("debug_level", S_IRUSR | S_IWUSR,
+ dfs_debugfs_root, dfs_data, &fops_dfs_debug_level))
+ goto failed0;
+ if (!debugfs_create_file("generate_radar", S_IWUSR, dfs_debugfs_root,
+ dfs_data, &fops_dfs_generate_radar))
+ goto failed0;
+ if (!debugfs_create_file("radar_width", S_IWUSR, dfs_debugfs_root,
+ dfs_data, &fops_dfs_radar_width))
+ goto failed0;
+ if (!debugfs_create_file("radar_pps", S_IWUSR, dfs_debugfs_root,
+ dfs_data, &fops_dfs_radar_pps))
+ goto failed0;
+ if (!debugfs_create_file("radar_ppb", S_IWUSR, dfs_debugfs_root,
+ dfs_data, &fops_dfs_radar_ppb))
+ goto failed0;
+ if (!debugfs_create_file("radar_rssi", S_IWUSR, dfs_debugfs_root,
+ dfs_data, &fops_dfs_radar_rssi))
+ goto failed0;
+ if (!debugfs_create_file("radar_freq", S_IWUSR, dfs_debugfs_root,
+ dfs_data, &fops_dfs_radar_freq))
+ goto failed0;
+ return 0;
+
+failed0:
+ dfs_debugfs_exit(dfs_data);
+ return -ENOMEM;
+}
+
+#else
+void dfs_debugfs_exit(struct dfs_data *dfs_data) {}
+
+int dfs_debugfs_init(struct dfs_data *dfs_data)
+{
+ return 0;
+}
+
+#endif
+
diff --git a/net/wireless/dfs/dfs_debugfs.h b/net/wireless/dfs/dfs_debugfs.h
new file mode 100644
index 0000000..718d9ea
--- /dev/null
+++ b/net/wireless/dfs/dfs_debugfs.h
@@ -0,0 +1,9 @@
+#ifndef DFS_DEBUGFS_H
+#define DFS_DEBUGFS_H
+
+struct dfs_data;
+
+int dfs_debugfs_init(struct dfs_data *dfs_data);
+void dfs_debugfs_exit(struct dfs_data *dfs_data);
+
+#endif /* DFS_DEBUGFS_H */
diff --git a/net/wireless/dfs/dfs_handler.c b/net/wireless/dfs/dfs_handler.c
new file mode 100644
index 0000000..7e65852
--- /dev/null
+++ b/net/wireless/dfs/dfs_handler.c
@@ -0,0 +1,94 @@
+#include "net/dfs.h"
+#include "net/cfg80211.h"
+#include "dfs_common.h"
+#include "dfs_debug.h"
+#include "dfs_debugfs.h"
+#include "dfs_pattern_detector.h"
+
+
+/* Destructor */
+static void dh_exit(struct dfs_handler *_this)
+{
+ ASSERT(_this != NULL);
+
+ if (_this->data != NULL) {
+ struct dfs_data *dfs_data = _this->data;
+ dfs_debugfs_exit(dfs_data);
+ if (dfs_data->pattern_detector != NULL)
+ dfs_data->pattern_detector->
+ exit(dfs_data->pattern_detector);
+ kfree(dfs_data);
+ _this->data = NULL;
+ }
+ kfree(_this);
+}
+
+static int dh_add_pulse(struct dfs_handler *_this, struct pulse_event *event)
+{
+ int detector_result;
+ struct dfs_data *dfs_data;
+ DTRACE();
+ ASSERT((_this != NULL) && (_this->data != NULL));
+
+ dfs_data = _this->data;
+ detector_result = dfs_data->pattern_detector->
+ add_pulse(dfs_data->pattern_detector, event);
+ if (detector_result == RADAR_DETECTED) {
+ /* DINIT("found radar type %d", radar_type); */
+ ieee80211_radar_detected(event->freq);
+ return 1;
+ }
+ return 0;
+}
+
+static struct dfs_handler default_dfs_handler = {
+ .exit = dh_exit,
+ .add_pulse = dh_add_pulse,
+};
+
+/* Constructor */
+struct dfs_handler *dfs_handler_init(enum dfs_domain dfs_domain)
+{
+ struct dfs_handler *_this;
+ struct dfs_data *dfs_data;
+ int sz = sizeof(struct dfs_handler);
+ _this = kmalloc(sz, GFP_KERNEL);
+
+ if (_this == NULL) {
+ DFATAL("dfs_handler allocation failed");
+ return NULL;
+ }
+
+ *_this = default_dfs_handler;
+
+
+ sz = sizeof(struct dfs_data);
+ dfs_data = kmalloc(sz, GFP_KERNEL);
+ if (dfs_data == NULL) {
+ DFATAL("dfs_data allocation failed");
+ goto failed;
+ }
+
+ memset(dfs_data, 0, sz);
+
+ _this->data = dfs_data;
+ dfs_data->pattern_detector = dfs_pattern_detector_init(dfs_domain);
+ if (dfs_data->pattern_detector == NULL) {
+ DFATAL("detector_init() failed!");
+ goto failed;
+ }
+ _this->data->dfs_domain = dfs_domain;
+ _this->data->dfs_handler = _this;
+
+ /* XXX: debug_fs considered as non-critical on failure */
+ dfs_debugfs_init(_this->data);
+ DINIT("ok");
+ return _this;
+
+failed:
+ _this->exit(_this);
+ return NULL;
+}
+EXPORT_SYMBOL(dfs_handler_init);
+
+
diff --git a/net/wireless/dfs/dfs_pattern_detector.c b/net/wireless/dfs/dfs_pattern_detector.c
new file mode 100644
index 0000000..17ab7d6
--- /dev/null
+++ b/net/wireless/dfs/dfs_pattern_detector.c
@@ -0,0 +1,559 @@
+#include "dfs_pattern_detector.h"
+#include "dfs_debug.h"
+#include "net/dfs.h"
+
+#include "dfs_radar_types.h"
+
+/*
+ * Abbreviations used (based on regulatory specs):
+ * * prf: pulse repetition frequency [Hz]
+ * * pri: pulse repetition interval = 1/prf, here used as [us]
+ * * ppb: pulses per burst
+ */
+
+
+#define DELTA(X, Y) ((X < Y) ? (Y-X) : (X-Y))
+
+/* number of deviation of radar time in usecs tolerated on both sides
+ * TODO: this might need to be HW-dependent
+ */
+#define MAX_PRI_TOLERANCE 10
+
+
+/**
+ * struct radar_specs - specifies a radar pattern type
+ *
+ * @type_id: pattern type, as defined by ETSI / FCC
+ * @width_min: minimum radar pulse width in [us]
+ * @width_max: maximum radar pulse width in [us]
+ * @pri_min: minimum pulse repetition interval in [us] (including tolerance)
+ * @pri_max: minimum pri in [us] (including tolerance)
+ * @num_pri: maximum number of different pri for this type
+ * @ppb: pulses per bursts for this type
+ * @ppb_thresh: number of pulses required to trigger detection
+ * @max_dur: absolute max duration of pattern: num_pri * pri_max * ppb
+ *
+ * Characteristics of each radar pattern type are calculated at initialization
+ * based on radar test signal types defined by the chosen regulatory.
+ * They remain unchanged thereafter.
+ */
+struct radar_specs {
+ unsigned int type_id;
+ unsigned int width_min;
+ unsigned int width_max;
+ unsigned int pri_min;
+ unsigned int pri_max;
+ unsigned int num_pri;
+ unsigned int ppb;
+ unsigned int ppb_thresh;
+ unsigned int max_dur;
+};
+
+
+/* so far, maximum prf number is 3 for ETSI types 5 and 6 */
+#define MAX_PRF_NUM 3
+
+/**
+ * struct radar_stats - detector statistics updated on each pulse
+ *
+ * @pri_count: number of pri used for this pattern type so far
+ * @pri: array of pris in use
+ * @matching_pulse_count: number of pulses detected correctly so far
+ * @missed_pulse_count: number of pulses assumed as lost so far
+ * @false_pulse_count: number of invalid / false pulses so far
+ * @first_ts: timestamp of first valid pulse for this type
+ * @last_ts: timestamp of last valid pulse for this type
+ *
+ * The statistics reflect the current state of the related detector line.
+ *
+ * Detection is performed in place updating the affected detector lines
+ * whenever a pulse is added. The algorithm operates without keeping track
+ * of the pulse history but requires only the statistics collected so far.
+ *
+ * Statistical decisions are made based on the numbers for matching,
+ * missed, and false pulses count.
+ */
+struct radar_stats {
+ u32 pri_count;
+ u32 pri[MAX_PRF_NUM];
+ u32 matching_pulse_count;
+ u32 missed_pulse_count;
+ u32 false_pulse_count;
+ u64 first_ts;
+ u64 last_ts;
+};
+
+/**
+ * struct dfs_channels - DFS channels' frequencies, assumed constant
+ */
+static const u16 dfs_channels[] =
+{
+ 5260, 5280, 5300, 5320,
+ 5500, 5520, 5540, 5560, 5580, 5600, 5620, 5640, 5660, 5680, 5700,
+};
+#define NUM_DFS_CHANNELS (sizeof(dfs_channels)/sizeof(dfs_channels[0]))
+
+
+/**
+ * struct detector_line - detector line for one specific dfs pattern type
+ *
+ * @specs: dfs pattern type specification
+ * @stats: array of statistics for for all DFS channels
+ *
+ * Each detector line consists of a constant radar type specification and
+ * an array of statistics for all DFS channels.
+ */
+struct detector_line {
+ struct radar_specs specs;
+ struct radar_stats stats[NUM_DFS_CHANNELS];
+};
+
+
+/**
+ * struct pattern_detector_data - private instance data
+ *
+ * @num_detector_elements: number of different radar types
+ * @radar_detectors: array of num_detector_elements detector lines
+ * @min_valid_width: combined min of valid pulse widths
+ * @max_valid_width: combined max of valid pulse widths
+ * @min_valid_pri: combined min of valid pris
+ * @max_valid_pri: combined max of valid pris
+ * @max_radar_dur: combined max duration of radar patterns
+ * @first_pulse_ts: timestamp of first pulse after detector reset
+ * @last_pulse_ts: timestamp of last valid pulse
+ * @last_pulse_rssi: rssi of last pulse
+ *
+ * For global range checking dfs_pattern_detector instances are initialized
+ * with a pre-calculated set of global limits that combine the limits of
+ * all detector lines.
+ */
+struct pattern_detector_data {
+ u32 num_detector_elements;
+ struct detector_line *radar_detectors;
+ u32 min_valid_width;
+ u32 max_valid_width;
+ u32 min_valid_pri;
+ u32 max_valid_pri;
+ u32 max_radar_dur;
+ u64 first_pulse_ts;
+ u64 last_pulse_ts;
+ u32 last_pulse_rssi;
+};
+
+/**
+ * get_dfs_channel_idx - (private) find DFS channel index for given frequency
+ *
+ * @freq: frequency to search for
+ *
+ * Returns -1 if not found.
+ */
+static int get_dfs_channel_idx(u16 freq)
+{
+ int i;
+ for (i = 0; i < NUM_DFS_CHANNELS; i++)
+ if (dfs_channels[i] == freq)
+ return i;
+ return -1;
+}
+
+/**
+ * reset_detector_element - (private) reset one detector element
+ *
+ * @rs: radar statistics to reset
+ * @ts: time stamp to be reset to
+ *
+ * Resets the statistics for one pattern type of one channel. Sets the
+ * timestamp for the last valid pulse to given value.
+ */
+static void reset_detector_element(struct radar_stats *rs, u64 ts)
+{
+ memset(rs, 0, sizeof(struct radar_stats));
+ rs->last_ts = ts;
+}
+
+
+/**
+ * detector_reset - (private) reset all detector lines for a given channel
+ *
+ * @pd_data: instance data ptr
+ * @dfs_channel_idx: DFS channel index to be reset
+ *
+ * Resets the statistics for all pattern types of one given channel.
+ */
+static void detector_reset(struct pattern_detector_data *pd_data,
+ int dfs_channel_idx)
+{
+ int i;
+ u64 ts = pd_data->last_pulse_ts;
+ DTRACE();
+ for (i = 0; i < pd_data->num_detector_elements; i++) {
+ struct radar_stats *rs;
+ rs = &pd_data->radar_detectors[i].stats[dfs_channel_idx];
+ reset_detector_element(rs, ts);
+ }
+}
+
+
+/**
+ * check_pulse_lost - (private) check potentially lost pulses
+ *
+ * @rs: radar stats to be checked
+ * @delta_ts: pulse interval to be checked
+ *
+ * In case we missed some pulse '.' in a row of valid pulses '|', we try to
+ * reconstruct them by checking for delta_ts being a multiple of the pri.
+ *
+ * Assume we were fed with a pattern like
+ * | | . . |
+ * Evaluating the last pulse we check if the last interval is a multiple of our
+ * pri and in that case return 2 as the number of (potentially) lost pulses.
+ *
+ * The global check if the last interval exceeds the max duration of this
+ * pattern type is performed by the caller.
+ *
+ */
+static int check_pulse_lost(struct radar_stats *rs, u32 delta_ts)
+{
+ int lost_pulses = 0;
+
+ if (rs->pri_count == 1) {
+ /* check constant pri patterns */
+ u32 pri = rs->pri[0];
+ while (delta_ts > pri) {
+ /* we already checked that we are within valid duration
+ * => won't loop too long */
+ lost_pulses++;
+ delta_ts -= pri;
+ }
+
+ if (DELTA(pri, delta_ts) <= MAX_PRI_TOLERANCE)
+ return lost_pulses;
+
+ return 0;
+ } else {
+ /* TODO: check staggered radar patterns
+ here we need to support
+ * single burst / packet based and
+ * single burst / single pulse
+ staggered PRF radar test signals
+ */
+ }
+ return 0;
+}
+
+/**
+ * detector_check_match - (private) check for pattern match
+ *
+ * @rp: radar specs to be checked
+ * @rs: radar stats to be checked
+ * @delta_ts: pulse interval to be checked
+ *
+ * Returns 1 on match
+ */
+static int detector_check_match(struct radar_specs *rp, struct radar_stats *rs)
+{
+
+ if (rs->matching_pulse_count >= rp->ppb_thresh) {
+ DINIT("XXXXXXXXXXXXXXXXXXXXXXX MATCH on type %d", rp->type_id);
+ return 1;
+ }
+ return 0;
+}
+
+static int detector_check_pri(struct radar_specs *rp, struct radar_stats *rs,
+ u32 delta_ts)
+{
+ int lost_pulses;
+
+ int pri_num;
+ DLOG("OK: delta_ts=%d <= max_dur[%d]=%d",
+ delta_ts, rp->type_id, rp->max_dur);
+ for (pri_num = 0; pri_num < rs->pri_count; pri_num++) {
+ if (DELTA(delta_ts, rs->pri[pri_num]) < MAX_PRI_TOLERANCE) {
+ rs->matching_pulse_count++;
+ DLOG("delta_ts=%d matches pri_num[%d][%d] => "
+ "matching_pulse_count = %d", delta_ts,
+ rp->type_id, pri_num, rs->matching_pulse_count);
+ if (detector_check_match(rp, rs))
+ return 1;
+ /* we only take the first match */
+ return 0;
+ }
+ lost_pulses = check_pulse_lost(rs, delta_ts);
+ if (lost_pulses > 0) {
+ rs->matching_pulse_count += lost_pulses + 1;
+ DLOG("[%d] assuming %d lost pulses => "
+ "matching_pulse_count = %d",
+ rp->type_id, lost_pulses,
+ rs->matching_pulse_count);
+ if (detector_check_match(rp, rs))
+ return 1;
+ return 0;
+ }
+ DLOG("delta_ts=%d not multiple of [%d] = %d",
+ delta_ts, rp->type_id, rs->pri[0]);
+ reset_detector_element(rs, rs->last_ts);
+ return 0;
+
+ }
+ if (rs->pri_count >= rp->num_pri) {
+ rs->false_pulse_count++;
+ } else {
+ /* pri was not found in the current array, add it as new */
+ rs->pri[rs->pri_count++] = delta_ts;
+ rs->matching_pulse_count += 2;
+ DLOG("added new pri[%d][%d]=%d",
+ rp->type_id, rs->pri_count-1, delta_ts);
+ }
+ return 0;
+}
+
+static int detector_check_pulse_ts(struct radar_specs *rp,
+ struct radar_stats *rs, u64 ts)
+{
+ u32 delta_ts;
+
+ DTRACE();
+ delta_ts = ts - rs->last_ts;
+ DLOG("[%d]: ts=%llu, last_ts=%llu, delta_ts=%d, pri_min=%d, pri_max=%d,"
+ "max_dur=%d", rp->type_id, ts, rs->last_ts, delta_ts,
+ rp->pri_min, rp->pri_max, rp->max_dur);
+ if (delta_ts >= rp->pri_min) {
+ DLOG("OK: delta_ts >= pri_min");
+ if (delta_ts <= rp->max_dur) {
+ /* this one is for us */
+ rs->last_ts = ts;
+ return detector_check_pri(rp, rs, delta_ts);
+ } else {
+ DLOG("NOK: delta_ts=%d > max_dur[%d]=%d",
+ delta_ts, rp->type_id, rp->max_dur);
+ }
+ } else
+ DLOG("delta_ts=%d < pri_min[%d]=%d",
+ delta_ts, rp->type_id, rp->pri_min);
+ /* if for some reason this radar was not for me, safely reset stats
+ * since this pulse invalidates all previous
+ */
+ reset_detector_element(rs, ts);
+ return 0;
+}
+
+
+static u32 freq_to_usec(u32 freq)
+{
+ return (1000000 / freq);
+}
+
+/* percentage of ppb threshold to trigger detection */
+#define MIN_PPB_THRESH 66
+#define PPB_THRESH(X) ((X*MIN_PPB_THRESH + 50) / 100)
+
+static void dpd_exit(struct dfs_pattern_detector *_this)
+{
+ if (_this->data != NULL) {
+ if (_this->data->radar_detectors != NULL)
+ kfree(_this->data->radar_detectors);
+ kfree(_this->data);
+ }
+ kfree(_this);
+}
+
+static enum dfs_detector_result dpd_add_pulse(
+ struct dfs_pattern_detector *_this, struct pulse_event *event)
+{
+ int detector_result = NO_DETECTION;
+ struct pattern_detector_data *pd_data = _this->data;
+ u64 delta_ts = event->ts - pd_data->last_pulse_ts;
+ u32 width = event->width;
+ int dfs_channel_idx;
+ DTRACE();
+
+ DINFO("e->width=%d, e->ts=%llu, delta_ts=%llu, e->rssi=%d, e->freq=%d",
+ event->width, event->ts, delta_ts,
+ event->rssi, event->freq);
+
+ dfs_channel_idx = get_dfs_channel_idx(event->freq);
+ if (dfs_channel_idx < 0) {
+ DERROR("pulse_event.freq=%d is no DFS frequency, dropping");
+ return PULSE_DROPPED;
+ }
+
+ /* global condition checks */
+
+ /* condition: pulse width inside valid range? */
+ if ((width > pd_data->max_valid_width) ||
+ (width < pd_data->min_valid_width)) {
+ DINFO("pulse width %d outside valid range [%d, %d], dropping",
+ width, pd_data->min_valid_pri, pd_data->max_valid_pri);
+ return PULSE_DROPPED;
+ }
+
+ pd_data->last_pulse_ts = event->ts;
+
+ /* condition: pulse interval < max allowed pattern duration */
+ if (delta_ts > pd_data->max_radar_dur) {
+ DINFO("pulse with delta_ts=%llu > max_radar_dur=%d, resetting",
+ delta_ts, pd_data->max_radar_dur);
+ detector_reset(pd_data, dfs_channel_idx);
+ return NO_DETECTION;
+ }
+
+ /* condition: pulse interval larger that min allowed pri
+ * NOTE: we are not checking against max allowed pri to
+ * allow for coverage of multiple pris
+ */
+ if (delta_ts >= pd_data->min_valid_pri) {
+ int i;
+
+ /* do type individual pattern matching */
+ for (i = 0; i < pd_data->num_detector_elements; i++) {
+ struct radar_specs *rp;
+ rp = &pd_data->radar_detectors[i].specs;
+ /* condition: width within type specific width range */
+ if (width >= rp->width_min && width <= rp->width_max) {
+ struct radar_stats *rs;
+ rs = &pd_data->radar_detectors[i].
+ stats[dfs_channel_idx];
+ if (detector_check_pulse_ts(rp,
+ rs, event->ts)) {
+ detector_result = RADAR_DETECTED;
+ /* stop here, don't care if further
+ * patterns might also match */
+ break;
+ }
+ }
+ }
+ if (detector_result == RADAR_DETECTED) {
+ /* radar pattern found -> reset detector line */
+ detector_reset(pd_data, dfs_channel_idx);
+ }
+ return detector_result;
+ } else
+ DINFO("pulse with delta_ts=%llu outside valid pri-range "
+ "[%d, %d], resetting", delta_ts,
+ pd_data->min_valid_pri, pd_data->max_valid_pri);
+ return 0;
+}
+
+
+/* our base VFT */
+static struct dfs_pattern_detector dpd_default_vft = {
+ .exit = dpd_exit,
+ .add_pulse = dpd_add_pulse,
+};
+
+
+static void print_detector_specs(struct pattern_detector_data *pd_data)
+{
+ int i;
+ for (i = 0; i < pd_data->num_detector_elements; i++) {
+ struct radar_specs *rs = &pd_data->radar_detectors[i].specs;
+ DINIT("Initialized radar pattern type %d", i);
+ DINIT(" rs->type_id = %d", rs->type_id);
+ DINIT(" rs->width_min = %d", rs->width_min);
+ DINIT(" rs->width_max = %d", rs->width_max);
+ DINIT(" rs->pri_min = %d", rs->pri_min);
+ DINIT(" rs->pri_max = %d", rs->pri_max);
+ DINIT(" rs->num_pri = %d", rs->num_pri);
+ DINIT(" rs->ppb_thresh = %d", rs->ppb_thresh);
+ DINIT(" rs->max_dur = %d", rs->max_dur);
+ }
+ DINIT("valid ranges: width=[%d, %d], pri=[%d, %d], dur=%d",
+ pd_data->min_valid_width, pd_data->max_valid_width,
+ pd_data->min_valid_pri, pd_data->max_valid_pri,
+ pd_data->max_radar_dur);
+}
+
+
+/* allocate and initialize object data */
+static struct pattern_detector_data *setup_detector_data(struct radar_type *rt)
+{
+ int i;
+ struct pattern_detector_data *pd_data;
+ int sz = sizeof(struct pattern_detector_data);
+ pd_data = kmalloc(sz, GFP_KERNEL);
+ if (pd_data == NULL) {
+ DERROR("allocation of pattern_detector_data failed");
+ return NULL;
+ }
+
+ memset(pd_data, 0, sz);
+
+ sz = sizeof(struct detector_line) * rt->num_radar_types;
+ pd_data->radar_detectors = kmalloc(sz, GFP_KERNEL);
+ if (pd_data->radar_detectors == NULL) {
+ DERROR("allocation of radar_detectors failed");
+ return NULL;
+ }
+ memset(pd_data->radar_detectors, 0, sz);
+
+ pd_data->num_detector_elements = rt->num_radar_types;
+ pd_data->min_valid_width = (u32) -1;
+ pd_data->max_valid_width = 0;
+ pd_data->min_valid_pri = (u32) -1;
+ pd_data->max_valid_pri = 0;
+ pd_data->max_radar_dur = 0;
+
+ for (i = 0; i < rt->num_radar_types; i++) {
+ struct radar_signal_type *rst = &rt->radar_types[i];
+ struct radar_specs *rs = &pd_data->radar_detectors[i].specs;
+ DINIT("Initializing type %d", i);
+ rs->type_id = rst->type_id;
+ rs->width_min = rst->width_min;
+ rs->width_max = rst->width_max;
+ rs->pri_min = freq_to_usec(rst->pps_max) - MAX_PRI_TOLERANCE;
+ rs->pri_max = freq_to_usec(rst->pps_min) + MAX_PRI_TOLERANCE;
+ rs->num_pri = rst->num_pri;
+ rs->ppb = rst->ppb;
+ rs->ppb_thresh = PPB_THRESH(rst->ppb);
+ rs->max_dur = rs->pri_max * rst->ppb * rst->num_pri;
+
+ if (rs->width_min < pd_data->min_valid_width)
+ pd_data->min_valid_width = rs->width_min;
+ if (rs->width_max > pd_data->max_valid_width)
+ pd_data->max_valid_width = rs->width_max;
+ if (rs->pri_min < pd_data->min_valid_pri)
+ pd_data->min_valid_pri = rs->pri_min;
+ if (rs->pri_max > pd_data->max_valid_pri)
+ pd_data->max_valid_pri = rs->pri_max;
+ if (rs->max_dur > pd_data->max_radar_dur)
+ pd_data->max_radar_dur = rs->max_dur;
+ }
+ print_detector_specs(pd_data);
+ return pd_data;
+}
+
+
+struct dfs_pattern_detector *dfs_pattern_detector_init(
+ enum dfs_domain dfs_domain)
+{
+ int i;
+ struct dfs_pattern_detector *_this;
+ struct radar_type *rt;
+
+ /* find supported radar type */
+ for (i = 0; /* nothing */; i++) {
+ rt = supported_radar_types[i];
+ if (rt == NULL) {
+ DERROR("non-supported dfs-domain %d", dfs_domain);
+ return NULL;
+ }
+ if (rt->dfs_id == dfs_domain)
+ break;
+ }
+ /* allocate object instance */
+ _this = kmalloc(sizeof(struct dfs_pattern_detector), GFP_KERNEL);
+ if (_this == NULL) {
+ DERROR("allocation of dfs_pattern_detector failed");
+ return NULL;
+ }
+ *_this = dpd_default_vft;
+
+ /* allocate and initialize object data */
+ _this->data = setup_detector_data(rt);
+ if (_this->data == NULL) {
+ _this->exit(_this);
+ return NULL;
+ }
+ return _this;
+}
diff --git a/net/wireless/dfs/dfs_pattern_detector.h b/net/wireless/dfs/dfs_pattern_detector.h
new file mode 100644
index 0000000..940c8c9
--- /dev/null
+++ b/net/wireless/dfs/dfs_pattern_detector.h
@@ -0,0 +1,46 @@
+#ifndef DFS_PATTERN_DETECTOR_H
+#define DFS_PATTERN_DETECTOR_H
+
+#include "net/dfs.h"
+
+
+/**
+ * enum dfs_detector_result - DFS detector result after adding pulse
+ *
+ * Feeding a potential radar pulse to the detector might result in:
+ * @NO_DETECTION: pulse added, but no detection so far
+ * @RADAR_DETECTED: pulse added, pattern matched => radar detected
+ * @PULSE_DROPPED: pulse not added, outside valid pattern ranges
+ */
+enum dfs_detector_result {
+ NO_DETECTION,
+ RADAR_DETECTED,
+ PULSE_DROPPED,
+};
+
+/**
+ * struct dfs_pattern_detector - pseudo-OO DFS pattern detector class
+ *
+ * A DFS pattern detector object is instantiated with its constructor that
+ * returns ptr to initialized object.
+ *
+ * The VFT so far needs only two public methods:
+ * @exit: destructor
+ * @add_pulse: adds radar pulse to detector
+ *
+ * All data is private.
+ */
+struct dfs_pattern_detector {
+ /* VFT */
+ void (*exit)(struct dfs_pattern_detector *_this);
+ enum dfs_detector_result (*add_pulse)
+ (struct dfs_pattern_detector *_this, struct pulse_event *pe);
+
+ /* private data */
+ struct pattern_detector_data *data;
+};
+
+/* Constructor */
+struct dfs_pattern_detector *dfs_pattern_detector_init(enum dfs_domain);
+
+#endif /* DFS_PATTERN_DETECTOR_H */
diff --git a/net/wireless/dfs/dfs_radar_types.h b/net/wireless/dfs/dfs_radar_types.h
new file mode 100644
index 0000000..329d96c
--- /dev/null
+++ b/net/wireless/dfs/dfs_radar_types.h
@@ -0,0 +1,47 @@
+#ifndef DFS_RADAR_TYPES_H
+#define DFS_RADAR_TYPES_H
+
+#include "net/dfs.h"
+
+struct radar_signal_type {
+ unsigned int type_id;
+ unsigned int width_min;
+ unsigned int width_max;
+ unsigned int pps_min;
+ unsigned int pps_max;
+ unsigned int num_pri;
+ unsigned int ppb;
+};
+
+static struct radar_signal_type etsi_radar_ref_types_v15[] = {
+ { 0, 0, 1, 700, 700, 1, 18, },
+ { 1, 0, 5, 200, 1000, 1, 10, },
+ { 2, 0, 15, 200, 1600, 1, 15, },
+ { 3, 0, 15, 2300, 4000, 1, 25, },
+ { 4, 20, 30, 2000, 4000, 1, 20, },
+ { 5, 0, 2, 300, 400, 3, 10, },
+ { 6, 0, 2, 400, 1200, 3, 15, },
+};
+
+struct radar_type {
+ u32 dfs_id;
+ u32 num_radar_types;
+ struct radar_signal_type *radar_types;
+};
+
+static struct radar_type etsi_radar_types_v15 = {
+ .dfs_id = DFS_ETSI_DOMAIN,
+ .num_radar_types = sizeof(etsi_radar_ref_types_v15) /
+ sizeof(struct radar_signal_type),
+ .radar_types = etsi_radar_ref_types_v15,
+};
+
+
+static struct radar_type *supported_radar_types[] = {
+ &etsi_radar_types_v15,
+};
+
+
+
+#endif /* DFS_RADAR_TYPES_H */
+
--
1.5.4.3