RADAR
Contents
DFS with ath5k
- With a view to Dynamic Frequency Selection powered by RADAR PHY errors reported to the driver.
- ath5k aims to support the Atheros WiFi chipset on Linux.
Visualisation of RADAR activity
- Patched ath5k driver reports PHY error details to userspace via debugfs.
- Python daemon on Linux collects details, sweeps frequency ranges on-demand, and reports details to any connected client over the network.
- .NET GUI visualises legitimate WiFi packets and RADAR errors over frequency/time, plots histograms of pulse width, RSSI distribution, time between pulses, and draws time-series graphic to help uncover repetition rate within a sample of pulses.
Resources
- madwifi
- Atheros Chipsets
- ath5k on Linux Wireless
- ath5k-devel mailing list
- Enabling debugfs with ath5k
- (Low) power levels with AR5414
- Radar Detection notes on FreeBSD ath-hal
- Method and apparatus for physical layer radar pulse detection and estimation
Wikipedia:
Hardware
I use a Ubiquiti Networks SR4C (802.11a) with the ath5k driver in compat-wireless-2011-10-11.
It appears as:
ath5k phy0: Atheros AR5414 chip found (MAC: 0xa5, PHY: 0x61) version: 2
With some extra 'printk's, the full frequency range is revealed:
AR5K_EEPROM_HDR_11A: 0xa61 (min: 4920, max: 6100)
Important changes
There are some extra changes which enable the whole system to work. These are contained in the driver patch, and are described below.
Channel list
The patch enables all channels between 4.9 GHz and 6.1 GHz (depending on channel width), with 5 MHz spacing. A future improvement would be another mechanism where a specific frequency could be set that is not contained in the channel list that is constructed upon driver initialisation (i.e. currently, the setting of frequencies not in this list will fail).
all_channels: Default is 1
Take note of the follow changes:
static unsigned int
ath5k_setup_channels(struct ath5k_hw *ah, struct ieee80211_channel *channels,
unsigned int mode, unsigned int max) // ATH_CHAN_MAX when !CHAN_DEBUG
{
unsigned int count, size, freq, ch;
enum ieee80211_band band;
switch (mode) {
case AR5K_MODE_11A:
/* 1..220, but 2GHz frequencies are filtered by check_channel */
size = 220 + (196-182+1) + 9+3 + 4+4;
band = IEEE80211_BAND_5GHZ;
break;
case AR5K_MODE_11B:
case AR5K_MODE_11G:
size = 26;
band = IEEE80211_BAND_2GHZ;
break;
default:
ATH5K_WARN(ah, "bad mode, not copying channels\n");
return 0;
}
count = 0;
for (ch = 1; ch <= size && count < max; ch++) {
if (ch <= 220)
freq = ieee80211_channel_to_frequency(ch, band);
else if (ch <= (220 + 15)) { // 5910 -> 5980 (15)
freq = 5000 + (ch - 221 + 182) * 5;
}
else if (ch <= (220 + 15 + 9+3)) { // 4920+2.5 -> 4985+2.5 but not whole (9)
int i = ch - (220 + 15);
freq = 49200;
do {
freq += 25;
if (((freq % 100) == 0) || ((freq % 100) == 50))
freq += 25;
} while (--i);
freq /= 10;
}
else if (ch <= (220 + 15 + 9+3 + 4+4)) { // 4990+2.5 -> 5000 (4)
freq = (49800 + (25 * (ch - (220 + 15 + 9+3)))) / 10;
}
else // Fallback
freq = ieee80211_channel_to_frequency(ch, band);
if (freq == 0) { /* mapping failed - not a standard channel */
printk("Not a standard channel: %d\n", ch);
continue;
}
/* Write channel info, needed for ath5k_channel_ok() */
channels[count].center_freq = freq;
channels[count].band = band;
channels[count].hw_value = mode;
/* Check if channel is supported by the chipset */
if (!ath5k_channel_ok(ah, &channels[count])) {
//if (ah->debug.level & ATH5K_DEBUG_DUMPBANDS)
printk("Channel NOT OK: %d %d\n", ch, channels[count].center_freq);
continue;
}
if (!modparam_all_channels &&
!ath5k_is_standard_channel(ch, band))
continue;
count++;
}
printk("Set up %d channels\n", count);
return count;
}
Regulatory domain
There are other changes, but these main ones open up all the channels for use:
#define ATH5K_ALL REG_RULE(4920-10, 6100+10, 20, 0, /*23*//*0*/40, /*NL80211_RRF_PASSIVE_SCAN*/NL80211_RRF_DFS)
static const struct ieee80211_regdomain ath_all = {
.n_reg_rules = 2,
.alpha2 = "99",
.reg_rules = {
ATH5K_ALL,
}
};
static const struct ieee80211_regdomain *ath_default_world_regdomain(void)
{
/* this is the most restrictive */
return &/*ath_world_regdom_64*/ath_all;
}
Additional module arguments
default_bwmode: 0: 20MHz 1: 10MHz 2: 5MHz
default_countrycode: Values from CTRY_* enum.
Kismet compatability
This patched driver works well with Kismet. Just use one of the following 'channellist's:
All channels:
channellist=ath5k_all:4920,4922,4925,4927,4930,4932,4935,4937,4940,4942,4945,4947,4950,4952,4955,4957,4960,4962,4965,4967,4970,4972,4975,4977,4980,4982,4985,4987,4990,4992,4995,4997,range-5000-6100-20-5
Normal channels (not Public Safety):
channellist=notps:range-5000-6100-20-5
Only Public Safety:
channellist=ps:4920,4922,4925,4927,4930,4932,4935,4937,4940,4942,4945,4947,4950,4952,4955,4957,4960,4962,4965,4967,4970,4972,4975,4977,4980,4982,4985,4987,4990,4992,4995,4997,5000
Files
ath5k Linux kernel driver patch
This is a diff against compat-wireless-2011-10-11. I had to apply some additional patches/fixes to enable it to compile against my existing kernel (2.6.26 x86):
- 022-atomic64_backport.patch is in the root directory in case you need it too (but is not applied by my driver patch).
My config.mk:
diff compat-wireless-2011-10-11.orig/config.mk compat-wireless-2011-10-11/config.mk
224c224
< # CONFIG_ATH5K_DEBUG=y
---
> CONFIG_ATH5K_DEBUG=y
615c615
< # CONFIG_ATH_DEBUG=y
---
> CONFIG_ATH_DEBUG=y
NOTE: Debug mode is necessary for the information to be passed to userland via debugfs!
Also add to fstab:
none /sys/kernel/debug debugfs
And make sure debugfs is enabled in your kernel!
To ready the interface:
sudo iwconfig wlan0 mode Monitor sudo ifconfig wlan0 up
You can optionally (manually) set a frequency if you want to watch /sys/kernel/debug/ieee80211/phy0/ath5k/radar:
sudo iwconfig wlan0 freq 5800M
To specify alternate channel width:
sudo modprobe ath5k default_bwmode=[0: 20MHz, 1: 10MHz, 2: 5MHz]
To remove it for restart:
sudo modprobe -r ath5k ath mac80211 cfg80211 compat
Python
Two types:
- TCP server for GUI
- Stand-alone for console
They have plenty of command-line arguments, so remember to check them with '-h'.
Both scripts rely on knowning how to decode the RADAR error struct passed down from the kernel. If this is different for you from the default, make sure you update these scripts!
The RADAR queue length must match the driver's one (2048 by default, can be change as command-line argument).
And
struct ath5k_radar_error {
u32 tsf;
u8 rssi;
u8 width; // 0 for WiFi frame
u8 type; // 0: WiFi frame (no error), 1: RADAR PHY error
u8 subtype; // For type 0: 0; type 1: rs_rate
};
must match:
sizeof_radar_error = 4+1+1+1+1
and
item = struct.unpack("Icccc"...
(and also the way it is used by the radar_error class).
Server
Usage: radar_server.py: [options] Options: -h, --help show this help message and exit -P PORT, --port=PORT server port [default=5256] -l QUEUE_LENGTH, --queue-length=QUEUE_LENGTH radar error queue length [default=2048] -d DEV, --dev=DEV device [default=wlan0] -p PHY, --phy=PHY device [default=phy0] --progress show progress [default=False]
All frequencies are in MHz (e.g. 5500). Sweep range can go backwards.
Simple plain-text line-based protocol:
FREQ <freq>
Thresholds (as in driver, see patch for details, or here (AR5212 radar detection notes on FreeBSD ath-hal)):
FIRPWR <pwr> RSSI <rssi> PHEIGHT <height> PRSSI <rssi> INBAND <threshold> START [start freq: 4920] [end freq: 6100] [freq step: 5] [sampling interval in seconds, can be floating point: 1] STOP
To continually scan one frequency, use same start and end frequency.
To terminate (will stop active sweep):
QUIT or EXIT
or just disconnect.
Details are sent back as:
DATA <freq> <Base64 encoded list of RADAR error structs>
Stand-alone console
Usage: radar.py: [options] Options: -h, --help show this help message and exit -s START, --start=START start freq [default=4920] -e END, --end=END end freq [default=6100] -S STEP, --step=STEP freq step [default=5] -d DEV, --dev=DEV device [default=wlan0] -p PHY, --phy=PHY device [default=phy0] -i INTERVAL, --interval=INTERVAL sample interval [default=2] -c, --current don't change current WiFi settings [default=False] --short show statistics in short form [default=False]
Will scan and output statistics to console (see Python script for output format). Also dumps various histograms to disk (CSV files).
Excerpt from output:
... 5620 MHz: - 5625 MHz: - 5630 MHz: 0039 in 1063604 us - RSSI: 20.4 +/- 7.2 [015-030], Width: 1st: 0000 #0000, 2nd: 0000 #0000 [imm: 0039, unk: 0000 (0.0 +/- 0.0 [256--01]), Time Diff: 1st: 3004 #0004, 2nd: 1006 #0002 (27989.6 +/- 79650.4 [994-382388]) 5635 MHz: 0006 in 135130 us - RSSI: 28.8 +/- 4.3 [021-035], Width: 1st: 0004 #0004, 2nd: 0011 #0001 [imm: 0000, unk: 0000 (5.3 +/- 2.6 [004-011]), Time Diff: 1st: 3010 #0001, 2nd: 12014 #0001 (27026.0 +/- 39315.9 [1502-105082]) 5640 MHz: - 5645 MHz: - ...
GUI
The GUI runs under .NET and uses ZedGraph (reference DLL included). You will need to run the Python server on your Linux box with the WiFi card and be able to connect to it over your network.
Screenshots may be seen below.
Pre-compiled binaries are included in the download, so you don't need to compile the source. However, if you decide to compile the project, you will have to point the ZedGraph and TehLib.NET references to the DLLs in the '_References' directory.
Monitoring RADAR detection in the console
Type:
watch -n 1 "cat /sys/kernel/debug/ieee80211/phy0/ath5k/radar"
to get:
Every 1.0s: cat /sys/kernel/debug/ieee80211/phy0/ath/radar RADAR detection enabled: 1 RADAR PHY error filter: 0 Filter output power threshold: 44 (44) Pulse height threshold: 28 RADAR RSSI threshold: 15 Pulse RSSI threshold: 58 In-band threshold: 9 RADAR error queue usage: 0/2048 (start: 0, overflows: 0) RADAR errors: 0 PHY errors: 0 Other errors: 0 Frames: 0 Width: 0: 0 1-50: 0 51-100: 0 101-150: 0 151-200: 0 201-250: 0 251-254: 0 255: 0
Manually setting RADAR detection parameters
For example (adjust depending on your interface index):
echo "firpwr -60" > /sys/kernel/debug/ieee80211/phy0/ath5k/radar echo "rssi 1" > /sys/kernel/debug/ieee80211/phy0/ath5k/radar echo "pheight 1" > /sys/kernel/debug/ieee80211/phy0/ath5k/radar echo "prssi 1" > /sys/kernel/debug/ieee80211/phy0/ath5k/radar echo "inband 31" > /sys/kernel/debug/ieee80211/phy0/ath5k/radar
Spectrum Sweep
20 MHz channel width
- Notice how RADAR errors are reported either side of a legitimate WiFi channel:
10 MHz channel width
- No WiFi operating at this channel width:
5 MHz channel width
- Some WiFi operating at this narrow channel width:
Kurnell Weather RADAR
- Registered as a Bureau of Meteorology Weather RADAR: http://www-cluster.bom.gov.au/inside/oeb/radar/sydney.shtml
- Registered on RFMap:
- 5.625 GHz (1.1 MHz bandwidth at 250 kW)
- Following data was received on ~5500/~5600 MHz
- One can infer the rotation rate of the RADAR by examining the difference in time, especially in the 'Counts' (number of reported RADAR PHY errors) over time:
- Average RSSI decreases a little in each 'transmission section' (separated by the pause in-between), however decrease is most noticable in the maximum value per sample-group:
- Not sure why the distribution of widths changes later (was this when my laptop was knocked off its perch by the wind?!):
- Whatever the change above, it is also reflected here:
- 1kHz PRF
- You can see that the five highest bins (which hold counts for the distinct times between detected RADAR pulses) have values of ~1000. The time-series plot shows the regular repetition:
- 5kHz PRF
- As above, however this time it's ~5000:
- This is also reflected in the time-between-pulses histogram:
ISM
- Indoors, the sweep looks quite different:
- Notice the significant response at 5800MHz. Could this be DECT nearby?
- Examing the time-series plot of RSSI for 5800MHz clearly shows a regular, repeating group of pulses (not as apparent due to the colouring on the width plot as the pulse widths seem to be changing moreso, however the time-between pulses is identical):
5140 MHz
- No idea what this is, however it appears rather regular (also note the regular pauses between groups of RADAR errors):
|