Merge pull request #51 from open-sdr/pre-release

802.11n feature and dual antenna IQ capture and other bug fixes
This commit is contained in:
Jiao Xianjun 2020-12-17 22:18:45 +01:00 committed by GitHub
commit 16da9d05c7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 2631 additions and 98 deletions

View File

@ -13,8 +13,7 @@ Openwifi code has dual licenses. AGPLv3 is the opensource license. For non-opens
**Features:**
- 802.11a/g
- 802.11n MCS 0~7 (Only PHY rx for now. Full system support of 802.11n will come soon)
- 802.11a/g/n [[IEEE 802.11n (Wi-Fi 4)](doc/app_notes/ieee80211n.md)]
- 20MHz bandwidth; 70 MHz to 6 GHz frequency range
- Mode tested: Ad-hoc; Station; AP, Monitor
- DCF (CSMA/CA) low MAC layer in FPGA (10us SIFS is achieved)
@ -26,7 +25,7 @@ Openwifi code has dual licenses. AGPLv3 is the opensource license. For non-opens
- 2MHz for 802.11ah in sub-GHz
- 10MHz for 802.11p/vehicle in 5.9GHz
- CSI (Channel State Information, freq offset, equalizer to computer) [[CSI notes](doc/app_notes/csi.md)]
- IQ capture (real-time AGC, RSSI, IQ sample to computer) [[IQ notes](doc/app_notes/iq.md)]
- IQ capture (real-time AGC, RSSI, IQ sample to computer) [[IQ notes](doc/app_notes/iq.md)][[IQ notes for dual antenna](doc/app_notes/iq_2ant.md)]
- On roadmap: **802.11ax**
**Performance (AP: openwifi at channel 44, client: TL-WDN4200 N900 USB Dongle):**

BIN
doc/app_notes/40mhz.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 KiB

View File

@ -5,3 +5,6 @@ Application notes collect many small topics about using openwifi in different sc
- [Communication between two SDR boards under ad-hoc mode](ad-hoc-two-sdr.md)
- [From CSI (Channel State Information) to CSI (Chip State Information)](csi.md)
- [Capture IQ sample, AGC gain, RSSI with many types of trigger condition](iq.md)
- [Capture dual antenna IQ for multi-purpose (capture collision)](iq_2ant.md)
- [IEEE 802.11n (Wi-Fi 4)](ieee80211n.md)
- [802.11 packet injection](inject_80211.md)

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -0,0 +1,53 @@
## IEEE 802.11n (Wi-Fi 4)
The 4th generation of Wi-Fi (i.e. 802.11n-2009) is a generation leap over its predecessor Wi-Fi 3 (i.e. 802.11g-2003). It was coined as high throughput (HT) since it improves both the physical layer and the MAC layer.
### PHY layer improvements
At the physical layer, 5 major improvements were amended on top of Wi-Fi 3 and this has increased the throughput from 54Mbps to 600Mbps.
#### More subcarriers
Wi-Fi 3 utilizes 48 OFDM data subcarriers and Wi-Fi 4 increased this number to 52, thereby increasing the throughput to 52/48 * 54Mbps = 58.5Mbps.
![](./subcarriers.png)
#### Forward error correction
The most efficient coding rate used in Wi-Fi 3 was 3/4 but Wi-Fi increased this value to 5/6 by squeezing more bits. This has increased the throughput to (5/6)/(3/4) * 58.5Mbps = 65Mbps.
#### Guard interval
As a measure to combat inter-symbol interference (ISA), Wi-Fi 3 utilizes 800nsec of guard interval between consecutive OFDM symbols. Wi-Fi 4 shortens this value to 400nsec, and this has increased the throughput to 4usec/3.6usec * 65Mbps = 72.2Mbps.
![](./guard-interval.png)
#### MIMO
Wi-Fi 4 was the first to introduce MIMO and standardized 4x4 spatial streams. This has quadrupled the throughput to 4*72.2Mbps = 288.9Mbps.
![](./mimo.png)
#### 40MHz bandwidth
The last thing Wi-Fi 4 introduced to the physical layer is a 40MHz bandwidth utilizing 108 OFDM data subcarriers. This has increased the throughput to 108/52 * 288.8Mbps = 600 Mbps.
![](./40mhz.png)
### MAC layer improvements
On top of the PHY layer improvements, Wi-Fi 4 also introduced frame aggregation at the MAC layer to ease the medium access contention. Two types of frame aggregation are used in Wi-Fi 4; A-MPDU and A-MSDU. While A-MSDU is efficient in medium occupation, a single packet error will make the whole frame unusable and require complete retransmission. However, A-MPDU aggregates multiple MPDUs by adding headers to each packet and a single packet error only requires single packet retransmission. As such, A-MPDU gained traction.
![](./mpdu-aggr.png)
## Supported openwifi 802.11n amendments
- 52 subcarriers
- 5/6 code rates
- 400nsec short guard interval.
Current theoretical throughput = 72.2Mbps.
## To be supported openwifi 802.11n amendments
- Frame aggregation
## Not supported openwifi 802.11n amendments
- MIMO
- 40MHz bandwidth

View File

@ -0,0 +1,86 @@
## 802.11 packet injection
The Linux wireless networking stack (i.e. driver, mac80211, cfg80211, net_dev, user app) is a robust implementation supporting a plethora of wireless devices. As robust as it is, it also has a drawback when it comes to single-layer testing.
Ping and Iperf are well established performance measurement tools. However, using such tools to measure 802.11 PHY performance can be misleading, simply because they touch multiple layers in the network stack.
Luckily, the mac80211 Linux subsystem provides packet injection functionality and it allows us to have finer control over physical layer testing.
To this end, we have adapted a [packetspammer](https://github.com/gnychis/packetspammer) application originally written by Andy Green <andy@warmcat.com> and maintained by George Nychis <gnychis@gmail.com>.
### inject_80211
Userspace program to inject 802.11 packets through mac80211 supported (softmac) wireless devices.
### Options
```
-m/--hw_mode <hardware operation mode> (a,g,n)
-r/--rate_index <rate/MCS index> (0,1,2,3,4,5,6,7)
-i/--sgi_flag (0,1)
-n/--num_packets <number of packets>
-s/--payload_size <payload size in bytes>
-d/--delay <delay between packets in usec>
-h this menu
```
### Example:
```
iw dev wlan0 interface add mon0 type monitor && ifconfig mon0 up
inject_80211 -m n -r 0 -n 64 -s 100 mon0 # Inject 10 802.11n packets at 6.5Mbps bitrate and 64bytes size
```
### Link performance test
To make a profound experimental analysis on the physical layer performance, we can rely on automation scripts.
The following script will inject 100 802.11n packets at different bitrates and payload sizes.
```
#!/bin/bash
HW_MODE='n'
COUNT=100
DELAY=1000
RATE=( 0 1 2 3 4 5 6 7 )
SIZE=( $(seq -s' ' 50 100 1450) ) # paload size in bytes
IF="mon0"
for (( i = 0 ; i < ${#PAYLOAD[@]} ; i++ )) do
for (( j = 0 ; j < ${#RATE[@]} ; j++ )) do
inject_80211 -m $HW_MODE -n $COUNT -d $DELAY -r ${RATE[$j]} -s ${SIZE[$i]} $IF
sleep 1
done
done
```
On the receiver side, we can use tcpdump to collect the pcap traces.
```
iw dev wlan0 interface add mon0 type monitor && ifconfig mon0 up
tcpdump -i mon0 -w trace.pcap 'wlan addr1 ff:ff:ff:ff:ff:ff and wlan addr2 66:55:44:33:22:11'
```
Wlan addresses *ff:ff:ff:ff:ff:ff* and *66:55:44:33:22:11* are specific to our injector application.
Next, we analyze the collected pcap traces using the analysis tool provided.
```
analyze_80211 trace.pcap
```
An excerpt from a sample analysis looks the following
```
HW MODE RATE(Mbps) SGI SIZE(bytes) COUNT Duration(sec)
======= ========== === =========== ===== =============
802.11n 6.5 OFF 54 100 0.11159
802.11n 13.0 OFF 54 100 0.11264
802.11n 19.5 OFF 54 100 0.11156
802.11n 26.0 OFF 54 100 0.11268
802.11n 39.0 OFF 54 100 0.11333
802.11n 52.0 OFF 54 100 0.11149
802.11n 58.5 OFF 54 100 0.11469
802.11n 65.0 OFF 54 100 0.11408
```

View File

@ -12,7 +12,7 @@ We implement the **IQ sample capture** with interesting extensions: many **trigg
./monitor_ch.sh sdr0 11
(Monitor on channel 11. You can change 11 to other channel that is busy)
insmod side_ch.ko iq_len_init=8187
(for zed, adrv9364z7020, zc702 board, 8187 should be 4095 because they have smaller FPGA)
(for smaller FPGA (7Z020), iq_len_init should be <4096, like 4095, instead of 8187)
./side_ch_ctl wh11d4094
(Above command is needed only when you run with zed, adrv9364z7020, zc702 board)
@ -25,13 +25,13 @@ We implement the **IQ sample capture** with interesting extensions: many **trigg
loop 128 side info count 99
...
```
If the second number (61, 99, ...) is not zero and keeps increasing, that means the IQ sample is going to the computer smoothly.
If the second number (side info count 61, 99, ...) keeps increasing, that means the trigger condition is met from time to time and the IQ sample is going to the computer smoothly.
- Open another terminal on the computer, and run:
```
cd openwifi/user_space/side_ch_ctl_src
python3 iq_capture.py
(for zed, adrv9364z7020, zc702 board, add 4095 as parameter!)
(for zed, adrv9364z7020, zc702 board, add argument that euqals to iq_len_init, like 4095)
```
The python script needs "matplotlib.pyplot" and "numpy" packages installed. Now you should see 3 figures showing run-time **IQ sample**, **AGC gain and lock status** and **RSSI (uncalibrated)**. Meanwhile the python script prints the **timestamp**.
@ -47,10 +47,10 @@ We implement the **IQ sample capture** with interesting extensions: many **trigg
For each element, the actual size is 64bit.
- timestamp: 64bit TSF timer value when the capture is triggered.
- IQ
- The first two 16bit are used for I/Q sample
- The first two 16bit are used for I/Q sample from the antenna currently used
- The 3rd 16bit is AD9361 AGC gain (bit7 -- lock/unlock; bit6~0 -- gain value)
- The 4th 16bit is RSSI (half dB, uncalibrated). Please check xpu.v and sdr.c to understand how the raw RSSI value is finally calibrated and reported to Linux mac80211.
The python and Matlab scripts are recommended for you to understand the IQ packet format precisely.
## Config the IQ capture and interval
@ -67,7 +67,7 @@ We implement the **IQ sample capture** with interesting extensions: many **trigg
```
./side_ch_ctl wh8dY
```
The parameter **Y** specifies the trigger condition. Valid range 0 ~ 15, which is explained in this table.
The parameter **Y** specifies the trigger condition. Valid range 0 ~ 31, which is explained in this table.
value|meaning
-----|-------
@ -87,6 +87,22 @@ We implement the **IQ sample capture** with interesting extensions: many **trigg
13|AD9361 AGC from unlock to lock
14|AD9361 AGC gain goes above the threshold
15|AD9361 AGC gain goes below the threshold
16|phy_tx_started signal from openofdm tx core
17|phy_tx_done signal from openofdm tx core
18|positive edge of tx_bb_is_ongoing from xpu core
19|negative edge of tx_bb_is_ongoing from xpu core
20|positive edge of tx_rf_is_ongoing from xpu core
21|negative edge of tx_rf_is_ongoing from xpu core
22|phy_tx_started and this tx packet needs ACK
23|phy_tx_done and this tx packet needs ACK
24|positive edge of tx_bb_is_ongoing and this tx packet needs ACK
25|negative edge of tx_bb_is_ongoing and this tx packet needs ACK
26|positive edge of tx_rf_is_ongoing and this tx packet needs ACK
27|negative edge of tx_rf_is_ongoing and this tx packet needs ACK
28|tx_bb_is_ongoing and I/Q amplitude from the other antenna is above rssi_or_iq_th
29|tx_rf_is_ongoing and I/Q amplitude from the other antenna is above rssi_or_iq_th
30|start tx, meanwhile I/Q amplitude from the other antenna is above rssi_or_iq_th
31|start tx and need for ACK, meanwhile I/Q amplitude from the other antenna is above rssi_or_iq_th
To set the RSSI threshold
```
@ -112,7 +128,7 @@ We implement the **IQ sample capture** with interesting extensions: many **trigg
```
insmod side_ch.ko iq_len_init=3000
```
Here 3000 is an example. **ATTENTION:** You need to specify **iq_len_init** explicitly to turn on IQ capture, which will turn off CSI. Insert the side_ch.ko without any parameter will run CSI mode.
Here 3000 is an example. **ATTENTION:** You need to specify **iq_len_init** explicitly to turn on IQ capture, which will turn off the default CSI mode. Insert the side_ch.ko without any parameter will run the default CSI mode.
- When launch the python script, use:
```
python3 iq_capture.py 3000

53
doc/app_notes/iq_2ant.md Normal file
View File

@ -0,0 +1,53 @@
Instead of [**normal IQ sample capture**](iq.md), this app note introduce how to enable the I/Q capture for dual antenna. In this dual antenna mode, the RSSI and AGC status won't be captured as in the normal mode. Instead, they are replaced by the I/Q samples from the other antenna. But you are suggested to read the [**normal IQ sample capture**](iq.md) to understand how do we use the side channel to capture I/Q sample by different trigger conditions.
In this app note, we show how to use the dual antenna I/Q capture to capture the collision.
## Quick start
The currently selected antenna (rx0 by default if you do not select explicitly by set_ant.sh) is always used for communication and I/Q capture. Meanwhile, the other antenna (rx1) will be also avaliable for capturing rx I/Q if you are using AD9361 based RF board, such as fmcomms2/3 and adrv9361z7035, by turning on the **dual antenna capture** mode. In this case, you can place the other antenna (rx1) close to the communication peer (for example, the other WiFi node) to capture the potential collision by monitoring rx1 I/Q. The nature of collision is that both sides of a communication link are trying to do transmission at the same time.
The collision capture steps:
- Change rx1 AGC to manual mode instead of fast_attack in rf_init.sh by:
```
echo manual > in_voltage1_gain_control_mode
```
- Change rx1 gain to a low level, such as 20, by:
```
echo 20 > in_voltage1_hardwaregain
```
- Use the new rf_init.sh script to boot up the SDR board, and setup the working scenario.
- Setup the side channel:
```
insmod side_ch.ko iq_len_init=8187
(iq_len_init should be <4096, like 4095, if smaller FPGA, like z7020, is used)
./side_ch_ctl wh11d2000
(Set a smaller pre_trigger_len 2000, because we want to see what happens after the trigger instead of long period stored before the trigger)
```
- Put the other antenna (rx1) close to the peer WiFi node, set trigger condition to 23 (baseband tx done)
```
./side_ch_ctl wh8d23
```
- Enable the **dual antenna capture** mode
```
./side_ch_ctl wh3h11
```
- Run some traffic between the SDR board and the peer WiFi node, and start the user space I/Q capture program
```
./side_ch_ctl g
```
If the printed "**side info count**" is increasing, it means the trigger condition is met from time to time.
- On remote computer, run
```
python3 iq_capture_2ant.py
(if smaller FPGA, like z7020, is used, add a argument that equals to iq_len_init, like 4095)
```
Above script will plot the real-time rx0 and rx1 I/Q captured each time trigger condition met. Meanwhile the script also prints the maximum amplitutde of the rx0 and rx1 I/Q samples. Check the 3rd column that is displayed by the script: Those small value printing indicate noise (most probably, because the rx1 gain is very low). The big value printing indicate a packet from rx1 (although rx1 has very low gain, rx1 is very close to the peer WiFi node). Go through the noise and the packet max I/Q amplitude numbers from rx1 printing (the 3rd column), and decide a threshold value that is significantly higher than the noise but less than those big values (packets).
- Set trigger condition to 29, which means that rx1 I/Q is found larger than a threshold while SDR is transmitting -- this means a collision condition is captured because rx1 I/Q implies the transmitting from the peer WiFi node. The threshold value is decided in the previous step (2500 is assumed here).
```
(Quit side_ch_ctl by Ctrl+C)
./side_ch_ctl wh8d29
./side_ch_ctl wh9d2500
./side_ch_ctl g
```
- Now the trigger condition can capture the case where both sides happen to transmit in an overlapped duration. If the printed "**side info count**" is increasing, it means the collision happens from time to time.
- You can also see it via iq_capture_2ant.py or do offline analysis by test_iq_2ant_file_display.m
- Check the **iq1** signal in FPGA ILA/probe (triggered by signal "iq_trigger") for further debug if you want to know what exactly happened when collision is captured.

BIN
doc/app_notes/mimo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

BIN
doc/app_notes/mpdu-aggr.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

View File

@ -245,6 +245,7 @@ const char *xpu_compatible_str = "sdr,xpu";
#define XPU_REG_TSF_LOAD_VAL_LOW_ADDR (2*4)
#define XPU_REG_TSF_LOAD_VAL_HIGH_ADDR (3*4)
#define XPU_REG_BAND_CHANNEL_ADDR (4*4)
#define XPU_REG_DIFS_ADVANCE_ADDR (5*4)
#define XPU_REG_RSSI_DB_CFG_ADDR (7*4)
#define XPU_REG_LBT_TH_ADDR (8*4)
#define XPU_REG_CSMA_DEBUG_ADDR (9*4)
@ -337,6 +338,9 @@ struct xpu_driver_api {
void (*XPU_REG_BAND_CHANNEL_write)(u32 value);
u32 (*XPU_REG_BAND_CHANNEL_read)(void);
void (*XPU_REG_DIFS_ADVANCE_write)(u32 value);
u32 (*XPU_REG_DIFS_ADVANCE_read)(void);
u32 (*XPU_REG_TRX_STATUS_read)(void);
u32 (*XPU_REG_TX_RESULT_read)(void);

View File

@ -85,7 +85,7 @@ static inline u32 hw_init(enum openofdm_tx_mode mode){
for (i=0;i<8;i++)
openofdm_tx_api->OPENOFDM_TX_REG_MULTI_RST_write(0);
openofdm_tx_api->OPENOFDM_TX_REG_INIT_PILOT_STATE_write(0x7E);
openofdm_tx_api->OPENOFDM_TX_REG_INIT_PILOT_STATE_write(0x7F);
openofdm_tx_api->OPENOFDM_TX_REG_INIT_DATA_STATE_write(0x7F);
printk("%s hw_init err %d\n", openofdm_tx_compatible_str, err);

View File

@ -148,7 +148,9 @@ static void ad9361_rf_set_channel(struct ieee80211_hw *dev,
} else {
priv->rssi_correction = 148;
}
xpu_api->XPU_REG_LBT_TH_write((priv->rssi_correction-62)<<1);
// xpu_api->XPU_REG_LBT_TH_write((priv->rssi_correction-62)<<1); // -62dBm
xpu_api->XPU_REG_LBT_TH_write((priv->rssi_correction-62-16)<<1); // wei's magic value is 135, here is 134 @ ch 44
if (actual_rx_lo < 2500) {
//priv->slot_time = 20; //20 is default slot time in ERP(OFDM)/11g 2.4G; short one is 9.
@ -313,7 +315,7 @@ static irqreturn_t openwifi_rx_interrupt(int irq, void *dev_id)
struct ieee80211_rx_status rx_status = {0};
struct sk_buff *skb;
struct ieee80211_hdr *hdr;
u32 addr1_low32=0, addr2_low32=0, addr3_low32=0, len, rate_idx, tsft_low, tsft_high, loop_count=0, ht_flag;//;//, fc_di;
u32 addr1_low32=0, addr2_low32=0, addr3_low32=0, len, rate_idx, tsft_low, tsft_high, loop_count=0, ht_flag, short_gi;//, fc_di;
// u32 dma_driver_buf_idx_mod;
u8 *pdata_tmp, fcs_ok, target_buf_idx;//, phy_rx_sn_hw;
s8 signal;
@ -337,6 +339,8 @@ static irqreturn_t openwifi_rx_interrupt(int irq, void *dev_id)
len_overflow = (len>(RX_BD_BUF_SIZE-16)?true:false);
rate_idx = (*((u16*)(pdata_tmp+14)));
short_gi = ((rate_idx&0x20)!=0);
rate_idx = (rate_idx&0xDF);
fcs_ok = ( len_overflow?0:(*(( u8*)(pdata_tmp+16+len-1))) );
@ -345,9 +349,8 @@ static irqreturn_t openwifi_rx_interrupt(int irq, void *dev_id)
// dma_driver_buf_idx_mod = (state.residue&0x7f);
fcs_ok = ((fcs_ok&0x80)!=0);
ht_flag = ((rate_idx&0x10)!=0);
rate_idx = (rate_idx&0xF);
if ( (len>=14 && (!len_overflow)) && (rate_idx>=8 && rate_idx<=15)) {
if ( (len>=14 && (!len_overflow)) && (rate_idx>=8 && rate_idx<=23)) {
// if ( phy_rx_sn_hw!=dma_driver_buf_idx_mod) {
// printk("%s openwifi_rx_interrupt: WARNING sn %d next buf_idx %d!\n", sdr_compatible_str,phy_rx_sn_hw,dma_driver_buf_idx_mod);
// }
@ -386,7 +389,7 @@ static irqreturn_t openwifi_rx_interrupt(int irq, void *dev_id)
sc = hdr->seq_ctrl;
if ( addr1_low32!=0xffffffff || addr1_high16!=0xffff )
printk("%s openwifi_rx_interrupt:%4dbytes ht%d %2dM FC%04x DI%04x addr1/2/3:%04x%08x/%04x%08x/%04x%08x SC%04x fcs%d buf_idx%d %ddBm\n", sdr_compatible_str,
printk("%s openwifi_rx_interrupt:%4dbytes ht%d %3dM FC%04x DI%04x addr1/2/3:%04x%08x/%04x%08x/%04x%08x SC%04x fcs%d buf_idx%d %ddBm\n", sdr_compatible_str,
len, ht_flag, wifi_rate_table[rate_idx], hdr->frame_control, hdr->duration_id,
reverse16(addr1_high16), reverse32(addr1_low32), reverse16(addr2_high16), reverse32(addr2_low32), reverse16(addr3_high16), reverse32(addr3_low32),
sc, fcs_ok, target_buf_idx_old, signal);
@ -408,8 +411,13 @@ static irqreturn_t openwifi_rx_interrupt(int irq, void *dev_id)
rx_status.flag |= RX_FLAG_MACTIME_START;
if (!fcs_ok)
rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
rx_status.encoding = RX_ENC_LEGACY;
if (rate_idx <= 15)
rx_status.encoding = RX_ENC_LEGACY;
else
rx_status.encoding = RX_ENC_HT;
rx_status.bw = RATE_INFO_BW_20;
if (short_gi)
rx_status.enc_flags |= RX_ENC_FLAG_SHORT_GI;
memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); // put rx_status into skb->cb, from now on skb->cb is not dma_dsts any more.
ieee80211_rx_irqsafe(dev, skb); // call mac80211 function
@ -469,7 +477,7 @@ static irqreturn_t openwifi_tx_interrupt(int irq, void *dev_id)
}
}
if ( ((*(u32*)(&(skb->data[0])))&0xFF000000) || (*(u32*)(&(skb->data[12]))) || (*(u32*)(&(skb->data[8]))) || (*(u32*)(&(skb->data[4]))) ) {
if ( (*(u32*)(&(skb->data[4]))) || ((*(u32*)(&(skb->data[12])))&0xFFFF0000) ) {
printk("%s openwifi_tx_interrupt: WARNING %08x %08x %08x %08x\n", sdr_compatible_str, *(u32*)(&(skb->data[12])), *(u32*)(&(skb->data[8])), *(u32*)(&(skb->data[4])), *(u32*)(&(skb->data[0])));
continue;
}
@ -522,18 +530,56 @@ u32 gen_parity(u32 v){
return (v >> 28) & 1;
}
u32 calc_phy_header(u8 rate_hw_value, u32 len, u8 *bytes){
u8 gen_ht_sig_crc(u64 m)
{
u8 i, temp, c[8] = {1, 1, 1, 1, 1, 1, 1, 1}, ht_sig_crc;
for (i = 0; i < 34; i++)
{
temp = c[7] ^ ((m >> i) & 0x01);
c[7] = c[6];
c[6] = c[5];
c[5] = c[4];
c[4] = c[3];
c[3] = c[2];
c[2] = c[1] ^ temp;
c[1] = c[0] ^ temp;
c[0] = temp;
}
ht_sig_crc = ((~c[7] & 0x01) << 0) | ((~c[6] & 0x01) << 1) | ((~c[5] & 0x01) << 2) | ((~c[4] & 0x01) << 3) | ((~c[3] & 0x01) << 4) | ((~c[2] & 0x01) << 5) | ((~c[1] & 0x01) << 6) | ((~c[0] & 0x01) << 7);
return ht_sig_crc;
}
u32 calc_phy_header(u8 rate_hw_value, bool use_ht_rate, bool use_short_gi, u32 len, u8 *bytes){
//u32 signal_word = 0 ;
u8 SIG_RATE = 0 ;
u8 SIG_RATE = 0, HT_SIG_RATE;
u8 len_2to0, len_10to3, len_msb,b0,b1,b2, header_parity ;
u32 l_len, ht_len, ht_sig1, ht_sig2;
// rate_hw_value = (rate_hw_value<=4?0:(rate_hw_value-4));
// SIG_RATE = wifi_mcs_table_phy_tx[rate_hw_value];
SIG_RATE = wifi_mcs_table_11b_force_up[rate_hw_value];
// printk("rate_hw_value=%u\tuse_ht_rate=%u\tuse_short_gi=%u\tlen=%u\n", rate_hw_value, use_ht_rate, use_short_gi, len);
len_2to0 = len & 0x07 ;
len_10to3 = (len >> 3 ) & 0xFF ;
len_msb = (len >> 11) & 0x01 ;
// HT-mixed mode ht signal
if(use_ht_rate)
{
SIG_RATE = wifi_mcs_table_11b_force_up[4];
HT_SIG_RATE = rate_hw_value;
l_len = 24 * len / wifi_n_dbps_ht_table[rate_hw_value];
ht_len = len;
}
else
{
// rate_hw_value = (rate_hw_value<=4?0:(rate_hw_value-4));
// SIG_RATE = wifi_mcs_table_phy_tx[rate_hw_value];
SIG_RATE = wifi_mcs_table_11b_force_up[rate_hw_value];
l_len = len;
}
len_2to0 = l_len & 0x07 ;
len_10to3 = (l_len >> 3 ) & 0xFF ;
len_msb = (l_len >> 11) & 0x01 ;
b0=SIG_RATE | (len_2to0 << 5) ;
b1 = len_10to3 ;
@ -544,9 +590,30 @@ u32 calc_phy_header(u8 rate_hw_value, u32 len, u8 *bytes){
bytes[0] = b0 ;
bytes[1] = b1 ;
bytes[2] = b2;
//signal_word = b0+(b1<<8)+(b2<<16) ;
//return signal_word;
return(SIG_RATE);
// HT-mixed mode signal
if(use_ht_rate)
{
ht_sig1 = (HT_SIG_RATE & 0x7F) | ((ht_len << 8) & 0xFFFF00);
ht_sig2 = 0x04 | (use_short_gi << 7);
ht_sig2 = ht_sig2 | (gen_ht_sig_crc(ht_sig1 | ht_sig2 << 24) << 10);
bytes[3] = 1;
bytes[8] = (ht_sig1 & 0xFF);
bytes[9] = (ht_sig1 >> 8) & 0xFF;
bytes[10] = (ht_sig1 >> 16) & 0xFF;
bytes[11] = (ht_sig2 & 0xFF);
bytes[12] = (ht_sig2 >> 8) & 0xFF;
bytes[13] = (ht_sig2 >> 16) & 0xFF;
return(HT_SIG_RATE);
}
else
{
//signal_word = b0+(b1<<8)+(b2<<16) ;
//return signal_word;
return(SIG_RATE);
}
}
static inline struct gpio_led_data * //please align with the implementation in leds-gpio.c
@ -571,7 +638,7 @@ static void openwifi_tx(struct ieee80211_hw *dev,
u32 pkt_need_ack, addr1_low32=0, addr2_low32=0, addr3_low32=0, queue_idx=2, dma_reg, cts_reg;//, openofdm_state_history;
u16 addr1_high16=0, addr2_high16=0, addr3_high16=0, sc=0, cts_duration=0, cts_rate_hw_value = 0, cts_rate_signal_value=0, sifs, ack_duration=0, traffic_pkt_duration;
u8 fc_flag,fc_type,fc_subtype,retry_limit_raw,*dma_buf,retry_limit_hw_value,rc_flags;
bool use_rts_cts, use_cts_protect, addr_flag, cts_use_traffic_rate=false, force_use_cts_protect=false;
bool use_rts_cts, use_cts_protect, use_ht_rate=false, use_short_gi, addr_flag, cts_use_traffic_rate=false, force_use_cts_protect=false;
__le16 frame_control,duration_id;
u32 dma_fifo_no_room_flag, hw_queue_len;
enum dma_status status;
@ -670,6 +737,8 @@ static void openwifi_tx(struct ieee80211_hw *dev,
rc_flags = info->control.rates[0].flags;
use_rts_cts = ((rc_flags&IEEE80211_TX_RC_USE_RTS_CTS)!=0);
use_cts_protect = ((rc_flags&IEEE80211_TX_RC_USE_CTS_PROTECT)!=0);
use_ht_rate = ((rc_flags&IEEE80211_TX_RC_MCS)!=0);
use_short_gi = ((rc_flags&IEEE80211_TX_RC_SHORT_GI)!=0);
if (use_rts_cts)
printk("%s openwifi_tx: WARNING sn %d use_rts_cts is not supported!\n", sdr_compatible_str, ring->bd_wr_idx);
@ -701,8 +770,8 @@ static void openwifi_tx(struct ieee80211_hw *dev,
}
if ( (!addr_flag) && (priv->drv_tx_reg_val[DRV_TX_REG_IDX_PRINT_CFG]&2) )
printk("%s openwifi_tx: %4dbytes %2dM FC%04x DI%04x addr1/2/3:%04x%08x/%04x%08x/%04x%08x SC%04x flag%08x retr%d ack%d prio%d q%d wr%d rd%d\n", sdr_compatible_str,
len_mac_pdu, wifi_rate_all[rate_hw_value],frame_control,duration_id,
printk("%s openwifi_tx: %4dbytes ht%d %3dM FC%04x DI%04x addr1/2/3:%04x%08x/%04x%08x/%04x%08x SC%04x flag%08x retr%d ack%d prio%d q%d wr%d rd%d\n", sdr_compatible_str,
len_mac_pdu, (use_ht_rate == false ? 0 : 1), (use_ht_rate == false ? wifi_rate_all[rate_hw_value] : wifi_rate_all[rate_hw_value + 12]),frame_control,duration_id,
reverse16(addr1_high16), reverse32(addr1_low32), reverse16(addr2_high16), reverse32(addr2_low32), reverse16(addr3_high16), reverse32(addr3_low32),
sc, info->flags, retry_limit_raw, pkt_need_ack, prio, queue_idx,
// use_rts_cts,use_cts_protect|force_use_cts_protect,wifi_rate_all[cts_rate_hw_value],cts_duration,
@ -747,7 +816,8 @@ static void openwifi_tx(struct ieee80211_hw *dev,
}
skb_push( skb, LEN_PHY_HEADER );
rate_signal_value = calc_phy_header(rate_hw_value, len_mac_pdu+LEN_PHY_CRC, skb->data); //fill the phy header
rate_signal_value = calc_phy_header(rate_hw_value, use_ht_rate, use_short_gi, len_mac_pdu+LEN_PHY_CRC, skb->data); //fill the phy header
//make sure dma length is integer times of DDC_NUM_BYTE_PER_DMA_SYMBOL
if (skb_tailroom(skb)<num_byte_pad) {
@ -795,7 +865,7 @@ static void openwifi_tx(struct ieee80211_hw *dev,
goto openwifi_tx_early_out_after_lock;
}
if ( ((*(u32*)(&(skb->data[0])))&0xFF000000) || (*(u32*)(&(skb->data[12]))) || (*(u32*)(&(skb->data[8]))) || (*(u32*)(&(skb->data[4]))) ) {
if ( (*(u32*)(&(skb->data[4]))) || ((*(u32*)(&(skb->data[12])))&0xFFFF0000) ) {
printk("%s openwifi_tx: WARNING 1 %d %08x %08x %08x %08x\n", sdr_compatible_str, num_byte_pad, *(u32*)(&(skb->data[12])), *(u32*)(&(skb->data[8])), *(u32*)(&(skb->data[4])), *(u32*)(&(skb->data[0])));
goto openwifi_tx_early_out_after_lock;
}
@ -837,7 +907,7 @@ static void openwifi_tx(struct ieee80211_hw *dev,
dma_async_issue_pending(priv->tx_chan);
if ( ((*(u32*)(&(skb->data[0])))&0xFF000000) || (*(u32*)(&(skb->data[12]))) || (*(u32*)(&(skb->data[8]))) || (*(u32*)(&(skb->data[4]))) )
if ( (*(u32*)(&(skb->data[4]))) || ((*(u32*)(&(skb->data[12])))&0xFFFF0000) )
printk("%s openwifi_tx: WARNING 2 %08x %08x %08x %08x\n", sdr_compatible_str, *(u32*)(&(skb->data[12])), *(u32*)(&(skb->data[8])), *(u32*)(&(skb->data[4])), *(u32*)(&(skb->data[0])));
spin_unlock_irqrestore(&priv->lock, flags);
@ -919,8 +989,7 @@ static int openwifi_start(struct ieee80211_hw *dev)
// rssi_half_db_th = 87<<1; // -62dBm // will settup in runtime in _rf_set_channel
// xpu_api->XPU_REG_LBT_TH_write(rssi_half_db_th); // set IQ rssi th step .5dB to xxx and enable it
// // xpu_api->XPU_REG_CSMA_CFG_write(3); // cw_min
// xpu_api->XPU_REG_CSMA_CFG_write(3);
// xpu_api->XPU_REG_CSMA_CFG_write(3); // cw_min -- already set in xpu.c
//xpu_api->XPU_REG_SEND_ACK_WAIT_TOP_write( ((40)<<16)|0 );//high 16bit 5GHz; low 16 bit 2.4GHz (Attention, current tx core has around 1.19us starting delay that makes the ack fall behind 10us SIFS in 2.4GHz! Need to improve TX in 2.4GHz!)
//xpu_api->XPU_REG_SEND_ACK_WAIT_TOP_write( ((51)<<16)|0 );//now our tx send out I/Q immediately
@ -931,8 +1000,8 @@ static int openwifi_start(struct ieee80211_hw *dev)
tx_intf_api->TX_INTF_REG_CTS_TOSELF_WAIT_SIFS_TOP_write( ((16*10)<<16)|(10*10) );//high 16bit 5GHz; low 16 bit 2.4GHz. counter speed 10MHz is assumed
//xpu_api->XPU_REG_BB_RF_DELAY_write(51); // fine tuned value at 0.005us. old: dac-->ant port: 0.6us, 57 taps fir at 40MHz: 1.425us; round trip: 2*(0.6+1.425)=4.05us; 4.05*10=41
xpu_api->XPU_REG_BB_RF_DELAY_write(49);//add .5us for slightly longer fir
// //xpu_api->XPU_REG_BB_RF_DELAY_write(51); // fine tuned value at 0.005us. old: dac-->ant port: 0.6us, 57 taps fir at 40MHz: 1.425us; round trip: 2*(0.6+1.425)=4.05us; 4.05*10=41
// xpu_api->XPU_REG_BB_RF_DELAY_write(47);//add .5us for slightly longer fir -- already in xpu.c
xpu_api->XPU_REG_MAC_ADDR_write(priv->mac_addr);
// setup time schedule of 4 slices
@ -1333,7 +1402,7 @@ static void openwifi_configure_filter(struct ieee80211_hw *dev,
u32 filter_flag;
(*total_flags) &= SDR_SUPPORTED_FILTERS;
// (*total_flags) |= FIF_ALLMULTI; //because we always pass all multicast (no matter it is for us or not) to upper layer
(*total_flags) |= FIF_ALLMULTI; //because we need to pass all multicast (no matter it is for us or not) to upper layer
filter_flag = (*total_flags);
@ -1983,6 +2052,11 @@ static int openwifi_dev_probe(struct platform_device *pdev)
priv->band_2GHz.n_channels = ARRAY_SIZE(priv->channels_2GHz);
priv->band_2GHz.bitrates = priv->rates_2GHz;
priv->band_2GHz.n_bitrates = ARRAY_SIZE(priv->rates_2GHz);
priv->band_2GHz.ht_cap.ht_supported = true;
priv->band_2GHz.ht_cap.cap = IEEE80211_HT_CAP_SGI_20;
memset(&priv->band_2GHz.ht_cap.mcs, 0, sizeof(priv->band_2GHz.ht_cap.mcs));
priv->band_2GHz.ht_cap.mcs.rx_mask[0] = 0xff;
priv->band_2GHz.ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
dev->wiphy->bands[NL80211_BAND_2GHZ] = &(priv->band_2GHz);
priv->band_5GHz.band = NL80211_BAND_5GHZ;
@ -1990,6 +2064,11 @@ static int openwifi_dev_probe(struct platform_device *pdev)
priv->band_5GHz.n_channels = ARRAY_SIZE(priv->channels_5GHz);
priv->band_5GHz.bitrates = priv->rates_5GHz;
priv->band_5GHz.n_bitrates = ARRAY_SIZE(priv->rates_5GHz);
priv->band_5GHz.ht_cap.ht_supported = true;
priv->band_5GHz.ht_cap.cap = IEEE80211_HT_CAP_SGI_20;
memset(&priv->band_5GHz.ht_cap.mcs, 0, sizeof(priv->band_5GHz.ht_cap.mcs));
priv->band_5GHz.ht_cap.mcs.rx_mask[0] = 0xff;
priv->band_5GHz.ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
dev->wiphy->bands[NL80211_BAND_5GHZ] = &(priv->band_5GHz);
printk("%s openwifi_dev_probe: band_2GHz.n_channels %d n_bitrates %d band_5GHz.n_channels %d n_bitrates %d\n",sdr_compatible_str,

View File

@ -260,11 +260,12 @@ static const struct ieee80211_iface_combination openwifi_if_comb = {
BIT(NL80211_CHAN_WIDTH_80),
};
static const u8 wifi_rate_table_mapping[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 10, 8, 6, 4, 11, 9, 7, 5};
static const u8 wifi_rate_table[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 48, 24, 12, 6, 54, 36, 18, 9};
static const u8 wifi_rate_all[16] = { 1, 2, 5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 0, 0, 0, 0};
static const u8 wifi_mcs_table_11b_force_up[16] = {11, 11, 11, 11, 11, 15, 10, 14, 9, 13, 8, 12, 0, 0, 0, 0};
static const u16 wifi_n_dbps_table[16] = {24, 24, 24, 24, 24, 36, 48, 72, 96, 144, 192, 216, 0, 0, 0, 0};
static const u8 wifi_rate_table_mapping[24] = { 0, 0, 0, 0, 0, 0, 0, 0, 10, 8, 6, 4, 11, 9, 7, 5, 0, 1, 2, 3, 4, 5, 6, 7};
static const u16 wifi_rate_table[24] = { 0, 0, 0, 0, 0, 0, 0, 0, 480, 240, 120, 60, 540, 360, 180, 90, 65, 130, 195, 260, 390, 520, 585, 650};
static const u16 wifi_rate_all[20] = {10, 20, 55, 110, 60, 90, 120, 180, 240, 360, 480, 540, 65, 130, 195, 260, 390, 520, 585, 650};
static const u8 wifi_mcs_table_11b_force_up[16] = {11, 11, 11, 11, 11, 15, 10, 14, 9, 13, 8, 12, 0, 0, 0, 0};
static const u16 wifi_n_dbps_table[16] = {24, 24, 24, 24, 24, 36, 48, 72, 96, 144, 192, 216, 0, 0, 0, 0};
static const u16 wifi_n_dbps_ht_table[16] = {26, 26, 26, 26, 26, 52, 78, 104, 156, 208, 234, 260, 0, 0, 0, 0};
// static const u8 wifi_mcs_table[8] = {6,9,12,18,24,36,48,54};
// static const u8 wifi_mcs_table_phy_tx[8] = {11,15,10,14,9,13,8,12};

View File

@ -132,6 +132,14 @@ static inline u32 XPU_REG_BAND_CHANNEL_read(void){
return reg_read(XPU_REG_BAND_CHANNEL_ADDR);
}
static inline void XPU_REG_DIFS_ADVANCE_write(u32 Data) {
reg_write(XPU_REG_DIFS_ADVANCE_ADDR, Data);
}
static inline u32 XPU_REG_DIFS_ADVANCE_read(void){
return reg_read(XPU_REG_DIFS_ADVANCE_ADDR);
}
static inline u32 XPU_REG_TRX_STATUS_read(void){
return reg_read(XPU_REG_TRX_STATUS_ADDR);
}
@ -331,7 +339,8 @@ static inline u32 hw_init(enum xpu_mode mode){
//xpu_api->XPU_REG_MAX_NUM_RETRANS_write(3); // if this > 0, it will override mac80211 set value, and set static retransmission limit
xpu_api->XPU_REG_BB_RF_DELAY_write(49);
// xpu_api->XPU_REG_BB_RF_DELAY_write((1<<8)|47);
xpu_api->XPU_REG_BB_RF_DELAY_write((10<<8)|40); // extended rf is ongoing for perfect muting. (10<<8)|40 is verified good for zcu102/zed
// setup time schedule of 4 slices
// slice 0
@ -391,14 +400,16 @@ static inline u32 hw_init(enum xpu_mode mode){
//xpu_api->XPU_REG_CSMA_DEBUG_write((1<<31)|(20<<24)|(4<<19)|(3<<14)|(10<<7)|(5));
xpu_api->XPU_REG_CSMA_DEBUG_write(0);
//xpu_api->XPU_REG_CSMA_CFG_write(3); //normal CSMA
xpu_api->XPU_REG_CSMA_CFG_write(0xe0000000); //high priority
xpu_api->XPU_REG_CSMA_CFG_write(3); //normal CSMA
// xpu_api->XPU_REG_CSMA_CFG_write(0xe0000000); //high priority
xpu_api->XPU_REG_SEND_ACK_WAIT_TOP_write( ((51)<<16)|0 );//now our tx send out I/Q immediately
xpu_api->XPU_REG_RECV_ACK_COUNT_TOP0_write( (((45+2+2)*10 + 15)<<16) | 10 );//2.4GHz. extra 300 clocks are needed when rx core fall into fake ht detection phase (rx mcs 6M)
xpu_api->XPU_REG_RECV_ACK_COUNT_TOP1_write( (((51+2+2)*10 + 15)<<16) | 10 );//5GHz. extra 300 clocks are needed when rx core fall into fake ht detection phase (rx mcs 6M)
xpu_api->XPU_REG_DIFS_ADVANCE_write(2); //us
printk("%s hw_init err %d\n", xpu_compatible_str, err);
return(err);
}
@ -458,6 +469,9 @@ static int dev_probe(struct platform_device *pdev)
xpu_api->XPU_REG_BAND_CHANNEL_write=XPU_REG_BAND_CHANNEL_write;
xpu_api->XPU_REG_BAND_CHANNEL_read=XPU_REG_BAND_CHANNEL_read;
xpu_api->XPU_REG_DIFS_ADVANCE_write=XPU_REG_DIFS_ADVANCE_write;
xpu_api->XPU_REG_DIFS_ADVANCE_read=XPU_REG_DIFS_ADVANCE_read;
xpu_api->XPU_REG_TRX_STATUS_read=XPU_REG_TRX_STATUS_read;
xpu_api->XPU_REG_TX_RESULT_read=XPU_REG_TX_RESULT_read;

View File

@ -670,7 +670,9 @@ CONFIG_IP_PNP_RARP=y
CONFIG_NET_IPIP=m
# CONFIG_NET_IPGRE_DEMUX is not set
CONFIG_NET_IP_TUNNEL=m
# CONFIG_IP_MROUTE is not set
CONFIG_IP_MROUTE=y
CONFIG_IP_PIMSM_V1=y
CONFIG_IP_PIMSM_V2=y
CONFIG_SYN_COOKIES=y
CONFIG_NET_IPVTI=m
# CONFIG_NET_UDP_TUNNEL is not set
@ -710,7 +712,33 @@ CONFIG_DEFAULT_CUBIC=y
# CONFIG_DEFAULT_RENO is not set
CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_TCP_MD5SIG is not set
# CONFIG_IPV6 is not set
CONFIG_IPV6=m
# CONFIG_IPV6_ROUTER_PREF is not set
# CONFIG_IPV6_OPTIMISTIC_DAD is not set
# CONFIG_INET6_AH is not set
# CONFIG_INET6_ESP is not set
# CONFIG_INET6_IPCOMP is not set
# CONFIG_IPV6_MIP6 is not set
# CONFIG_IPV6_ILA is not set
# CONFIG_INET6_XFRM_TUNNEL is not set
# CONFIG_INET6_TUNNEL is not set
CONFIG_INET6_XFRM_MODE_TRANSPORT=m
CONFIG_INET6_XFRM_MODE_TUNNEL=m
CONFIG_INET6_XFRM_MODE_BEET=m
# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
# CONFIG_IPV6_VTI is not set
CONFIG_IPV6_SIT=m
# CONFIG_IPV6_SIT_6RD is not set
CONFIG_IPV6_NDISC_NODETYPE=y
# CONFIG_IPV6_TUNNEL is not set
# CONFIG_IPV6_FOU is not set
# CONFIG_IPV6_FOU_TUNNEL is not set
# CONFIG_IPV6_MULTIPLE_TABLES is not set
CONFIG_IPV6_MROUTE=y
CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y
CONFIG_IPV6_PIMSM_V2=y
# CONFIG_IPV6_SEG6_LWTUNNEL is not set
# CONFIG_IPV6_SEG6_HMAC is not set
# CONFIG_NETWORK_SECMARK is not set
CONFIG_NET_PTP_CLASSIFY=y
# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
@ -741,7 +769,7 @@ CONFIG_NF_CT_PROTO_SCTP=y
CONFIG_NF_CT_PROTO_UDPLITE=y
CONFIG_NF_CONNTRACK_AMANDA=y
CONFIG_NF_CONNTRACK_FTP=y
CONFIG_NF_CONNTRACK_H323=y
CONFIG_NF_CONNTRACK_H323=m
CONFIG_NF_CONNTRACK_IRC=y
CONFIG_NF_CONNTRACK_BROADCAST=y
CONFIG_NF_CONNTRACK_NETBIOS_NS=y
@ -767,6 +795,7 @@ CONFIG_NF_NAT_TFTP=y
CONFIG_NF_NAT_REDIRECT=y
CONFIG_NETFILTER_SYNPROXY=y
CONFIG_NF_TABLES=y
# CONFIG_NF_TABLES_INET is not set
CONFIG_NF_TABLES_NETDEV=y
CONFIG_NFT_EXTHDR=y
CONFIG_NFT_META=y
@ -821,10 +850,10 @@ CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
CONFIG_NETFILTER_XT_TARGET_NOTRACK=y
CONFIG_NETFILTER_XT_TARGET_RATEEST=y
CONFIG_NETFILTER_XT_TARGET_REDIRECT=y
CONFIG_NETFILTER_XT_TARGET_TEE=y
CONFIG_NETFILTER_XT_TARGET_TPROXY=y
CONFIG_NETFILTER_XT_TARGET_TEE=m
CONFIG_NETFILTER_XT_TARGET_TPROXY=m
CONFIG_NETFILTER_XT_TARGET_TRACE=y
CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=y
#
@ -900,7 +929,7 @@ CONFIG_NFT_REDIR_IPV4=y
CONFIG_NF_NAT_SNMP_BASIC=y
CONFIG_NF_NAT_PROTO_GRE=y
CONFIG_NF_NAT_PPTP=y
CONFIG_NF_NAT_H323=y
CONFIG_NF_NAT_H323=m
CONFIG_IP_NF_IPTABLES=y
CONFIG_IP_NF_MATCH_AH=y
CONFIG_IP_NF_MATCH_ECN=y
@ -921,6 +950,18 @@ CONFIG_IP_NF_RAW=y
CONFIG_IP_NF_ARPTABLES=y
CONFIG_IP_NF_ARPFILTER=y
CONFIG_IP_NF_ARP_MANGLE=y
#
# IPv6: Netfilter Configuration
#
# CONFIG_NF_DEFRAG_IPV6 is not set
# CONFIG_NF_CONNTRACK_IPV6 is not set
# CONFIG_NF_SOCKET_IPV6 is not set
# CONFIG_NF_TABLES_IPV6 is not set
CONFIG_NF_DUP_IPV6=m
# CONFIG_NF_REJECT_IPV6 is not set
CONFIG_NF_LOG_IPV6=m
# CONFIG_IP6_NF_IPTABLES is not set
# CONFIG_IP_DCCP is not set
# CONFIG_IP_SCTP is not set
# CONFIG_RDS is not set
@ -940,6 +981,7 @@ CONFIG_VLAN_8021Q=m
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
# CONFIG_PHONET is not set
# CONFIG_6LOWPAN is not set
# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@ -973,6 +1015,7 @@ CONFIG_NET_FLOW_LIMIT=y
# CONFIG_AF_RXRPC is not set
# CONFIG_AF_KCM is not set
# CONFIG_STREAM_PARSER is not set
CONFIG_FIB_RULES=y
CONFIG_WIRELESS=y
CONFIG_WEXT_CORE=y
CONFIG_WEXT_PROC=y

View File

@ -646,10 +646,12 @@ CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
CONFIG_IP_PNP_BOOTP=y
CONFIG_IP_PNP_RARP=y
# CONFIG_NET_IPIP is not set
CONFIG_NET_IPIP=y
# CONFIG_NET_IPGRE_DEMUX is not set
CONFIG_NET_IP_TUNNEL=y
# CONFIG_IP_MROUTE is not set
CONFIG_IP_MROUTE=y
CONFIG_IP_PIMSM_V1=y
CONFIG_IP_PIMSM_V2=y
CONFIG_SYN_COOKIES=y
# CONFIG_NET_IPVTI is not set
# CONFIG_NET_UDP_TUNNEL is not set
@ -672,7 +674,7 @@ CONFIG_INET_TCP_DIAG=y
CONFIG_TCP_CONG_CUBIC=y
CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_TCP_MD5SIG is not set
CONFIG_IPV6=y
CONFIG_IPV6=m
# CONFIG_IPV6_ROUTER_PREF is not set
# CONFIG_IPV6_OPTIMISTIC_DAD is not set
# CONFIG_INET6_AH is not set
@ -682,19 +684,21 @@ CONFIG_IPV6=y
# CONFIG_IPV6_ILA is not set
# CONFIG_INET6_XFRM_TUNNEL is not set
# CONFIG_INET6_TUNNEL is not set
CONFIG_INET6_XFRM_MODE_TRANSPORT=y
CONFIG_INET6_XFRM_MODE_TUNNEL=y
CONFIG_INET6_XFRM_MODE_BEET=y
CONFIG_INET6_XFRM_MODE_TRANSPORT=m
CONFIG_INET6_XFRM_MODE_TUNNEL=m
CONFIG_INET6_XFRM_MODE_BEET=m
# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
# CONFIG_IPV6_VTI is not set
CONFIG_IPV6_SIT=y
CONFIG_IPV6_SIT=m
# CONFIG_IPV6_SIT_6RD is not set
CONFIG_IPV6_NDISC_NODETYPE=y
# CONFIG_IPV6_TUNNEL is not set
# CONFIG_IPV6_FOU is not set
# CONFIG_IPV6_FOU_TUNNEL is not set
# CONFIG_IPV6_MULTIPLE_TABLES is not set
# CONFIG_IPV6_MROUTE is not set
CONFIG_IPV6_MROUTE=y
CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y
CONFIG_IPV6_PIMSM_V2=y
# CONFIG_IPV6_SEG6_LWTUNNEL is not set
# CONFIG_IPV6_SEG6_HMAC is not set
CONFIG_NETWORK_SECMARK=y
@ -870,11 +874,11 @@ CONFIG_NF_DEFRAG_IPV6=m
CONFIG_NF_CONNTRACK_IPV6=m
# CONFIG_NF_SOCKET_IPV6 is not set
# CONFIG_NF_DUP_IPV6 is not set
CONFIG_NF_REJECT_IPV6=y
CONFIG_NF_LOG_IPV6=y
CONFIG_NF_REJECT_IPV6=m
CONFIG_NF_LOG_IPV6=m
CONFIG_NF_NAT_IPV6=m
# CONFIG_NF_NAT_MASQUERADE_IPV6 is not set
CONFIG_IP6_NF_IPTABLES=y
CONFIG_IP6_NF_IPTABLES=m
# CONFIG_IP6_NF_MATCH_AH is not set
# CONFIG_IP6_NF_MATCH_EUI64 is not set
# CONFIG_IP6_NF_MATCH_FRAG is not set
@ -885,16 +889,16 @@ CONFIG_IP6_NF_IPTABLES=y
# CONFIG_IP6_NF_MATCH_RPFILTER is not set
# CONFIG_IP6_NF_MATCH_RT is not set
# CONFIG_IP6_NF_TARGET_HL is not set
CONFIG_IP6_NF_FILTER=y
CONFIG_IP6_NF_TARGET_REJECT=y
CONFIG_IP6_NF_FILTER=m
CONFIG_IP6_NF_TARGET_REJECT=m
# CONFIG_IP6_NF_TARGET_SYNPROXY is not set
CONFIG_IP6_NF_MANGLE=y
CONFIG_IP6_NF_MANGLE=m
# CONFIG_IP6_NF_RAW is not set
# CONFIG_IP6_NF_NAT is not set
CONFIG_BRIDGE_NF_EBTABLES=y
CONFIG_BRIDGE_NF_EBTABLES=m
# CONFIG_BRIDGE_EBT_BROUTE is not set
CONFIG_BRIDGE_EBT_T_FILTER=y
CONFIG_BRIDGE_EBT_T_NAT=y
CONFIG_BRIDGE_EBT_T_FILTER=m
CONFIG_BRIDGE_EBT_T_NAT=m
# CONFIG_BRIDGE_EBT_802_3 is not set
# CONFIG_BRIDGE_EBT_AMONG is not set
# CONFIG_BRIDGE_EBT_ARP is not set
@ -907,7 +911,7 @@ CONFIG_BRIDGE_EBT_T_NAT=y
# CONFIG_BRIDGE_EBT_VLAN is not set
# CONFIG_BRIDGE_EBT_ARPREPLY is not set
# CONFIG_BRIDGE_EBT_DNAT is not set
CONFIG_BRIDGE_EBT_MARK_T=y
CONFIG_BRIDGE_EBT_MARK_T=m
# CONFIG_BRIDGE_EBT_REDIRECT is not set
# CONFIG_BRIDGE_EBT_SNAT is not set
# CONFIG_BRIDGE_EBT_LOG is not set
@ -918,14 +922,14 @@ CONFIG_BRIDGE_EBT_MARK_T=y
# CONFIG_TIPC is not set
# CONFIG_ATM is not set
# CONFIG_L2TP is not set
CONFIG_STP=y
CONFIG_BRIDGE=y
CONFIG_STP=m
CONFIG_BRIDGE=m
CONFIG_BRIDGE_IGMP_SNOOPING=y
CONFIG_HAVE_NET_DSA=y
# CONFIG_NET_DSA is not set
# CONFIG_VLAN_8021Q is not set
# CONFIG_DECNET is not set
CONFIG_LLC=y
CONFIG_LLC=m
# CONFIG_LLC2 is not set
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
@ -1048,31 +1052,30 @@ CONFIG_BT_WILINK=y
# CONFIG_AF_RXRPC is not set
# CONFIG_AF_KCM is not set
# CONFIG_STREAM_PARSER is not set
CONFIG_FIB_RULES=y
CONFIG_WIRELESS=y
CONFIG_WEXT_CORE=y
CONFIG_WEXT_PROC=y
CONFIG_CFG80211=y
CONFIG_CFG80211=m
CONFIG_NL80211_TESTMODE=y
# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set
CONFIG_CFG80211_CERTIFICATION_ONUS=y
CONFIG_CFG80211_REG_CELLULAR_HINTS=y
CONFIG_CFG80211_REG_RELAX_NO_IR=y
CONFIG_CFG80211_DEVELOPER_WARNINGS=y
# CONFIG_CFG80211_CERTIFICATION_ONUS is not set
CONFIG_CFG80211_DEFAULT_PS=y
# CONFIG_CFG80211_DEBUGFS is not set
CONFIG_CFG80211_DEBUGFS=y
# CONFIG_CFG80211_INTERNAL_REGDB is not set
CONFIG_CFG80211_CRDA_SUPPORT=y
CONFIG_CFG80211_WEXT=y
# CONFIG_LIB80211 is not set
CONFIG_MAC80211=y
CONFIG_MAC80211=m
CONFIG_MAC80211_HAS_RC=y
CONFIG_MAC80211_RC_MINSTREL=y
CONFIG_MAC80211_RC_MINSTREL_HT=y
# CONFIG_MAC80211_RC_MINSTREL_VHT is not set
CONFIG_MAC80211_RC_MINSTREL_VHT=y
CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y
CONFIG_MAC80211_RC_DEFAULT="minstrel_ht"
# CONFIG_MAC80211_MESH is not set
CONFIG_MAC80211_MESH=y
CONFIG_MAC80211_LEDS=y
# CONFIG_MAC80211_DEBUGFS is not set
CONFIG_MAC80211_DEBUGFS=y
CONFIG_MAC80211_MESSAGE_TRACING=y
CONFIG_MAC80211_DEBUG_MENU=y
# CONFIG_MAC80211_NOINLINE is not set
@ -1083,7 +1086,14 @@ CONFIG_MAC80211_DEBUG_MENU=y
# CONFIG_MAC80211_OCB_DEBUG is not set
# CONFIG_MAC80211_IBSS_DEBUG is not set
# CONFIG_MAC80211_PS_DEBUG is not set
# CONFIG_MAC80211_MPL_DEBUG is not set
# CONFIG_MAC80211_MPATH_DEBUG is not set
# CONFIG_MAC80211_MHWMP_DEBUG is not set
# CONFIG_MAC80211_MESH_SYNC_DEBUG is not set
# CONFIG_MAC80211_MESH_CSA_DEBUG is not set
# CONFIG_MAC80211_MESH_PS_DEBUG is not set
# CONFIG_MAC80211_TDLS_DEBUG is not set
# CONFIG_MAC80211_DEBUG_COUNTERS is not set
CONFIG_MAC80211_STA_HASH_MAX_SIZE=0
# CONFIG_WIMAX is not set
CONFIG_RFKILL=y
@ -1844,7 +1854,6 @@ CONFIG_WLAN_VENDOR_ADMTEK=y
# CONFIG_ADM8211 is not set
CONFIG_WLAN_VENDOR_ATH=y
# CONFIG_ATH_DEBUG is not set
# CONFIG_ATH_REG_DYNAMIC_USER_REG_HINTS is not set
# CONFIG_ATH5K is not set
# CONFIG_ATH5K_PCI is not set
# CONFIG_ATH9K is not set
@ -1887,7 +1896,7 @@ CONFIG_WLAN_VENDOR_RALINK=y
CONFIG_WLAN_VENDOR_REALTEK=y
# CONFIG_RTL8180 is not set
# CONFIG_RTL8187 is not set
CONFIG_RTL_CARDS=y
CONFIG_RTL_CARDS=m
# CONFIG_RTL8192CE is not set
# CONFIG_RTL8192SE is not set
# CONFIG_RTL8192DE is not set
@ -1905,10 +1914,10 @@ CONFIG_WLAN_VENDOR_ST=y
CONFIG_WLAN_VENDOR_TI=y
# CONFIG_WL1251 is not set
# CONFIG_WL12XX is not set
CONFIG_WL18XX=y
CONFIG_WLCORE=y
CONFIG_WLCORE_SPI=y
CONFIG_WLCORE_SDIO=y
CONFIG_WL18XX=m
CONFIG_WLCORE=m
CONFIG_WLCORE_SPI=m
CONFIG_WLCORE_SDIO=m
CONFIG_WILINK_PLATFORM_DATA=y
CONFIG_WLAN_VENDOR_ZYDAS=y
# CONFIG_USB_ZD1201 is not set

15
user_space/fosdem-11ag.sh Executable file
View File

@ -0,0 +1,15 @@
#!/bin/bash
killall hostapd
killall webfsd
cd ~/openwifi
service network-manager stop
./wgd.sh
ifconfig sdr0 192.168.13.1
route add default gw 192.168.10.1
service isc-dhcp-server restart
hostapd hostapd-openwifi-11ag.conf &
sleep 5
cd webserver
webfsd -F -p 80 -f index.html &

View File

@ -0,0 +1,16 @@
interface=sdr0
driver=nl80211
country_code=BE
ssid=openwifi
hw_mode=a
channel=44
supported_rates=60 90 120 180 240 360 480 540
basic_rates=60 90 120 180
#ieee80211n=1
#ht_capab=[SHORT-GI-20]
#require_ht=1
#ieee80211d=1
#ieee80211h=1
#wpa=2
#wpa_passphrase=myrabbit
#wpa_key_mgmt=WPA-PSK

View File

@ -6,6 +6,9 @@ hw_mode=a
channel=44
supported_rates=60 90 120 180 240 360 480 540
basic_rates=60 90 120 180
ieee80211n=1
ht_capab=[SHORT-GI-20]
require_ht=1
#ieee80211d=1
#ieee80211h=1
#wpa=2

View File

@ -0,0 +1,13 @@
all: inject_80211 analyze_80211
inject_80211: inject_80211.c
gcc -Wall -Werror inject_80211.c -o inject_80211 -lpcap
analyze_80211: analyze_80211.c
gcc -Wall -Werror radiotap.c analyze_80211.c -o analyze_80211 -lpcap
clean:
rm -f inject_80211 analyze_80211

View File

@ -0,0 +1,138 @@
// (c)2020 Michael Tetemke Mehari <michael.mehari@ugent.be>
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "inject_80211.h"
#include "radiotap.h"
#include "uthash.h"
#define HEADERLEN_80211 24
struct RECORD_t
{
char id[16]; // hw_mode-rate-sgi_flag-packet_size
uint16_t pkt_cnt; // number of packets received
uint64_t ts_begin; // beginning timestamp
uint64_t ts_end; // ending timestamp
UT_hash_handle hh; // hash function handler
};
/* 802.11n bitrates x 2 */
static const uint8_t rates_11n[] = {13, 26, 39, 52, 78, 104, 117, 130};
int main(int argc, char **argv)
{
struct pcap_pkthdr pcap_hdr;
const u_char *packet;
char hw_mode, id[16];
int rate, sgi_flag, packet_size;
int n, hdr_len;
struct ieee80211_radiotap_iterator rti;
struct RECORD_t *RECORD_ptr, *tmp_ptr, *hash_ptr = NULL;
if (argc < 2)
{
fprintf(stderr, "Usage: %s <pcap>\n", argv[0]);
exit(1);
}
pcap_t *handle;
char errbuf[PCAP_ERRBUF_SIZE];
handle = pcap_open_offline(argv[1], errbuf);
if (handle == NULL)
{
fprintf(stderr,"Couldn't open pcap file %s: %s\n", argv[1], errbuf);
return(2);
}
while ((packet = pcap_next(handle, &pcap_hdr)))
{
hdr_len = (packet[2] + (packet[3] << 8));
if (pcap_hdr.len < (hdr_len + HEADERLEN_80211))
continue;
packet_size = pcap_hdr.len - (hdr_len + HEADERLEN_80211);
if (packet_size < 0)
continue;
if (ieee80211_radiotap_iterator_init(&rti, (struct ieee80211_radiotap_header *)packet, packet_size) < 0)
continue;
while ((n = ieee80211_radiotap_iterator_next(&rti)) == 0)
{
switch (rti.this_arg_index)
{
case IEEE80211_RADIOTAP_RATE:
rate = (rti.this_arg)[0];
sgi_flag = 0;
hw_mode = 'a';
break;
case IEEE80211_RADIOTAP_MCS:
rate = rates_11n[((rti.this_arg)[2])];
sgi_flag = (rti.this_arg)[1] & 0x40;
hw_mode = 'n';
break;
}
}
// create hash table index
sprintf(id, "%c-%d-%d-%d", hw_mode, rate, sgi_flag, packet_size);
// Hash table implementation for c : https://github.com/troydhanson/uthash
HASH_FIND_STR(hash_ptr, id, RECORD_ptr);
if(RECORD_ptr == NULL)
{
RECORD_ptr = (struct RECORD_t*)malloc(sizeof(struct RECORD_t));
if(RECORD_ptr == NULL)
{
fprintf(stderr, "Unable to create record!\n");
return 1;
}
strcpy(RECORD_ptr->id, id);
RECORD_ptr->pkt_cnt = 1;
RECORD_ptr->ts_begin = 1e6*pcap_hdr.ts.tv_sec + pcap_hdr.ts.tv_usec;
// Add the new record to the hash table
HASH_ADD_STR(hash_ptr, id, RECORD_ptr);
}
else
{
RECORD_ptr->pkt_cnt++;
RECORD_ptr->ts_end = 1e6*pcap_hdr.ts.tv_sec + pcap_hdr.ts.tv_usec;
}
}
pcap_close(handle);
// Iterate through the hash table
printf("HW MODE\tRATE(Mbps)\tSGI\tSIZE(bytes)\tCOUNT\tDELAY(sec)\n");
printf("=======\t==========\t===\t===========\t=====\t=========\n");
HASH_ITER(hh, hash_ptr, RECORD_ptr, tmp_ptr)
{
sscanf(RECORD_ptr->id, "%c-%d-%d-%d", &hw_mode, &rate, &sgi_flag, &packet_size);
printf("802.11%c\t%.1f\t\t%s\t%d\t\t%d\t%.5f\n", hw_mode, rate/2.0, (sgi_flag == 0 ? "OFF" : "ON"), packet_size, RECORD_ptr->pkt_cnt, 1e-6*(RECORD_ptr->ts_end - RECORD_ptr->ts_begin));
}
fflush(stdout);
return 0;
}

View File

@ -0,0 +1,307 @@
/*
* Copyright (c) 2003, 2004 David Young. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of David Young may not be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID
* YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
/*
* Modifications to fit into the linux IEEE 802.11 stack,
* Mike Kershaw (dragorn@kismetwireless.net)
*/
#ifndef IEEE80211RADIOTAP_H
#define IEEE80211RADIOTAP_H
#include <linux/if_ether.h>
#include <linux/kernel.h>
/* Base version of the radiotap packet header data */
#define PKTHDR_RADIOTAP_VERSION 0
/* A generic radio capture format is desirable. There is one for
* Linux, but it is neither rigidly defined (there were not even
* units given for some fields) nor easily extensible.
*
* I suggest the following extensible radio capture format. It is
* based on a bitmap indicating which fields are present.
*
* I am trying to describe precisely what the application programmer
* should expect in the following, and for that reason I tell the
* units and origin of each measurement (where it applies), or else I
* use sufficiently weaselly language ("is a monotonically nondecreasing
* function of...") that I cannot set false expectations for lawyerly
* readers.
*/
/*
* The radio capture header precedes the 802.11 header.
* All data in the header is little endian on all platforms.
*/
struct ieee80211_radiotap_header {
u8 it_version; /* Version 0. Only increases
* for drastic changes,
* introduction of compatible
* new fields does not count.
*/
u8 it_pad;
__le16 it_len; /* length of the whole
* header in bytes, including
* it_version, it_pad,
* it_len, and data fields.
*/
__le32 it_present; /* A bitmap telling which
* fields are present. Set bit 31
* (0x80000000) to extend the
* bitmap by another 32 bits.
* Additional extensions are made
* by setting bit 31.
*/
} __packed;
/* Name Data type Units
* ---- --------- -----
*
* IEEE80211_RADIOTAP_TSFT __le64 microseconds
*
* Value in microseconds of the MAC's 64-bit 802.11 Time
* Synchronization Function timer when the first bit of the
* MPDU arrived at the MAC. For received frames, only.
*
* IEEE80211_RADIOTAP_CHANNEL 2 x __le16 MHz, bitmap
*
* Tx/Rx frequency in MHz, followed by flags (see below).
*
* IEEE80211_RADIOTAP_FHSS __le16 see below
*
* For frequency-hopping radios, the hop set (first byte)
* and pattern (second byte).
*
* IEEE80211_RADIOTAP_RATE u8 500kb/s
*
* Tx/Rx data rate
*
* IEEE80211_RADIOTAP_DBM_ANTSIGNAL s8 decibels from
* one milliwatt (dBm)
*
* RF signal power at the antenna, decibel difference from
* one milliwatt.
*
* IEEE80211_RADIOTAP_DBM_ANTNOISE s8 decibels from
* one milliwatt (dBm)
*
* RF noise power at the antenna, decibel difference from one
* milliwatt.
*
* IEEE80211_RADIOTAP_DB_ANTSIGNAL u8 decibel (dB)
*
* RF signal power at the antenna, decibel difference from an
* arbitrary, fixed reference.
*
* IEEE80211_RADIOTAP_DB_ANTNOISE u8 decibel (dB)
*
* RF noise power at the antenna, decibel difference from an
* arbitrary, fixed reference point.
*
* IEEE80211_RADIOTAP_LOCK_QUALITY __le16 unitless
*
* Quality of Barker code lock. Unitless. Monotonically
* nondecreasing with "better" lock strength. Called "Signal
* Quality" in datasheets. (Is there a standard way to measure
* this?)
*
* IEEE80211_RADIOTAP_TX_ATTENUATION __le16 unitless
*
* Transmit power expressed as unitless distance from max
* power set at factory calibration. 0 is max power.
* Monotonically nondecreasing with lower power levels.
*
* IEEE80211_RADIOTAP_DB_TX_ATTENUATION __le16 decibels (dB)
*
* Transmit power expressed as decibel distance from max power
* set at factory calibration. 0 is max power. Monotonically
* nondecreasing with lower power levels.
*
* IEEE80211_RADIOTAP_DBM_TX_POWER s8 decibels from
* one milliwatt (dBm)
*
* Transmit power expressed as dBm (decibels from a 1 milliwatt
* reference). This is the absolute power level measured at
* the antenna port.
*
* IEEE80211_RADIOTAP_FLAGS u8 bitmap
*
* Properties of transmitted and received frames. See flags
* defined below.
*
* IEEE80211_RADIOTAP_ANTENNA u8 antenna index
*
* Unitless indication of the Rx/Tx antenna for this packet.
* The first antenna is antenna 0.
*
* IEEE80211_RADIOTAP_RX_FLAGS __le16 bitmap
*
* Properties of received frames. See flags defined below.
*
* IEEE80211_RADIOTAP_TX_FLAGS __le16 bitmap
*
* Properties of transmitted frames. See flags defined below.
*
* IEEE80211_RADIOTAP_RTS_RETRIES u8 data
*
* Number of rts retries a transmitted frame used.
*
* IEEE80211_RADIOTAP_DATA_RETRIES u8 data
*
* Number of unicast retries a transmitted frame used.
*
* IEEE80211_RADIOTAP_MCS u8, u8, u8 unitless
*
* Contains a bitmap of known fields/flags, the flags, and
* the MCS index.
*
* IEEE80211_RADIOTAP_AMPDU_STATUS u32, u16, u8, u8 unitless
*
* Contains the AMPDU information for the subframe.
*
* IEEE80211_RADIOTAP_VHT u16, u8, u8, u8[4], u8, u8, u16
*
* Contains VHT information about this frame.
*/
enum ieee80211_radiotap_type {
IEEE80211_RADIOTAP_TSFT = 0,
IEEE80211_RADIOTAP_FLAGS = 1,
IEEE80211_RADIOTAP_RATE = 2,
IEEE80211_RADIOTAP_CHANNEL = 3,
IEEE80211_RADIOTAP_FHSS = 4,
IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5,
IEEE80211_RADIOTAP_DBM_ANTNOISE = 6,
IEEE80211_RADIOTAP_LOCK_QUALITY = 7,
IEEE80211_RADIOTAP_TX_ATTENUATION = 8,
IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9,
IEEE80211_RADIOTAP_DBM_TX_POWER = 10,
IEEE80211_RADIOTAP_ANTENNA = 11,
IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12,
IEEE80211_RADIOTAP_DB_ANTNOISE = 13,
IEEE80211_RADIOTAP_RX_FLAGS = 14,
IEEE80211_RADIOTAP_TX_FLAGS = 15,
IEEE80211_RADIOTAP_RTS_RETRIES = 16,
IEEE80211_RADIOTAP_DATA_RETRIES = 17,
IEEE80211_RADIOTAP_MCS = 19,
IEEE80211_RADIOTAP_AMPDU_STATUS = 20,
IEEE80211_RADIOTAP_VHT = 21,
/* valid in every it_present bitmap, even vendor namespaces */
IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE = 29,
IEEE80211_RADIOTAP_VENDOR_NAMESPACE = 30,
IEEE80211_RADIOTAP_EXT = 31
};
/* Channel flags. */
#define IEEE80211_CHAN_TURBO 0x0010 /* Turbo channel */
#define IEEE80211_CHAN_CCK 0x0020 /* CCK channel */
#define IEEE80211_CHAN_OFDM 0x0040 /* OFDM channel */
#define IEEE80211_CHAN_2GHZ 0x0080 /* 2 GHz spectrum channel. */
#define IEEE80211_CHAN_5GHZ 0x0100 /* 5 GHz spectrum channel */
#define IEEE80211_CHAN_PASSIVE 0x0200 /* Only passive scan allowed */
#define IEEE80211_CHAN_DYN 0x0400 /* Dynamic CCK-OFDM channel */
#define IEEE80211_CHAN_GFSK 0x0800 /* GFSK channel (FHSS PHY) */
/* For IEEE80211_RADIOTAP_FLAGS */
#define IEEE80211_RADIOTAP_F_CFP 0x01 /* sent/received
* during CFP
*/
#define IEEE80211_RADIOTAP_F_SHORTPRE 0x02 /* sent/received
* with short
* preamble
*/
#define IEEE80211_RADIOTAP_F_WEP 0x04 /* sent/received
* with WEP encryption
*/
#define IEEE80211_RADIOTAP_F_FRAG 0x08 /* sent/received
* with fragmentation
*/
#define IEEE80211_RADIOTAP_F_FCS 0x10 /* frame includes FCS */
#define IEEE80211_RADIOTAP_F_DATAPAD 0x20 /* frame has padding between
* 802.11 header and payload
* (to 32-bit boundary)
*/
#define IEEE80211_RADIOTAP_F_BADFCS 0x40 /* bad FCS */
/* For IEEE80211_RADIOTAP_RX_FLAGS */
#define IEEE80211_RADIOTAP_F_RX_BADPLCP 0x0002 /* frame has bad PLCP */
/* For IEEE80211_RADIOTAP_TX_FLAGS */
#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive
* retries */
#define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */
#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */
#define IEEE80211_RADIOTAP_F_TX_NOACK 0x0008 /* don't expect an ack */
/* For IEEE80211_RADIOTAP_MCS */
#define IEEE80211_RADIOTAP_MCS_HAVE_BW 0x01
#define IEEE80211_RADIOTAP_MCS_HAVE_MCS 0x02
#define IEEE80211_RADIOTAP_MCS_HAVE_GI 0x04
#define IEEE80211_RADIOTAP_MCS_HAVE_FMT 0x08
#define IEEE80211_RADIOTAP_MCS_HAVE_FEC 0x10
#define IEEE80211_RADIOTAP_MCS_BW_MASK 0x03
#define IEEE80211_RADIOTAP_MCS_BW_20 0
#define IEEE80211_RADIOTAP_MCS_BW_40 1
#define IEEE80211_RADIOTAP_MCS_BW_20L 2
#define IEEE80211_RADIOTAP_MCS_BW_20U 3
#define IEEE80211_RADIOTAP_MCS_SGI 0x04
#define IEEE80211_RADIOTAP_MCS_FMT_GF 0x08
#define IEEE80211_RADIOTAP_MCS_FEC_LDPC 0x10
/* For IEEE80211_RADIOTAP_AMPDU_STATUS */
#define IEEE80211_RADIOTAP_AMPDU_REPORT_ZEROLEN 0x0001
#define IEEE80211_RADIOTAP_AMPDU_IS_ZEROLEN 0x0002
#define IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN 0x0004
#define IEEE80211_RADIOTAP_AMPDU_IS_LAST 0x0008
#define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR 0x0010
#define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN 0x0020
/* For IEEE80211_RADIOTAP_VHT */
#define IEEE80211_RADIOTAP_VHT_KNOWN_STBC 0x0001
#define IEEE80211_RADIOTAP_VHT_KNOWN_TXOP_PS_NA 0x0002
#define IEEE80211_RADIOTAP_VHT_KNOWN_GI 0x0004
#define IEEE80211_RADIOTAP_VHT_KNOWN_SGI_NSYM_DIS 0x0008
#define IEEE80211_RADIOTAP_VHT_KNOWN_LDPC_EXTRA_OFDM_SYM 0x0010
#define IEEE80211_RADIOTAP_VHT_KNOWN_BEAMFORMED 0x0020
#define IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH 0x0040
#define IEEE80211_RADIOTAP_VHT_KNOWN_GROUP_ID 0x0080
#define IEEE80211_RADIOTAP_VHT_KNOWN_PARTIAL_AID 0x0100
#define IEEE80211_RADIOTAP_VHT_FLAG_STBC 0x01
#define IEEE80211_RADIOTAP_VHT_FLAG_TXOP_PS_NA 0x02
#define IEEE80211_RADIOTAP_VHT_FLAG_SGI 0x04
#define IEEE80211_RADIOTAP_VHT_FLAG_SGI_NSYM_M10_9 0x08
#define IEEE80211_RADIOTAP_VHT_FLAG_LDPC_EXTRA_OFDM_SYM 0x10
#define IEEE80211_RADIOTAP_VHT_FLAG_BEAMFORMED 0x20
#endif /* IEEE80211_RADIOTAP_H */

View File

@ -0,0 +1,258 @@
// (c)2007 Andy Green <andy@warmcat.com>
// (r)2020 Michael Tetemke Mehari <michael.mehari@ugent.be>
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
// Thanks for contributions:
// 2007-03-15 fixes to getopt_long code by Matteo Croce rootkit85@yahoo.it
#include "inject_80211.h"
#include "radiotap.h"
/* wifi bitrate to use in 500kHz units */
static const u8 u8aRatesToUse[] = {
6*2,
9*2,
12*2,
18*2,
24*2,
36*2,
48*2,
54*2
};
/* this is the template radiotap header we send packets out with */
static const u8 u8aRadiotapHeader[] =
{
0x00, 0x00, // <-- radiotap version
0x1c, 0x00, // <- radiotap header length
0x6f, 0x08, 0x08, 0x00, // <-- bitmap
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // <-- timestamp
0x00, // <-- flags (Offset +0x10)
0x6c, // <-- rate (0ffset +0x11)
0x71, 0x09, 0xc0, 0x00, // <-- channel
0xde, // <-- antsignal
0x00, // <-- antnoise
0x01, // <-- antenna
0x02, 0x00, 0x0f, // <-- MCS
};
#define OFFSET_RATE 0x11
#define MCS_OFFSET 0x19
#define GI_OFFSET 0x1a
#define MCS_RATE_OFFSET 0x1b
/* IEEE80211 header */
static const u8 ieee_hdr[] =
{
0x08, 0x01, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x66, 0x55, 0x44, 0x33, 0x22, 0x11,
0x66, 0x55, 0x44, 0x33, 0x22, 0x11,
0x10, 0x86,
};
// Generate random string
void gen_rand_str(int size, char *rand_char)
{
int i, randNum = 0;
// Seed the random number generator with packet size
srand(size);
for (i = 0; i < size; i++)
{
// First, pick a number between 0 and 25.
randNum = 255 * (rand() / (RAND_MAX + 1.0));
if(randNum == 0)
{
i--;
continue;
}
// Type cast to character
rand_char[i] = (char) randNum;
}
rand_char[i] = '\0';
}
int flagHelp = 0;
void usage(void)
{
printf(
"(c)2006-2007 Andy Green <andy@warmcat.com> Licensed under GPL2\n"
"(r)2020 Michael Tetemke Mehari <michael.mehari@ugent.be>"
"\n"
"Usage: inject_80211 [options] <interface>\n\nOptions\n"
"-m/--hw_mode <hardware operation mode> (a,g,n)\n"
"-r/--rate_index <rate/MCS index> (0,1,2,3,4,5,6,7)\n"
"-i/--sgi_flag (0,1)\n"
"-n/--num_packets <number of packets>\n"
"-s/--payload_size <payload size in bytes>\n"
"-d/--delay <delay between packets in usec>\n"
"-h this menu\n\n"
"Example:\n"
" iw dev wlan0 interface add mon0 type monitor && ifconfig mon0 up\n"
" inject_80211 mon0\n"
"\n");
exit(1);
}
int main(int argc, char *argv[])
{
u8 buffer[1536];
char szErrbuf[PCAP_ERRBUF_SIZE], rand_char[1536], hw_mode = 'n';
int i, nLinkEncap = 0, r, rate_index = 0, sgi_flag = 0, num_packets = 10, payload_size = 64, packet_size, nDelay = 100000;
pcap_t *ppcap = NULL;
while (1)
{
int nOptionIndex;
static const struct option optiona[] =
{
{ "hw_mode", required_argument, NULL, 'm' },
{ "rate_index", required_argument, NULL, 'r' },
{ "sgi_flag", no_argument, NULL, 'i' },
{ "num_packets", required_argument, NULL, 'n' },
{ "payload_size", required_argument, NULL, 's' },
{ "delay", required_argument, NULL, 'd' },
{ "help", no_argument, &flagHelp, 1 },
{ 0, 0, 0, 0 }
};
int c = getopt_long(argc, argv, "m:r:i:n:s:d:h", optiona, &nOptionIndex);
if (c == -1)
break;
switch (c)
{
case 0: // long option
break;
case 'h':
usage();
case 'm':
hw_mode = optarg[0];
break;
case 'r':
rate_index = atoi(optarg);
break;
case 'i':
sgi_flag = atoi(optarg);
break;
case 'n':
num_packets = atoi(optarg);
break;
case 's':
payload_size = atoi(optarg);
break;
case 'd':
nDelay = atoi(optarg);
break;
default:
printf("unknown switch %c\n", c);
usage();
break;
}
}
if (optind >= argc)
usage();
// open the interface in pcap
szErrbuf[0] = '\0';
ppcap = pcap_open_live(argv[optind], 800, 1, 20, szErrbuf);
if (ppcap == NULL)
{
printf("Unable to open interface %s in pcap: %s\n", argv[optind], szErrbuf);
return (1);
}
nLinkEncap = pcap_datalink(ppcap);
switch (nLinkEncap)
{
case DLT_PRISM_HEADER:
printf("DLT_PRISM_HEADER Encap\n");
break;
case DLT_IEEE802_11_RADIO:
printf("DLT_IEEE802_11_RADIO Encap\n");
break;
default:
printf("!!! unknown encapsulation on %s !\n", argv[1]);
return (1);
}
pcap_setnonblock(ppcap, 1, szErrbuf);
// Generate random string
gen_rand_str(payload_size, rand_char);
packet_size = sizeof(u8aRadiotapHeader) + sizeof(ieee_hdr) + strlen(rand_char);
printf("mode = 802.11%c, rate index = %d, SHORT GI = %d, number of packets = %d and packet size = %d bytes, delay = %d usec\n", hw_mode, rate_index, sgi_flag, num_packets, packet_size, nDelay);
// Clear storage buffer
memset(buffer, 0, sizeof (buffer));
// Insert default radiotap header
memcpy(buffer, u8aRadiotapHeader, sizeof (u8aRadiotapHeader));
// Update radiotap header (i.e. hw_mode, rate, GI)
if(hw_mode == 'g' || hw_mode == 'a')
{
buffer[OFFSET_RATE] = u8aRatesToUse[rate_index];
buffer[MCS_OFFSET] = 0x00;
}
else
{
buffer[MCS_OFFSET] = 0x07;
if(sgi_flag)
buffer[GI_OFFSET] = IEEE80211_RADIOTAP_MCS_SGI;
buffer[MCS_RATE_OFFSET] = rate_index;
}
// Insert IEEE DATA header
memcpy(buffer + sizeof(u8aRadiotapHeader), ieee_hdr, sizeof (ieee_hdr));
// Insert IEEE DATA payload
sprintf((char *)(buffer + sizeof(u8aRadiotapHeader) + sizeof(ieee_hdr)), "%s", rand_char);
// Inject packets
for(i = 1; i <= num_packets; i++)
{
r = pcap_inject(ppcap, buffer, packet_size);
if (r != packet_size) {
perror("Trouble injecting packet");
return (1);
}
printf("number of packets sent = %d\r", i);
fflush(stdout);
if (nDelay)
usleep(nDelay);
}
printf("\n");
return (0);
}

View File

@ -0,0 +1,26 @@
#include <stdlib.h>
#include <resolv.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>
#include <pcap.h>
#include <errno.h>
typedef unsigned int u32;
typedef unsigned short u16;
typedef unsigned char u8;
typedef u32 __le32;
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define le16_to_cpu(x) (x)
#define le32_to_cpu(x) (x)
#else
#define le16_to_cpu(x) ((((x)&0xff)<<8)|(((x)&0xff00)>>8))
#define le32_to_cpu(x) \
((((x)&0xff)<<24)|(((x)&0xff00)<<8)|(((x)&0xff0000)>>8)|(((x)&0xff000000)>>24))
#endif
#define unlikely(x) (x)

View File

@ -0,0 +1,16 @@
#!/bin/bash
HW_MODE='n'
COUNT=100
DELAY=1000
RATE=( 0 1 2 3 4 5 6 7 )
SIZE=( $(seq -s' ' 50 100 1450) )
IF="mon0"
for (( i = 0 ; i < ${#SIZE[@]} ; i++ )) do
for (( j = 0 ; j < ${#RATE[@]} ; j++ )) do
inject_80211 -m $HW_MODE -n $COUNT -d $DELAY -r ${RATE[$j]} -s ${SIZE[$i]} $IF
sleep 1
done
done

View File

@ -0,0 +1,244 @@
/*
* Radiotap parser
*
* Copyright 2007 Andy Green <andy@warmcat.com>
*/
#include "inject_80211.h"
#include "radiotap.h"
/**
* ieee80211_radiotap_iterator_init - radiotap parser iterator initialization
* @iterator: radiotap_iterator to initialize
* @radiotap_header: radiotap header to parse
* @max_length: total length we can parse into (eg, whole packet length)
*
* Returns: 0 or a negative error code if there is a problem.
*
* This function initializes an opaque iterator struct which can then
* be passed to ieee80211_radiotap_iterator_next() to visit every radiotap
* argument which is present in the header. It knows about extended
* present headers and handles them.
*
* How to use:
* call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator
* struct ieee80211_radiotap_iterator (no need to init the struct beforehand)
* checking for a good 0 return code. Then loop calling
* __ieee80211_radiotap_iterator_next()... it returns either 0,
* -ENOENT if there are no more args to parse, or -EINVAL if there is a problem.
* The iterator's @this_arg member points to the start of the argument
* associated with the current argument index that is present, which can be
* found in the iterator's @this_arg_index member. This arg index corresponds
* to the IEEE80211_RADIOTAP_... defines.
*
* Radiotap header length:
* You can find the CPU-endian total radiotap header length in
* iterator->max_length after executing ieee80211_radiotap_iterator_init()
* successfully.
*
* Example code:
* See Documentation/networking/radiotap-headers.txt
*/
int ieee80211_radiotap_iterator_init(
struct ieee80211_radiotap_iterator *iterator,
struct ieee80211_radiotap_header *radiotap_header,
int max_length)
{
/* Linux only supports version 0 radiotap format */
if (radiotap_header->it_version)
return -EINVAL;
/* sanity check for allowed length and radiotap length field */
if (max_length < le16_to_cpu(radiotap_header->it_len))
return -EINVAL;
iterator->rtheader = radiotap_header;
iterator->max_length = le16_to_cpu(radiotap_header->it_len);
iterator->arg_index = 0;
iterator->bitmap_shifter = le32_to_cpu(radiotap_header->it_present);
iterator->arg = (u8 *)radiotap_header + sizeof(*radiotap_header);
iterator->this_arg = 0;
/* find payload start allowing for extended bitmap(s) */
if (unlikely(iterator->bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT))) {
while (le32_to_cpu(*((u32 *)iterator->arg)) &
(1<<IEEE80211_RADIOTAP_EXT)) {
iterator->arg += sizeof(u32);
/*
* check for insanity where the present bitmaps
* keep claiming to extend up to or even beyond the
* stated radiotap header length
*/
if (((ulong)iterator->arg -
(ulong)iterator->rtheader) > iterator->max_length)
return -EINVAL;
}
iterator->arg += sizeof(u32);
/*
* no need to check again for blowing past stated radiotap
* header length, because ieee80211_radiotap_iterator_next
* checks it before it is dereferenced
*/
}
/* we are all initialized happily */
return 0;
}
/**
* ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg
* @iterator: radiotap_iterator to move to next arg (if any)
*
* Returns: 0 if there is an argument to handle,
* -ENOENT if there are no more args or -EINVAL
* if there is something else wrong.
*
* This function provides the next radiotap arg index (IEEE80211_RADIOTAP_*)
* in @this_arg_index and sets @this_arg to point to the
* payload for the field. It takes care of alignment handling and extended
* present fields. @this_arg can be changed by the caller (eg,
* incremented to move inside a compound argument like
* IEEE80211_RADIOTAP_CHANNEL). The args pointed to are in
* little-endian format whatever the endianess of your CPU.
*/
int ieee80211_radiotap_iterator_next(
struct ieee80211_radiotap_iterator *iterator)
{
/*
* small length lookup table for all radiotap types we heard of
* starting from b0 in the bitmap, so we can walk the payload
* area of the radiotap header
*
* There is a requirement to pad args, so that args
* of a given length must begin at a boundary of that length
* -- but note that compound args are allowed (eg, 2 x u16
* for IEEE80211_RADIOTAP_CHANNEL) so total arg length is not
* a reliable indicator of alignment requirement.
*
* upper nybble: content alignment for arg
* lower nybble: content length for arg
*/
static const u8 rt_sizes[] = {
[IEEE80211_RADIOTAP_TSFT] = 0x88,
[IEEE80211_RADIOTAP_FLAGS] = 0x11,
[IEEE80211_RADIOTAP_RATE] = 0x11,
[IEEE80211_RADIOTAP_CHANNEL] = 0x24,
[IEEE80211_RADIOTAP_FHSS] = 0x22,
[IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = 0x11,
[IEEE80211_RADIOTAP_DBM_ANTNOISE] = 0x11,
[IEEE80211_RADIOTAP_LOCK_QUALITY] = 0x22,
[IEEE80211_RADIOTAP_TX_ATTENUATION] = 0x22,
[IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = 0x22,
[IEEE80211_RADIOTAP_DBM_TX_POWER] = 0x11,
[IEEE80211_RADIOTAP_ANTENNA] = 0x11,
[IEEE80211_RADIOTAP_DB_ANTSIGNAL] = 0x11,
[IEEE80211_RADIOTAP_DB_ANTNOISE] = 0x11,
[IEEE80211_RADIOTAP_RX_FLAGS] = 0x22,
[IEEE80211_RADIOTAP_TX_FLAGS] = 0x22,
[IEEE80211_RADIOTAP_RTS_RETRIES] = 0x11,
[IEEE80211_RADIOTAP_DATA_RETRIES] = 0x11,
[IEEE80211_RADIOTAP_MCS] = 0x13,
[IEEE80211_RADIOTAP_AMPDU_STATUS] = 0x48
/*
* add more here as they are defined in
* include/net/ieee80211_radiotap.h
*/
};
/*
* for every radiotap entry we can at
* least skip (by knowing the length)...
*/
while (iterator->arg_index < sizeof(rt_sizes)) {
int hit = 0;
int pad;
if (!(iterator->bitmap_shifter & 1))
goto next_entry; /* arg not present */
/*
* arg is present, account for alignment padding
* 8-bit args can be at any alignment
* 16-bit args must start on 16-bit boundary
* 32-bit args must start on 32-bit boundary
* 64-bit args must start on 64-bit boundary
*
* note that total arg size can differ from alignment of
* elements inside arg, so we use upper nybble of length
* table to base alignment on
*
* also note: these alignments are ** relative to the
* start of the radiotap header **. There is no guarantee
* that the radiotap header itself is aligned on any
* kind of boundary.
*/
pad = (((ulong)iterator->arg) -
((ulong)iterator->rtheader)) &
((rt_sizes[iterator->arg_index] >> 4) - 1);
if (pad)
iterator->arg +=
(rt_sizes[iterator->arg_index] >> 4) - pad;
/*
* this is what we will return to user, but we need to
* move on first so next call has something fresh to test
*/
iterator->this_arg_index = iterator->arg_index;
iterator->this_arg = iterator->arg;
hit = 1;
/* internally move on the size of this arg */
iterator->arg += rt_sizes[iterator->arg_index] & 0x0f;
/*
* check for insanity where we are given a bitmap that
* claims to have more arg content than the length of the
* radiotap section. We will normally end up equalling this
* max_length on the last arg, never exceeding it.
*/
if (((ulong)iterator->arg - (ulong)iterator->rtheader) >
iterator->max_length)
return -EINVAL;
next_entry:
iterator->arg_index++;
if (unlikely((iterator->arg_index & 31) == 0)) {
/* completed current u32 bitmap */
if (iterator->bitmap_shifter & 1) {
/* b31 was set, there is more */
/* move to next u32 bitmap */
iterator->bitmap_shifter =
le32_to_cpu(*iterator->next_bitmap);
iterator->next_bitmap++;
} else {
/* no more bitmaps: end */
iterator->arg_index = sizeof(rt_sizes);
}
} else { /* just try the next bit */
iterator->bitmap_shifter >>= 1;
}
/* if we found a valid arg earlier, return it now */
if (hit)
return 0;
}
/* we don't know how to handle any more args, we're done */
return -ENOENT;
}

View File

@ -0,0 +1,38 @@
#include "ieee80211_radiotap.h"
/* Radiotap header iteration
* implemented in net/wireless/radiotap.c
* docs in Documentation/networking/radiotap-headers.txt
*/
/**
* struct ieee80211_radiotap_iterator - tracks walk thru present radiotap args
* @rtheader: pointer to the radiotap header we are walking through
* @max_length: length of radiotap header in cpu byte ordering
* @this_arg_index: IEEE80211_RADIOTAP_... index of current arg
* @this_arg: pointer to current radiotap arg
* @arg_index: internal next argument index
* @arg: internal next argument pointer
* @next_bitmap: internal pointer to next present u32
* @bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present
*/
struct ieee80211_radiotap_iterator {
struct ieee80211_radiotap_header *rtheader;
int max_length;
int this_arg_index;
u8 *this_arg;
int arg_index;
u8 *arg;
__le32 *next_bitmap;
u32 bitmap_shifter;
};
extern int ieee80211_radiotap_iterator_init(
struct ieee80211_radiotap_iterator *iterator,
struct ieee80211_radiotap_header *radiotap_header,
int max_length);
extern int ieee80211_radiotap_iterator_next(
struct ieee80211_radiotap_iterator *iterator);

View File

@ -0,0 +1,948 @@
/*
Copyright (c) 2003-2013, Troy D. Hanson http://troydhanson.github.com/uthash/
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef UTHASH_H
#define UTHASH_H
#include <string.h> /* memcmp,strlen */
#include <stddef.h> /* ptrdiff_t */
#include <stdlib.h> /* exit() */
/* These macros use decltype or the earlier __typeof GNU extension.
As decltype is only available in newer compilers (VS2010 or gcc 4.3+
when compiling c++ source) this code uses whatever method is needed
or, for VS2008 where neither is available, uses casting workarounds. */
#ifdef _MSC_VER /* MS compiler */
#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */
#define DECLTYPE(x) (decltype(x))
#else /* VS2008 or older (or VS2010 in C mode) */
#define NO_DECLTYPE
#define DECLTYPE(x)
#endif
#else /* GNU, Sun and other compilers */
#define DECLTYPE(x) (__typeof(x))
#endif
#ifdef NO_DECLTYPE
#define DECLTYPE_ASSIGN(dst,src) \
do { \
char **_da_dst = (char**)(&(dst)); \
*_da_dst = (char*)(src); \
} while(0)
#else
#define DECLTYPE_ASSIGN(dst,src) \
do { \
(dst) = DECLTYPE(dst)(src); \
} while(0)
#endif
/* a number of the hash function use uint32_t which isn't defined on win32 */
#ifdef _MSC_VER
typedef unsigned int uint32_t;
typedef unsigned char uint8_t;
#else
#include <inttypes.h> /* uint32_t */
#endif
#define UTHASH_VERSION 1.9.8
#ifndef uthash_fatal
#define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */
#endif
#ifndef uthash_malloc
#define uthash_malloc(sz) malloc(sz) /* malloc fcn */
#endif
#ifndef uthash_free
#define uthash_free(ptr,sz) free(ptr) /* free fcn */
#endif
#ifndef uthash_noexpand_fyi
#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */
#endif
#ifndef uthash_expand_fyi
#define uthash_expand_fyi(tbl) /* can be defined to log expands */
#endif
/* initial number of buckets */
#define HASH_INITIAL_NUM_BUCKETS 32 /* initial number of buckets */
#define HASH_INITIAL_NUM_BUCKETS_LOG2 5 /* lg2 of initial number of buckets */
#define HASH_BKT_CAPACITY_THRESH 10 /* expand when bucket count reaches */
/* calculate the element whose hash handle address is hhe */
#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho)))
#define HASH_FIND(hh,head,keyptr,keylen,out) \
do { \
unsigned _hf_bkt,_hf_hashv; \
out=NULL; \
if (head) { \
HASH_FCN(keyptr,keylen, (head)->hh.tbl->num_buckets, _hf_hashv, _hf_bkt); \
if (HASH_BLOOM_TEST((head)->hh.tbl, _hf_hashv)) { \
HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], \
keyptr,keylen,out); \
} \
} \
} while (0)
#ifdef HASH_BLOOM
#define HASH_BLOOM_BITLEN (1ULL << HASH_BLOOM)
#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8) + ((HASH_BLOOM_BITLEN%8) ? 1:0)
#define HASH_BLOOM_MAKE(tbl) \
do { \
(tbl)->bloom_nbits = HASH_BLOOM; \
(tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \
if (!((tbl)->bloom_bv)) { uthash_fatal( "out of memory"); } \
memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN); \
(tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \
} while (0)
#define HASH_BLOOM_FREE(tbl) \
do { \
uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \
} while (0)
#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8] |= (1U << ((idx)%8)))
#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8] & (1U << ((idx)%8)))
#define HASH_BLOOM_ADD(tbl,hashv) \
HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1)))
#define HASH_BLOOM_TEST(tbl,hashv) \
HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1)))
#else
#define HASH_BLOOM_MAKE(tbl)
#define HASH_BLOOM_FREE(tbl)
#define HASH_BLOOM_ADD(tbl,hashv)
#define HASH_BLOOM_TEST(tbl,hashv) (1)
#define HASH_BLOOM_BYTELEN 0
#endif
#define HASH_MAKE_TABLE(hh,head) \
do { \
(head)->hh.tbl = (UT_hash_table*)uthash_malloc( \
sizeof(UT_hash_table)); \
if (!((head)->hh.tbl)) { uthash_fatal( "out of memory"); } \
memset((head)->hh.tbl, 0, sizeof(UT_hash_table)); \
(head)->hh.tbl->tail = &((head)->hh); \
(head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \
(head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \
(head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \
(head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \
HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \
if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); } \
memset((head)->hh.tbl->buckets, 0, \
HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \
HASH_BLOOM_MAKE((head)->hh.tbl); \
(head)->hh.tbl->signature = HASH_SIGNATURE; \
} while(0)
#define HASH_ADD(hh,head,fieldname,keylen_in,add) \
HASH_ADD_KEYPTR(hh,head,&((add)->fieldname),keylen_in,add)
#define HASH_REPLACE(hh,head,fieldname,keylen_in,add,replaced) \
do { \
replaced=NULL; \
HASH_FIND(hh,head,&((add)->fieldname),keylen_in,replaced); \
if (replaced!=NULL) { \
HASH_DELETE(hh,head,replaced); \
}; \
HASH_ADD(hh,head,fieldname,keylen_in,add); \
} while(0)
#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \
do { \
unsigned _ha_bkt; \
(add)->hh.next = NULL; \
(add)->hh.key = (char*)(keyptr); \
(add)->hh.keylen = (unsigned)(keylen_in); \
if (!(head)) { \
head = (add); \
(head)->hh.prev = NULL; \
HASH_MAKE_TABLE(hh,head); \
} else { \
(head)->hh.tbl->tail->next = (add); \
(add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \
(head)->hh.tbl->tail = &((add)->hh); \
} \
(head)->hh.tbl->num_items++; \
(add)->hh.tbl = (head)->hh.tbl; \
HASH_FCN(keyptr,keylen_in, (head)->hh.tbl->num_buckets, \
(add)->hh.hashv, _ha_bkt); \
HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt],&(add)->hh); \
HASH_BLOOM_ADD((head)->hh.tbl,(add)->hh.hashv); \
HASH_EMIT_KEY(hh,head,keyptr,keylen_in); \
HASH_FSCK(hh,head); \
} while(0)
#define HASH_TO_BKT( hashv, num_bkts, bkt ) \
do { \
bkt = ((hashv) & ((num_bkts) - 1)); \
} while(0)
/* delete "delptr" from the hash table.
* "the usual" patch-up process for the app-order doubly-linked-list.
* The use of _hd_hh_del below deserves special explanation.
* These used to be expressed using (delptr) but that led to a bug
* if someone used the same symbol for the head and deletee, like
* HASH_DELETE(hh,users,users);
* We want that to work, but by changing the head (users) below
* we were forfeiting our ability to further refer to the deletee (users)
* in the patch-up process. Solution: use scratch space to
* copy the deletee pointer, then the latter references are via that
* scratch pointer rather than through the repointed (users) symbol.
*/
#define HASH_DELETE(hh,head,delptr) \
do { \
unsigned _hd_bkt; \
struct UT_hash_handle *_hd_hh_del; \
if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) ) { \
uthash_free((head)->hh.tbl->buckets, \
(head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \
HASH_BLOOM_FREE((head)->hh.tbl); \
uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \
head = NULL; \
} else { \
_hd_hh_del = &((delptr)->hh); \
if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) { \
(head)->hh.tbl->tail = \
(UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \
(head)->hh.tbl->hho); \
} \
if ((delptr)->hh.prev) { \
((UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \
(head)->hh.tbl->hho))->next = (delptr)->hh.next; \
} else { \
DECLTYPE_ASSIGN(head,(delptr)->hh.next); \
} \
if (_hd_hh_del->next) { \
((UT_hash_handle*)((ptrdiff_t)_hd_hh_del->next + \
(head)->hh.tbl->hho))->prev = \
_hd_hh_del->prev; \
} \
HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \
HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \
(head)->hh.tbl->num_items--; \
} \
HASH_FSCK(hh,head); \
} while (0)
/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */
#define HASH_FIND_STR(head,findstr,out) \
HASH_FIND(hh,head,findstr,strlen(findstr),out)
#define HASH_ADD_STR(head,strfield,add) \
HASH_ADD(hh,head,strfield,strlen(add->strfield),add)
#define HASH_REPLACE_STR(head,strfield,add,replaced) \
HASH_REPLACE(hh,head,strfield,strlen(add->strfield),add,replaced)
#define HASH_FIND_INT(head,findint,out) \
HASH_FIND(hh,head,findint,sizeof(int),out)
#define HASH_ADD_INT(head,intfield,add) \
HASH_ADD(hh,head,intfield,sizeof(int),add)
#define HASH_REPLACE_INT(head,intfield,add,replaced) \
HASH_REPLACE(hh,head,intfield,sizeof(int),add,replaced)
#define HASH_FIND_PTR(head,findptr,out) \
HASH_FIND(hh,head,findptr,sizeof(void *),out)
#define HASH_ADD_PTR(head,ptrfield,add) \
HASH_ADD(hh,head,ptrfield,sizeof(void *),add)
#define HASH_REPLACE_PTR(head,ptrfield,add,replaced) \
HASH_REPLACE(hh,head,ptrfield,sizeof(void *),add,replaced)
#define HASH_DEL(head,delptr) \
HASH_DELETE(hh,head,delptr)
/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined.
* This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined.
*/
#ifdef HASH_DEBUG
#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0)
#define HASH_FSCK(hh,head) \
do { \
unsigned _bkt_i; \
unsigned _count, _bkt_count; \
char *_prev; \
struct UT_hash_handle *_thh; \
if (head) { \
_count = 0; \
for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) { \
_bkt_count = 0; \
_thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \
_prev = NULL; \
while (_thh) { \
if (_prev != (char*)(_thh->hh_prev)) { \
HASH_OOPS("invalid hh_prev %p, actual %p\n", \
_thh->hh_prev, _prev ); \
} \
_bkt_count++; \
_prev = (char*)(_thh); \
_thh = _thh->hh_next; \
} \
_count += _bkt_count; \
if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \
HASH_OOPS("invalid bucket count %d, actual %d\n", \
(head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \
} \
} \
if (_count != (head)->hh.tbl->num_items) { \
HASH_OOPS("invalid hh item count %d, actual %d\n", \
(head)->hh.tbl->num_items, _count ); \
} \
/* traverse hh in app order; check next/prev integrity, count */ \
_count = 0; \
_prev = NULL; \
_thh = &(head)->hh; \
while (_thh) { \
_count++; \
if (_prev !=(char*)(_thh->prev)) { \
HASH_OOPS("invalid prev %p, actual %p\n", \
_thh->prev, _prev ); \
} \
_prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \
_thh = ( _thh->next ? (UT_hash_handle*)((char*)(_thh->next) + \
(head)->hh.tbl->hho) : NULL ); \
} \
if (_count != (head)->hh.tbl->num_items) { \
HASH_OOPS("invalid app item count %d, actual %d\n", \
(head)->hh.tbl->num_items, _count ); \
} \
} \
} while (0)
#else
#define HASH_FSCK(hh,head)
#endif
/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to
* the descriptor to which this macro is defined for tuning the hash function.
* The app can #include <unistd.h> to get the prototype for write(2). */
#ifdef HASH_EMIT_KEYS
#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \
do { \
unsigned _klen = fieldlen; \
write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \
write(HASH_EMIT_KEYS, keyptr, fieldlen); \
} while (0)
#else
#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen)
#endif
/* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */
#ifdef HASH_FUNCTION
#define HASH_FCN HASH_FUNCTION
#else
#define HASH_FCN HASH_JEN
#endif
/* The Bernstein hash function, used in Perl prior to v5.6 */
#define HASH_BER(key,keylen,num_bkts,hashv,bkt) \
do { \
unsigned _hb_keylen=keylen; \
char *_hb_key=(char*)(key); \
(hashv) = 0; \
while (_hb_keylen--) { (hashv) = ((hashv) * 33) + *_hb_key++; } \
bkt = (hashv) & (num_bkts-1); \
} while (0)
/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at
* http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */
#define HASH_SAX(key,keylen,num_bkts,hashv,bkt) \
do { \
unsigned _sx_i; \
char *_hs_key=(char*)(key); \
hashv = 0; \
for(_sx_i=0; _sx_i < keylen; _sx_i++) \
hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \
bkt = hashv & (num_bkts-1); \
} while (0)
#define HASH_FNV(key,keylen,num_bkts,hashv,bkt) \
do { \
unsigned _fn_i; \
char *_hf_key=(char*)(key); \
hashv = 2166136261UL; \
for(_fn_i=0; _fn_i < keylen; _fn_i++) \
hashv = (hashv * 16777619) ^ _hf_key[_fn_i]; \
bkt = hashv & (num_bkts-1); \
} while(0)
#define HASH_OAT(key,keylen,num_bkts,hashv,bkt) \
do { \
unsigned _ho_i; \
char *_ho_key=(char*)(key); \
hashv = 0; \
for(_ho_i=0; _ho_i < keylen; _ho_i++) { \
hashv += _ho_key[_ho_i]; \
hashv += (hashv << 10); \
hashv ^= (hashv >> 6); \
} \
hashv += (hashv << 3); \
hashv ^= (hashv >> 11); \
hashv += (hashv << 15); \
bkt = hashv & (num_bkts-1); \
} while(0)
#define HASH_JEN_MIX(a,b,c) \
do { \
a -= b; a -= c; a ^= ( c >> 13 ); \
b -= c; b -= a; b ^= ( a << 8 ); \
c -= a; c -= b; c ^= ( b >> 13 ); \
a -= b; a -= c; a ^= ( c >> 12 ); \
b -= c; b -= a; b ^= ( a << 16 ); \
c -= a; c -= b; c ^= ( b >> 5 ); \
a -= b; a -= c; a ^= ( c >> 3 ); \
b -= c; b -= a; b ^= ( a << 10 ); \
c -= a; c -= b; c ^= ( b >> 15 ); \
} while (0)
#define HASH_JEN(key,keylen,num_bkts,hashv,bkt) \
do { \
unsigned _hj_i,_hj_j,_hj_k; \
unsigned char *_hj_key=(unsigned char*)(key); \
hashv = 0xfeedbeef; \
_hj_i = _hj_j = 0x9e3779b9; \
_hj_k = (unsigned)(keylen); \
while (_hj_k >= 12) { \
_hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \
+ ( (unsigned)_hj_key[2] << 16 ) \
+ ( (unsigned)_hj_key[3] << 24 ) ); \
_hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \
+ ( (unsigned)_hj_key[6] << 16 ) \
+ ( (unsigned)_hj_key[7] << 24 ) ); \
hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \
+ ( (unsigned)_hj_key[10] << 16 ) \
+ ( (unsigned)_hj_key[11] << 24 ) ); \
\
HASH_JEN_MIX(_hj_i, _hj_j, hashv); \
\
_hj_key += 12; \
_hj_k -= 12; \
} \
hashv += keylen; \
switch ( _hj_k ) { \
case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); \
case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); \
case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); \
case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); \
case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); \
case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); \
case 5: _hj_j += _hj_key[4]; \
case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); \
case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); \
case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); \
case 1: _hj_i += _hj_key[0]; \
} \
HASH_JEN_MIX(_hj_i, _hj_j, hashv); \
bkt = hashv & (num_bkts-1); \
} while(0)
/* The Paul Hsieh hash function */
#undef get16bits
#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
|| defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
#define get16bits(d) (*((const uint16_t *) (d)))
#endif
#if !defined (get16bits)
#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \
+(uint32_t)(((const uint8_t *)(d))[0]) )
#endif
#define HASH_SFH(key,keylen,num_bkts,hashv,bkt) \
do { \
unsigned char *_sfh_key=(unsigned char*)(key); \
uint32_t _sfh_tmp, _sfh_len = keylen; \
\
int _sfh_rem = _sfh_len & 3; \
_sfh_len >>= 2; \
hashv = 0xcafebabe; \
\
/* Main loop */ \
for (;_sfh_len > 0; _sfh_len--) { \
hashv += get16bits (_sfh_key); \
_sfh_tmp = (uint32_t)(get16bits (_sfh_key+2)) << 11 ^ hashv; \
hashv = (hashv << 16) ^ _sfh_tmp; \
_sfh_key += 2*sizeof (uint16_t); \
hashv += hashv >> 11; \
} \
\
/* Handle end cases */ \
switch (_sfh_rem) { \
case 3: hashv += get16bits (_sfh_key); \
hashv ^= hashv << 16; \
hashv ^= (uint32_t)(_sfh_key[sizeof (uint16_t)] << 18); \
hashv += hashv >> 11; \
break; \
case 2: hashv += get16bits (_sfh_key); \
hashv ^= hashv << 11; \
hashv += hashv >> 17; \
break; \
case 1: hashv += *_sfh_key; \
hashv ^= hashv << 10; \
hashv += hashv >> 1; \
} \
\
/* Force "avalanching" of final 127 bits */ \
hashv ^= hashv << 3; \
hashv += hashv >> 5; \
hashv ^= hashv << 4; \
hashv += hashv >> 17; \
hashv ^= hashv << 25; \
hashv += hashv >> 6; \
bkt = hashv & (num_bkts-1); \
} while(0)
#ifdef HASH_USING_NO_STRICT_ALIASING
/* The MurmurHash exploits some CPU's (x86,x86_64) tolerance for unaligned reads.
* For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error.
* MurmurHash uses the faster approach only on CPU's where we know it's safe.
*
* Note the preprocessor built-in defines can be emitted using:
*
* gcc -m64 -dM -E - < /dev/null (on gcc)
* cc -## a.c (where a.c is a simple test file) (Sun Studio)
*/
#if (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86))
#define MUR_GETBLOCK(p,i) p[i]
#else /* non intel */
#define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 0x3) == 0)
#define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 0x3) == 1)
#define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 0x3) == 2)
#define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 0x3) == 3)
#define WP(p) ((uint32_t*)((unsigned long)(p) & ~3UL))
#if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__))
#define MUR_THREE_ONE(p) ((((*WP(p))&0x00ffffff) << 8) | (((*(WP(p)+1))&0xff000000) >> 24))
#define MUR_TWO_TWO(p) ((((*WP(p))&0x0000ffff) <<16) | (((*(WP(p)+1))&0xffff0000) >> 16))
#define MUR_ONE_THREE(p) ((((*WP(p))&0x000000ff) <<24) | (((*(WP(p)+1))&0xffffff00) >> 8))
#else /* assume little endian non-intel */
#define MUR_THREE_ONE(p) ((((*WP(p))&0xffffff00) >> 8) | (((*(WP(p)+1))&0x000000ff) << 24))
#define MUR_TWO_TWO(p) ((((*WP(p))&0xffff0000) >>16) | (((*(WP(p)+1))&0x0000ffff) << 16))
#define MUR_ONE_THREE(p) ((((*WP(p))&0xff000000) >>24) | (((*(WP(p)+1))&0x00ffffff) << 8))
#endif
#define MUR_GETBLOCK(p,i) (MUR_PLUS0_ALIGNED(p) ? ((p)[i]) : \
(MUR_PLUS1_ALIGNED(p) ? MUR_THREE_ONE(p) : \
(MUR_PLUS2_ALIGNED(p) ? MUR_TWO_TWO(p) : \
MUR_ONE_THREE(p))))
#endif
#define MUR_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r))))
#define MUR_FMIX(_h) \
do { \
_h ^= _h >> 16; \
_h *= 0x85ebca6b; \
_h ^= _h >> 13; \
_h *= 0xc2b2ae35l; \
_h ^= _h >> 16; \
} while(0)
#define HASH_MUR(key,keylen,num_bkts,hashv,bkt) \
do { \
const uint8_t *_mur_data = (const uint8_t*)(key); \
const int _mur_nblocks = (keylen) / 4; \
uint32_t _mur_h1 = 0xf88D5353; \
uint32_t _mur_c1 = 0xcc9e2d51; \
uint32_t _mur_c2 = 0x1b873593; \
uint32_t _mur_k1 = 0; \
const uint8_t *_mur_tail; \
const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+_mur_nblocks*4); \
int _mur_i; \
for(_mur_i = -_mur_nblocks; _mur_i; _mur_i++) { \
_mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i); \
_mur_k1 *= _mur_c1; \
_mur_k1 = MUR_ROTL32(_mur_k1,15); \
_mur_k1 *= _mur_c2; \
\
_mur_h1 ^= _mur_k1; \
_mur_h1 = MUR_ROTL32(_mur_h1,13); \
_mur_h1 = _mur_h1*5+0xe6546b64; \
} \
_mur_tail = (const uint8_t*)(_mur_data + _mur_nblocks*4); \
_mur_k1=0; \
switch((keylen) & 3) { \
case 3: _mur_k1 ^= _mur_tail[2] << 16; \
case 2: _mur_k1 ^= _mur_tail[1] << 8; \
case 1: _mur_k1 ^= _mur_tail[0]; \
_mur_k1 *= _mur_c1; \
_mur_k1 = MUR_ROTL32(_mur_k1,15); \
_mur_k1 *= _mur_c2; \
_mur_h1 ^= _mur_k1; \
} \
_mur_h1 ^= (keylen); \
MUR_FMIX(_mur_h1); \
hashv = _mur_h1; \
bkt = hashv & (num_bkts-1); \
} while(0)
#endif /* HASH_USING_NO_STRICT_ALIASING */
/* key comparison function; return 0 if keys equal */
#define HASH_KEYCMP(a,b,len) memcmp(a,b,len)
/* iterate over items in a known bucket to find desired item */
#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,out) \
do { \
if (head.hh_head) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,head.hh_head)); \
else out=NULL; \
while (out) { \
if ((out)->hh.keylen == keylen_in) { \
if ((HASH_KEYCMP((out)->hh.key,keyptr,keylen_in)) == 0) break; \
} \
if ((out)->hh.hh_next) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,(out)->hh.hh_next)); \
else out = NULL; \
} \
} while(0)
/* add an item to a bucket */
#define HASH_ADD_TO_BKT(head,addhh) \
do { \
head.count++; \
(addhh)->hh_next = head.hh_head; \
(addhh)->hh_prev = NULL; \
if (head.hh_head) { (head).hh_head->hh_prev = (addhh); } \
(head).hh_head=addhh; \
if (head.count >= ((head.expand_mult+1) * HASH_BKT_CAPACITY_THRESH) \
&& (addhh)->tbl->noexpand != 1) { \
HASH_EXPAND_BUCKETS((addhh)->tbl); \
} \
} while(0)
/* remove an item from a given bucket */
#define HASH_DEL_IN_BKT(hh,head,hh_del) \
(head).count--; \
if ((head).hh_head == hh_del) { \
(head).hh_head = hh_del->hh_next; \
} \
if (hh_del->hh_prev) { \
hh_del->hh_prev->hh_next = hh_del->hh_next; \
} \
if (hh_del->hh_next) { \
hh_del->hh_next->hh_prev = hh_del->hh_prev; \
}
/* Bucket expansion has the effect of doubling the number of buckets
* and redistributing the items into the new buckets. Ideally the
* items will distribute more or less evenly into the new buckets
* (the extent to which this is true is a measure of the quality of
* the hash function as it applies to the key domain).
*
* With the items distributed into more buckets, the chain length
* (item count) in each bucket is reduced. Thus by expanding buckets
* the hash keeps a bound on the chain length. This bounded chain
* length is the essence of how a hash provides constant time lookup.
*
* The calculation of tbl->ideal_chain_maxlen below deserves some
* explanation. First, keep in mind that we're calculating the ideal
* maximum chain length based on the *new* (doubled) bucket count.
* In fractions this is just n/b (n=number of items,b=new num buckets).
* Since the ideal chain length is an integer, we want to calculate
* ceil(n/b). We don't depend on floating point arithmetic in this
* hash, so to calculate ceil(n/b) with integers we could write
*
* ceil(n/b) = (n/b) + ((n%b)?1:0)
*
* and in fact a previous version of this hash did just that.
* But now we have improved things a bit by recognizing that b is
* always a power of two. We keep its base 2 log handy (call it lb),
* so now we can write this with a bit shift and logical AND:
*
* ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0)
*
*/
#define HASH_EXPAND_BUCKETS(tbl) \
do { \
unsigned _he_bkt; \
unsigned _he_bkt_i; \
struct UT_hash_handle *_he_thh, *_he_hh_nxt; \
UT_hash_bucket *_he_new_buckets, *_he_newbkt; \
_he_new_buckets = (UT_hash_bucket*)uthash_malloc( \
2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \
if (!_he_new_buckets) { uthash_fatal( "out of memory"); } \
memset(_he_new_buckets, 0, \
2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \
tbl->ideal_chain_maxlen = \
(tbl->num_items >> (tbl->log2_num_buckets+1)) + \
((tbl->num_items & ((tbl->num_buckets*2)-1)) ? 1 : 0); \
tbl->nonideal_items = 0; \
for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++) \
{ \
_he_thh = tbl->buckets[ _he_bkt_i ].hh_head; \
while (_he_thh) { \
_he_hh_nxt = _he_thh->hh_next; \
HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2, _he_bkt); \
_he_newbkt = &(_he_new_buckets[ _he_bkt ]); \
if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) { \
tbl->nonideal_items++; \
_he_newbkt->expand_mult = _he_newbkt->count / \
tbl->ideal_chain_maxlen; \
} \
_he_thh->hh_prev = NULL; \
_he_thh->hh_next = _he_newbkt->hh_head; \
if (_he_newbkt->hh_head) _he_newbkt->hh_head->hh_prev = \
_he_thh; \
_he_newbkt->hh_head = _he_thh; \
_he_thh = _he_hh_nxt; \
} \
} \
uthash_free( tbl->buckets, tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \
tbl->num_buckets *= 2; \
tbl->log2_num_buckets++; \
tbl->buckets = _he_new_buckets; \
tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ? \
(tbl->ineff_expands+1) : 0; \
if (tbl->ineff_expands > 1) { \
tbl->noexpand=1; \
uthash_noexpand_fyi(tbl); \
} \
uthash_expand_fyi(tbl); \
} while(0)
/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */
/* Note that HASH_SORT assumes the hash handle name to be hh.
* HASH_SRT was added to allow the hash handle name to be passed in. */
#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn)
#define HASH_SRT(hh,head,cmpfcn) \
do { \
unsigned _hs_i; \
unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \
struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \
if (head) { \
_hs_insize = 1; \
_hs_looping = 1; \
_hs_list = &((head)->hh); \
while (_hs_looping) { \
_hs_p = _hs_list; \
_hs_list = NULL; \
_hs_tail = NULL; \
_hs_nmerges = 0; \
while (_hs_p) { \
_hs_nmerges++; \
_hs_q = _hs_p; \
_hs_psize = 0; \
for ( _hs_i = 0; _hs_i < _hs_insize; _hs_i++ ) { \
_hs_psize++; \
_hs_q = (UT_hash_handle*)((_hs_q->next) ? \
((void*)((char*)(_hs_q->next) + \
(head)->hh.tbl->hho)) : NULL); \
if (! (_hs_q) ) break; \
} \
_hs_qsize = _hs_insize; \
while ((_hs_psize > 0) || ((_hs_qsize > 0) && _hs_q )) { \
if (_hs_psize == 0) { \
_hs_e = _hs_q; \
_hs_q = (UT_hash_handle*)((_hs_q->next) ? \
((void*)((char*)(_hs_q->next) + \
(head)->hh.tbl->hho)) : NULL); \
_hs_qsize--; \
} else if ( (_hs_qsize == 0) || !(_hs_q) ) { \
_hs_e = _hs_p; \
if (_hs_p){ \
_hs_p = (UT_hash_handle*)((_hs_p->next) ? \
((void*)((char*)(_hs_p->next) + \
(head)->hh.tbl->hho)) : NULL); \
} \
_hs_psize--; \
} else if (( \
cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \
DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \
) <= 0) { \
_hs_e = _hs_p; \
if (_hs_p){ \
_hs_p = (UT_hash_handle*)((_hs_p->next) ? \
((void*)((char*)(_hs_p->next) + \
(head)->hh.tbl->hho)) : NULL); \
} \
_hs_psize--; \
} else { \
_hs_e = _hs_q; \
_hs_q = (UT_hash_handle*)((_hs_q->next) ? \
((void*)((char*)(_hs_q->next) + \
(head)->hh.tbl->hho)) : NULL); \
_hs_qsize--; \
} \
if ( _hs_tail ) { \
_hs_tail->next = ((_hs_e) ? \
ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL); \
} else { \
_hs_list = _hs_e; \
} \
if (_hs_e) { \
_hs_e->prev = ((_hs_tail) ? \
ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL); \
} \
_hs_tail = _hs_e; \
} \
_hs_p = _hs_q; \
} \
if (_hs_tail){ \
_hs_tail->next = NULL; \
} \
if ( _hs_nmerges <= 1 ) { \
_hs_looping=0; \
(head)->hh.tbl->tail = _hs_tail; \
DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \
} \
_hs_insize *= 2; \
} \
HASH_FSCK(hh,head); \
} \
} while (0)
/* This function selects items from one hash into another hash.
* The end result is that the selected items have dual presence
* in both hashes. There is no copy of the items made; rather
* they are added into the new hash through a secondary hash
* hash handle that must be present in the structure. */
#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \
do { \
unsigned _src_bkt, _dst_bkt; \
void *_last_elt=NULL, *_elt; \
UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \
ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \
if (src) { \
for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \
for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \
_src_hh; \
_src_hh = _src_hh->hh_next) { \
_elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \
if (cond(_elt)) { \
_dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \
_dst_hh->key = _src_hh->key; \
_dst_hh->keylen = _src_hh->keylen; \
_dst_hh->hashv = _src_hh->hashv; \
_dst_hh->prev = _last_elt; \
_dst_hh->next = NULL; \
if (_last_elt_hh) { _last_elt_hh->next = _elt; } \
if (!dst) { \
DECLTYPE_ASSIGN(dst,_elt); \
HASH_MAKE_TABLE(hh_dst,dst); \
} else { \
_dst_hh->tbl = (dst)->hh_dst.tbl; \
} \
HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \
HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh); \
(dst)->hh_dst.tbl->num_items++; \
_last_elt = _elt; \
_last_elt_hh = _dst_hh; \
} \
} \
} \
} \
HASH_FSCK(hh_dst,dst); \
} while (0)
#define HASH_CLEAR(hh,head) \
do { \
if (head) { \
uthash_free((head)->hh.tbl->buckets, \
(head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \
HASH_BLOOM_FREE((head)->hh.tbl); \
uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \
(head)=NULL; \
} \
} while(0)
#define HASH_OVERHEAD(hh,head) \
(size_t)((((head)->hh.tbl->num_items * sizeof(UT_hash_handle)) + \
((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket)) + \
(sizeof(UT_hash_table)) + \
(HASH_BLOOM_BYTELEN)))
#ifdef NO_DECLTYPE
#define HASH_ITER(hh,head,el,tmp) \
for((el)=(head), (*(char**)(&(tmp)))=(char*)((head)?(head)->hh.next:NULL); \
el; (el)=(tmp),(*(char**)(&(tmp)))=(char*)((tmp)?(tmp)->hh.next:NULL))
#else
#define HASH_ITER(hh,head,el,tmp) \
for((el)=(head),(tmp)=DECLTYPE(el)((head)?(head)->hh.next:NULL); \
el; (el)=(tmp),(tmp)=DECLTYPE(el)((tmp)?(tmp)->hh.next:NULL))
#endif
/* obtain a count of items in the hash */
#define HASH_COUNT(head) HASH_CNT(hh,head)
#define HASH_CNT(hh,head) ((head)?((head)->hh.tbl->num_items):0)
typedef struct UT_hash_bucket {
struct UT_hash_handle *hh_head;
unsigned count;
/* expand_mult is normally set to 0. In this situation, the max chain length
* threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If
* the bucket's chain exceeds this length, bucket expansion is triggered).
* However, setting expand_mult to a non-zero value delays bucket expansion
* (that would be triggered by additions to this particular bucket)
* until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH.
* (The multiplier is simply expand_mult+1). The whole idea of this
* multiplier is to reduce bucket expansions, since they are expensive, in
* situations where we know that a particular bucket tends to be overused.
* It is better to let its chain length grow to a longer yet-still-bounded
* value, than to do an O(n) bucket expansion too often.
*/
unsigned expand_mult;
} UT_hash_bucket;
/* random signature used only to find hash tables in external analysis */
#define HASH_SIGNATURE 0xa0111fe1
#define HASH_BLOOM_SIGNATURE 0xb12220f2
typedef struct UT_hash_table {
UT_hash_bucket *buckets;
unsigned num_buckets, log2_num_buckets;
unsigned num_items;
struct UT_hash_handle *tail; /* tail hh in app order, for fast append */
ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */
/* in an ideal situation (all buckets used equally), no bucket would have
* more than ceil(#items/#buckets) items. that's the ideal chain length. */
unsigned ideal_chain_maxlen;
/* nonideal_items is the number of items in the hash whose chain position
* exceeds the ideal chain maxlen. these items pay the penalty for an uneven
* hash distribution; reaching them in a chain traversal takes >ideal steps */
unsigned nonideal_items;
/* ineffective expands occur when a bucket doubling was performed, but
* afterward, more than half the items in the hash had nonideal chain
* positions. If this happens on two consecutive expansions we inhibit any
* further expansion, as it's not helping; this happens when the hash
* function isn't a good fit for the key domain. When expansion is inhibited
* the hash will still work, albeit no longer in constant time. */
unsigned ineff_expands, noexpand;
uint32_t signature; /* used only to find hash tables in external analysis */
#ifdef HASH_BLOOM
uint32_t bloom_sig; /* used only to test bloom exists in external analysis */
uint8_t *bloom_bv;
char bloom_nbits;
#endif
} UT_hash_table;
typedef struct UT_hash_handle {
struct UT_hash_table *tbl;
void *prev; /* prev element in app order */
void *next; /* next element in app order */
struct UT_hash_handle *hh_prev; /* previous hh in bucket order */
struct UT_hash_handle *hh_next; /* next hh in bucket order */
void *key; /* ptr to enclosing struct's key */
unsigned keylen; /* enclosing struct's key len */
unsigned hashv; /* result of hash-fcn(key) */
} UT_hash_handle;
#endif /* UTHASH_H */

View File

@ -54,6 +54,7 @@ git submodule update $LINUX_KERNEL_SRC_DIR_NAME
cd $OPENWIFI_DIR/$LINUX_KERNEL_SRC_DIR_NAME
git checkout 2019_R1
git pull origin 2019_R1
# git reset --hard 4fea7c5
cp $OPENWIFI_DIR/driver/xilinx_dma/xilinx_dma.c $OPENWIFI_DIR/$LINUX_KERNEL_SRC_DIR_NAME/drivers/dma/xilinx/xilinx_dma.c
cp $LINUX_KERNEL_CONFIG_FILE ./.config
source $XILINX_DIR/SDK/2018.3/settings64.sh

View File

@ -0,0 +1,101 @@
#
# openwifi side info receive and display program
# Xianjun jiao. putaoshu@msn.com; xianjun.jiao@imec.be
#
import os
import sys
import socket
import numpy as np
import matplotlib.pyplot as plt
def display_iq(iq0_capture, iq1_capture):
fig_iq_capture = plt.figure(0)
fig_iq_capture.clf()
ax_iq0 = fig_iq_capture.add_subplot(211)
# ax_iq0.set_xlabel("sample")
ax_iq0.set_ylabel("I/Q")
ax_iq0.set_title("rx0 I/Q")
plt.plot(iq0_capture.real, 'b')
plt.plot(iq0_capture.imag, 'r')
plt.ylim(-32767, 32767)
ax_iq1 = fig_iq_capture.add_subplot(212)
ax_iq1.set_xlabel("sample")
ax_iq1.set_ylabel("I/Q")
ax_iq1.set_title("rx1 I/Q")
plt.plot(iq1_capture.real, 'b')
plt.plot(iq1_capture.imag, 'r')
plt.ylim(-32767, 32767)
fig_iq_capture.show()
plt.pause(0.0001)
def parse_iq(iq, iq_len):
# print(len(iq), iq_len)
num_dma_symbol_per_trans = 1 + iq_len
num_int16_per_trans = num_dma_symbol_per_trans*4 # 64bit per dma symbol
num_trans = round(len(iq)/num_int16_per_trans)
# print(len(iq), iq.dtype, num_trans)
iq = iq.reshape([num_trans, num_int16_per_trans])
timestamp = iq[:,0] + pow(2,16)*iq[:,1] + pow(2,32)*iq[:,2] + pow(2,48)*iq[:,3]
iq0_capture = iq[:,4::4] + iq[:,5::4]*1j
iq1_capture = iq[:,6::4] + iq[:,7::4]*1j
# print(num_trans, iq_len, iq0_capture.shape, iq1_capture.shape)
iq0_capture = iq0_capture.reshape([num_trans*iq_len,])
iq1_capture = iq1_capture.reshape([num_trans*iq_len,])
return timestamp, iq0_capture, iq1_capture
UDP_IP = "192.168.10.1" #Local IP to listen
UDP_PORT = 4000 #Local port to listen
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # UDP
sock.bind((UDP_IP, UDP_PORT))
# align with side_ch_control.v and all related user space, remote files
MAX_NUM_DMA_SYMBOL = 8192
if len(sys.argv)<2:
print("Assume iq_len = 8187! (Max UDP 65507 bytes; (65507/8)-1 = 8187)")
iq_len = 8187
else:
iq_len = int(sys.argv[1])
print(iq_len)
# print(type(num_eq))
if iq_len>8187:
iq_len = 8187
print('Limit iq_len to 8187! (Max UDP 65507 bytes; (65507/8)-1 = 8187)')
num_dma_symbol_per_trans = 1 + iq_len
num_byte_per_trans = 8*num_dma_symbol_per_trans
if os.path.exists("iq_2ant.txt"):
os.remove("iq_2ant.txt")
iq_fd=open('iq_2ant.txt','a')
while True:
try:
data, addr = sock.recvfrom(MAX_NUM_DMA_SYMBOL*8) # buffer size
# print(addr)
test_residual = len(data)%num_byte_per_trans
# print(len(data)/8, num_dma_symbol_per_trans, test_residual)
if (test_residual != 0):
print("Abnormal length")
iq = np.frombuffer(data, dtype='int16')
np.savetxt(iq_fd, iq)
timestamp, iq0_capture, iq1_capture = parse_iq(iq, iq_len)
print(timestamp, max(iq0_capture.real), max(iq1_capture.real))
display_iq(iq0_capture, iq1_capture)
except KeyboardInterrupt:
print('User quit')
break
print('close()')
side_info_fd.close()
sock.close()

View File

@ -0,0 +1,44 @@
% Xianjun Jiao. xianjun.jiao@imec.be; putaoshu@msn.com
clear all;
close all;
% iq_len = 8187; % default for big fpga
iq_len = 4095; % for small fpga
a = load('iq_2ant.txt');
len_a = floor(length(a)/4)*4;
a = a(1:len_a);
b = reshape(a, [4, length(a)/4])';
num_data_in_each_iq_capture = 1 + iq_len;
num_iq_capture = floor(size(b,1)/num_data_in_each_iq_capture);
iq0_capture = zeros(iq_len, num_iq_capture);
iq1_capture = zeros(iq_len, num_iq_capture);
for i=1:num_iq_capture
sp = (i-1)*num_data_in_each_iq_capture + 1;
ep = i*num_data_in_each_iq_capture;
timestamp(i) = b(sp,1) + (2^16)*b(sp,2) + (2^32)*b(sp,3) + (2^48)*b(sp,4);
iq0_capture(:,i) = b((sp+1):ep,1) + 1i.*b((sp+1):ep,2);
iq1_capture(:,i) = b((sp+1):ep,3) + 1i.*b((sp+1):ep,4);
end
iq0_capture = iq0_capture(:);
iq1_capture = iq1_capture(:);
figure; plot(timestamp); title('time stamp (TSF value)'); ylabel('us'); xlabel('packet'); grid on;
figure;
subplot(2,1,1);
plot(real(iq0_capture)); hold on; plot(imag(iq0_capture),'r'); title('rx0 I (blue) Q (red) sample'); xlabel('sample'); ylabel('I/Q'); grid on;
subplot(2,1,2);
plot(real(iq1_capture)); hold on; plot(imag(iq1_capture),'r'); title('rx1 I (blue) Q (red) sample'); xlabel('sample'); ylabel('I/Q'); grid on;
figure;
a = abs(iq0_capture);
b = abs(iq1_capture);
a(a==0) = max(b);
plot(a); hold on;
plot(b,'r'); title('rx0 and rx1 abs'); xlabel('sample'); ylabel('abs'); grid on;
legend('rx0','rx1');

View File

@ -65,15 +65,20 @@ home_dir=$(pwd)
set -x
cd $OPENWIFI_DIR/user_space/
./prepare_kernel.sh $OPENWIFI_DIR $XILINX_DIR 32 build
sudo true
./prepare_kernel.sh $OPENWIFI_DIR $XILINX_DIR 64 build
sudo true
LINUX_KERNEL_SRC_DIR_NAME32=adi-linux
LINUX_KERNEL_SRC_DIR_NAME64=adi-linux-64
cd $OPENWIFI_DIR/user_space/
# special case, we need our xilinx_dma.c is there when building kernel to avoid version issue
cp $OPENWIFI_DIR/$LINUX_KERNEL_SRC_DIR_NAME32/drivers/dma/xilinx/xilinx_dma.c $OPENWIFI_DIR/$LINUX_KERNEL_SRC_DIR_NAME32/drivers/dma/xilinx/xilinx_dma.c.bak
cp $OPENWIFI_DIR/driver/xilinx_dma/xilinx_dma.c $OPENWIFI_DIR/$LINUX_KERNEL_SRC_DIR_NAME32/drivers/dma/xilinx -rf
./prepare_kernel.sh $OPENWIFI_DIR $XILINX_DIR 32 build
sudo true
cp $OPENWIFI_DIR/$LINUX_KERNEL_SRC_DIR_NAME64/drivers/dma/xilinx/xilinx_dma.c $OPENWIFI_DIR/$LINUX_KERNEL_SRC_DIR_NAME64/drivers/dma/xilinx/xilinx_dma.c.bak
cp $OPENWIFI_DIR/driver/xilinx_dma/xilinx_dma.c $OPENWIFI_DIR/$LINUX_KERNEL_SRC_DIR_NAME64/drivers/dma/xilinx -rf
./prepare_kernel.sh $OPENWIFI_DIR $XILINX_DIR 64 build
sudo true
$OPENWIFI_DIR/user_space/get_fpga.sh $OPENWIFI_DIR
BOARD_NAME_ALL="zc706_fmcs2 zed_fmcs2 zc702_fmcs2 adrv9361z7035 adrv9364z7020 zcu102_fmcs2 zcu102_9371"