Add more app notes:

1. Packet/event statistics in FPGA
2. Packet/event statistics in driver
3. Some frequent/usual trick for openwifi configuration/fine-tuning/special-setting/etc
This commit is contained in:
Xianjun Jiao 2022-03-28 11:02:00 +02:00
parent 7e3e6749ba
commit 17cfeb0bf7
4 changed files with 423 additions and 0 deletions

View File

@ -17,4 +17,7 @@ Application notes collect many small topics about using openwifi in different sc
- [IEEE 802.11n (Wi-Fi 4)](ieee80211n.md) - [IEEE 802.11n (Wi-Fi 4)](ieee80211n.md)
- [802.11 packet injection and fuzzing](inject_80211.md) - [802.11 packet injection and fuzzing](inject_80211.md)
- [CSI fuzzer](csi_fuzzer.md) - [CSI fuzzer](csi_fuzzer.md)
- [Access counter/statistics in FPGA](perf_counter.md)
- [Access counter/statistics in driver](driver_stat.md)
- [Frequent trick on controlling Gain/Att/Frequency/CCA/LBT/CSMA/CW/etc](frequent_trick.md)
- [owfuzz: a WiFi protocol fuzzing tool using openwifi.](https://github.com/alipay/WiFi-Protocol-Fuzzing-Tool) [[**Vulnerabilities**]](https://github.com/E7mer/Owfuzz) - [owfuzz: a WiFi protocol fuzzing tool using openwifi.](https://github.com/alipay/WiFi-Protocol-Fuzzing-Tool) [[**Vulnerabilities**]](https://github.com/E7mer/Owfuzz)

View File

@ -0,0 +1,136 @@
Comprehensive statistics are offered at the driver level via the [Linux sysfs](https://en.wikipedia.org/wiki/Sysfs#:~:text=sysfs%20is%20a%20pseudo%20file,user%20space%20through%20virtual%20files.).
[[Quick start](#Quick-start)]
[[Sysfs explanation](#Sysfs-explanation)]
[[Statistics variable file meaning](#Statistics-variable-file-meaning)]
All operations should be done on board in openwifi directory, not in host PC.
## Quick start
Enable the driver level statistics (after openwifi up and running)
```
./stat_enable.sh
```
Show the statistics
```
./tx_stat_show.sh
./tx_prio_queue_show.sh
./rx_stat_show.sh
./rx_gain_show.sh
```
Clear the stattistics
```
./tx_stat_show.sh clear
./tx_prio_queue_show.sh clear
./rx_stat_show.sh clear
```
To only show the statistics for the link with a specific peer node
```
./set_rx_target_sender_mac_addr.sh c83caf93
(If the peer node MAC address is 00:80:c8:3c:af:93)
```
To show the statistics of all (not filtered by the peer node MAC address)
```
./set_rx_target_sender_mac_addr.sh 0
```
To show the peer node MAC address for statistics
```
./set_rx_target_sender_mac_addr.sh
```
To see the statistics of ACK packet, run this before above scripts
```
./set_rx_monitor_all.sh
```
Disable the statistics of ACK packet, run this before above scripts
```
./set_rx_monitor_all.sh 0
```
Disable the driver level statistics (after openwifi up and running)
```
./stat_enable.sh 0
```
## Sysfs explanation
For user, as you can check in those scripts above, the sysfs is a set of files that can be operated in the command line for communicating with kernel module. You can find these files on zcu102 board at
```
/sys/devices/platform/fpga-axi@0/fpga-axi@0:sdr
```
On othe boards at
```
/sys/devices/soc0/fpga-axi@0/fpga-axi@0:sdr
```
## Statistics variable file meaning
These statistics names are the same as the file names (in those scripts) and variable names in the sdr.c. Do search these names in sdr.c to understand exact meaning of these statistics.
- tx_stat_show.sh
name|meaning
------------|----------------------
tx_data_pkt_need_ack_num_total | number of tx data packet reported in openwifi_tx_interrupt() (both fail and succeed)
tx_data_pkt_need_ack_num_total_fail| number of tx data packet reported in openwifi_tx_interrupt() (fail -- no ACK received)
tx_data_pkt_need_ack_num_retx | number of tx data packet reported in openwifi_tx_interrupt() at different number of retransmission (both fail and succeed)
tx_data_pkt_need_ack_num_retx_fail | number of tx data packet reported in openwifi_tx_interrupt() at different number of retransmission (fail -- no ACK received)
tx_data_pkt_mcs_realtime | MCS (10*Mbps) of tx data packet reported in openwifi_tx_interrupt() (both fail and succeed)
tx_data_pkt_fail_mcs_realtime | MCS (10*Mbps) of tx data packet reported in openwifi_tx_interrupt() (fail -- no ACK received)
tx_mgmt_pkt_need_ack_num_total | number of tx management packet reported in openwifi_tx_interrupt() (both fail and succeed)
tx_mgmt_pkt_need_ack_num_total_fail| number of tx management packet reported in openwifi_tx_interrupt() (fail -- no ACK received)
tx_mgmt_pkt_need_ack_num_retx | number of tx management packet reported in openwifi_tx_interrupt() at different number of retransmission (both fail and succeed)
tx_mgmt_pkt_need_ack_num_retx_fail | number of tx management packet reported in openwifi_tx_interrupt() at different number of retransmission (fail -- no ACK received)
tx_mgmt_pkt_mcs_realtime | MCS (10*Mbps) of tx management packet reported in openwifi_tx_interrupt() (both fail and succeed)
tx_mgmt_pkt_fail_mcs_realtime | MCS (10*Mbps) of tx management packet reported in openwifi_tx_interrupt() (fail -- no ACK received)
- tx_prio_queue_show.sh
tx_prio_queue_show.sh will show 4 rows. Each row is corresponding one Linux-prio and one FPGA queue. Each row has 12 elements. Elements' name will not be displayed in the command line.
Element name|meaning
------------|----------------------
tx_prio_num | number of tx packet from Linux prio N to openwifi_tx()
tx_prio_interrupt_num | number of tx packet from Linux prio N recorded in openwifi_tx_interrupt()
tx_prio_stop0_fake_num | number of Linux prio N stopped attempt in the 1st place of openwfii_tx(), fake alarm
tx_prio_stop0_real_num | number of Linux prio N stopped attempt in the 1st place of openwfii_tx(), real stop
tx_prio_stop1_num | number of Linux prio N stopped in the 2nd place of openwfii_tx()
tx_prio_wakeup_num | number of Linux prio N waked up in openwifi_tx_interrupt()
tx_queue_num | number of tx packet for FPGA queue N to openwifi_tx()
tx_queue_interrupt_num | number of tx packet for FPGA queue N recorded in openwifi_tx_interrupt()
tx_queue_stop0_fake_num| number of FPGA queue N stopped attempt in the 1st place of openwfii_tx(), fake alarm
tx_queue_stop0_real_num| number of FPGA queue N stopped attempt in the 1st place of openwfii_tx(), real stop
tx_queue_stop1_num | number of FPGA queue N stopped in the 2nd place of openwfii_tx()
tx_queue_wakeup_num | number of FPGA queue N waked up in openwifi_tx_interrupt()
- rx_stat_show.sh
name|meaning
------------|----------------------
rx_data_pkt_num_total | number of rx data packet with both FCS ok and failed
rx_data_pkt_num_fail | number of rx data packet with FCS failed
rx_mgmt_pkt_num_total | number of rx management packet with both FCS ok and failed
rx_mgmt_pkt_num_fail | number of rx management packet with FCS failed
rx_ack_pkt_num_total | number of rx ACK packet with both FCS ok and failed
rx_ack_pkt_num_fail | number of rx ACK packet with FCS failed
rx_data_pkt_mcs_realtime | MCS (10*Mbps) of rx data packet with both FCS ok and failed
rx_data_pkt_fail_mcs_realtime | MCS (10*Mbps) of rx data packet with FCS failed
rx_mgmt_pkt_mcs_realtime | MCS (10*Mbps) of rx management packet with both FCS ok and failed
rx_mgmt_pkt_fail_mcs_realtime | MCS (10*Mbps) of rx management packet with FCS failed
rx_ack_pkt_mcs_realtime | MCS (10*Mbps) of rx ACK packet with both FCS ok and failed
rx_data_ok_agc_gain_value_realtime | agc gain value of rx data packet with FCS ok
rx_data_fail_agc_gain_value_realtime| agc gain value of rx data packet with FCS failed
rx_mgmt_ok_agc_gain_value_realtime | agc gain value of rx management packet with FCS ok
rx_mgmt_fail_agc_gain_value_realtime| agc gain value of rx management packet with FCS failed
rx_ack_ok_agc_gain_value_realtime | agc gain value of rx ACK packet with FCS ok
- rx_gain_show.sh
name|meaning
------------|----------------------
rx_data_ok_agc_gain_value_realtime | agc gain value of rx data packet with FCS ok
rx_data_fail_agc_gain_value_realtime| agc gain value of rx data packet with FCS failed
rx_mgmt_ok_agc_gain_value_realtime | agc gain value of rx management packet with FCS ok
rx_mgmt_fail_agc_gain_value_realtime| agc gain value of rx management packet with FCS failed
rx_ack_ok_agc_gain_value_realtime | agc gain value of rx ACK packet with FCS ok
Note: gain value here is always 14 dB higher than set_rx_gain_auto.sh/set_rx_gain_manual.sh at 5220MHz. 5dB higher at 2.4GHz.

View File

@ -0,0 +1,220 @@
Some usual/frequent control trick over the openwifi FPGA. You need to do these controls on board in the openwifi directory.
[[CCA LBT threshold and disable](#CCA-LBT-threshold-and-disable)]
[[Retransmission and ACK tx control](#Retransmission-and-ACK-tx-control)]
[[NAV DIFS EIFS CW disable and enable](#NAV-DIFS-EIFS-CW-disable-and-enable)]
[[CW max and min config](#CW-max-and-min-config)]
[[Rx gain config](#Rx-gain-config)]
[[Tx power config](#Tx-power-config)]
[[Tx Lo and port config](#Tx-Lo-and-port-config)]
[[Antenna selection](#Antenna-selection)]
[[Restrict the frequency](#Restrict-the-frequency)]
[[Tx rate config](#Tx-rate-config)]
[[Arbiturary Tx IQ sample](#Arbiturary-Tx-IQ-sample)]
## CCA LBT threshold and disable
In normal operation, different threshold is set to FPGA according to the different calibration of different frequency/channel by driver automatically. Show the current LBT threshold in FPGA:
```
./set_lbt_th.sh
```
"reg val: 00000086" means the current threshold is 134 (86 in Hex).
Override a new threshold to FPGA, for example 4dB higher than 134, the new value should be 134 + 4*2 = 142 (1 means 0.5dB, so 4dB higher needs adding 8)
```
./set_lbt_th.sh 142
```
Above will disable the automatic CCA threshold setting from the openwifi driver.
Recover the driver automatic control on the threshold:
```
./set_lbt_th.sh 0
```
Disable the CCA by setting a maximum threshold 2047:
```
./set_lbt_th.sh 2047
```
After above command, the CCA engine will always believe the channel is idle.
## Retransmission and ACK tx control
The best way of override the maximum number of re-transmission for a Tx packet is doing it in the driver openwifi_tx() function.
```
retry_limit_hw_value = ( retry_limit_raw==0?0:((retry_limit_raw - 1)&0xF) );
```
Override retry_limit_hw_value to 0 to disable re-transmission. Override it to 1 means that let FPGA do maximum 1 time re-transmission.
The FPGA also has a register to override the re-transmission and ACK behavior. Check the current register value.
```
./sdrctl dev sdr0 get reg xpu 11
```
When operate this register, make sure you only change the relevant bits and leave other bits untouched, because other bits have other purposes.
To override the maximum number of re-transmission, set bit3 to 1, and set the value (0 ~ 7) to bit2 ~ 0. Example, override the maximum number of re-transmission to 1
```
./sdrctl dev sdr0 set reg xpu 11 9
```
9 in binary form is 01001.
To disable the ACK TX after receive a packet, set bit4 to 1. (Assume we want to preserve the above re-transmission overriding setting)
```
./sdrctl dev sdr0 set reg xpu 11 25
```
25 in binary form is 11001. the 1001 of bit3 to 1 is untouched.
Disabling ACK TX might be useful for monitor mode and packet injection.
## NAV DIFS EIFS CW disable and enable
To check the current NAV/DIFS/EIFS/CW disable status, just run
```
./nav_disable.sh
./difs_disable.sh
./eifs_disable.sh
./cw_disable.sh
```
If NAV is disabled, the openwifi will always assume the NAV (Network Allocation Vector) is already counting down to 0. If DIFS/EIFS is disabled, when the CSMA engine needs to wait for DIFS/EIFS, it won't wait anymore. If CW is disabled, the contention window is fixed to 0, and there won't be any number of slots for random backoff procedure. To disable them, just input 1 as the script argument.
```
./nav_disable.sh 1
./difs_disable.sh 1
./eifs_disable.sh 1
./cw_disable.sh 1
```
To enable them, just input 0 as the script argument.
```
./nav_disable.sh 0
./difs_disable.sh 0
./eifs_disable.sh 0
./cw_disable.sh 0
```
## CW max and min config
When the openwifi NIC bring up (as AP/Client/ad-hoc/etc), Linux will configure the CW (Contention Window) max and min value for FPGA queue 3 ~ 0 via openwifi_conf_tx() in the openwifi driver. You can check the current CW configuration in FPGA (set by Linux).
```
./cw_max_min_cfg.sh
```
It will show sth like
```
FPGA cw max min for q3 to q0: 1023 15; 63 15; 15 7; 7 3
FPGA cw max min for q3 to q0: a4644332
```
The CW max and min for q3 ~ 0 are a4, 64, 43, 32 (in hex). Example explanation for q3: in hex the configuration is a4, which means 10 and 4 in the logarithmic domain, (2^10)-1=1023 and (2^4)-1=15 in the linear domain.
To override the CW max and min for queue 3 ~ 0, for example 2047 31; 63 31; 15 7; 7 3, just map it to a hex string b5654332 for queue 3 ~ 0 and give it as the script argument:
```
./cw_max_min_cfg.sh b5654332
```
It will show sth like
```
FPGA cw max min for q3 to q0: 2047 31; 63 31; 15 7; 7 3
FPGA cw max min for q3 to q0: b5654332
SYSFS cw max min for q3 to q0: 2047 31; 63 31; 15 7; 7 3
SYSFS cw max min for q3 to q0: b5654332
```
To give the control back to Linux
```
./cw_max_min_cfg.sh 0
```
Be careful that above command won't bring the Linux CW max min setting back to FPGA automatically, because Linux normally only call the setting function openwifi_conf_tx() for 1 time when the NIC is started. So either you write down the Linux setting by checking it at the beginning, and set it back via cw_max_min_cfg.sh before giving it argument 0, or re-load the NIC/driver to trigger the Linux setting action for the NIC.
## Rx gain config
In normal operation, you don't need to do Rx gain control manually, because it is controled by the AD9361 AGC function. For optimization/experiment purpose, you might want to use the manual rx gain control, you can run
```
./set_rx_gain_manual.sh 30
```
Above command will turn the automatic gain control mode to manual gain control mode, and set 30dB to the Rx gain module.
Bring it back to the automatic gain control mode
```
./set_rx_gain_auto.sh
```
To find out a good reference about a manual Rx gain setting for the current link/peer, you can set it to automatic mode and then run
```
rx_gain_show.sh
```
for multiple times to check the actual AGC gain vlaue for received packet as explained in this [Access counter/statistics in driver](driver_stat.md). Then you can set the AGC gain value as argument to the **set_rx_gain_manual.sh** with the corret **offset**! For example, if **rx_gain_show.sh** reports a AGC gain value 34 for many successfully received data packets, and you want to use it as a manual gain setting, you need to set
```
./set_rx_gain_manual.sh 20
```
if the current working channel is 5220MHz (34 - 14dB offset = 20). You need to set
```
./set_rx_gain_manual.sh 29
```
if the current working channel is in 2.4GHz (34 - 5dB offset = 29).
## Tx power config
```
./sdrctl dev sdr0 set reg rf 0 20000
```
Above command will set Tx power attenuation to 20dB (20*1000). By default it is 0dB.
If you want an initial attenuation 20dB while loading and bringing up the openwifi NIC, please use the **init_tx_att** argument for the sdr.ko.
```
insmod sdr.ko init_tx_att=20000
```
You can change above driver loading action at the end of **wgd.sh**.
The initial Tx attenuation might be useful when you connect two SDR boards directly by cable. Even though, you shouldn't not connect them during the setup phase (bring up the AP or client), because the initialization/tuning of AD9361 might generate big Tx power and kill the other AD9361's Rx. Only connect two SDR boards by cable after both sides have been setup and the attenuation setting takes effect.
## Tx Lo and port config
In normal operation, the Tx Lo and RF port are controled by FPGA automatically during signal Tx. To check the current Tx Lo and RF port switch status
```
./set_tx_port.sh
./set_tx_lo.sh
```
Give argument **1** to above scripts to turn them **ON**, **0** for **OFF**.
## Antenna selection
By default, the 1st Tx and Rx antennas are used (tx0 and rx0). You can change the tx antenna to tx1 by
```
./sdrctl dev sdr0 set reg drv_tx 4 1
```
Change the tx antenna back to tx0 by
```
./sdrctl dev sdr0 set reg drv_tx 4 0
```
Change the rx antenna to rx1 and rx0 by
```
./sdrctl dev sdr0 set reg drv_rx 4 1
./sdrctl dev sdr0 set reg drv_rx 4 0
```
## Restrict the frequency
Since the AD9361 frequency tuning could generate big unwanted Tx noise, and it could damage the other AD9361 Rx during the test via cable, a restricted frequency can be set to avoid the possible frequency tuning (such as the background scan of Wifi). For example, you want the AD9361 works only in 5220Mhz:
```
./set_restrict_freq.sh 5220
```
Above command will fix the AD9361 in 5220MHz and let driver ignore frequency tuning request other than 5220MHz. The restriction can be removed by:
```
./set_restrict_freq.sh 0
```
## Tx rate config
By default, the Linux rate adaptation algorithm **minstrel_ht** set the packet rate/MCS automatically via openwifi_tx() function.
```
rate_hw_value = ieee80211_get_tx_rate(dev, info)->hw_value;
```
To override the Linux automatic control for non-ht packet
```
./sdrctl dev sdr0 set reg drv_tx 0 N
```
Value N: 0 for Linux auto control; 4 ~ 11 for 6M, 9M, 12M, 18M, 24M, 36M, 48M, 54M.
To override the Linux automatic control for ht packet
```
./sdrctl dev sdr0 set reg drv_tx 1 N
```
Value N: 0 for Linux auto control; 4 ~ 11 for 6.5M, 13M, 19.5M, 26M, 39M, 52M, 58.5M, 65M. By default, the normal GI is used. To use the short GI, you need to add 16 to the target value N.
## Arbiturary Tx IQ sample
To be written.

View File

@ -0,0 +1,64 @@
<!--
Author: Xianjun jiao
SPDX-FileCopyrightText: 2019 UGent
SPDX-License-Identifier: AGPL-3.0-or-later
-->
Counter/statistics (number of TX packet, RX packet, etc.) in FPGA is offered via side channel register write/read.
The 1st step is alway loading the side channel kernel module:
```
insmod side_ch.ko
```
The register write command is:
```
./side_ch_ctl whXdY
X -- register index
Y -- decimal value to be written
./side_ch_ctl whXhY
X -- register index
Y -- hex value to be written (useful for MAC address)
```
Write register 26~31 with arbitrary value to reset the corresponding counter to 0.
The register read command is:
```
./side_ch_ctl rhX
X -- register index
```
## Register definition
The register 26~31 readback value represents the number of event happened. Each register has two event sources that can be selected via bit in register 19.
register idx|source selection reg19|event
------------|----------------------|-----------
26 |reg19[0] == 0 |short_preamble_detected
26 |reg19[0] == 1 |phy_tx_start
27 |reg19[4] == 0 |long_preamble_detected
27 |reg19[4] == 1 |phy_tx_done
28 |reg19[8] == 0 |pkt_header_valid_strobe
28 |reg19[8] == 1 |rssi_above_th
29 |reg19[12] == 0 |pkt_header_valid_strobe&pkt_header_valid
29 |reg19[12] == 1 |gain_change
30 |reg19[16] == 0 |((fcs_in_strobe&addr2_match)&pkt_for_me)&is_data
30 |reg19[16] == 1 |agc_lock
31 |reg19[20] == 0 |(((fcs_in_strobe&fcs_ok)&addr2_match)&pkt_for_me)&is_data
31 |reg19[20] == 1 |tx_pkt_need_ack
Note: fcs_in_strobe means decoding is done (not necessarily CRC is correct); fcs_ok 1 means CRC correct; fcs_ok 0 means CRC not correct.
Note: addr2_match means addr2 matches to the register (addr2_target) value; pkt_for_me means addr1 matches self mac addr; is_data means the packet type is data.
Configuration register:
register idx|meaning |note
------------|----------------------|-----------
7 |addr2 target value |fcs event always needs addr2 match
9 |threshold for event rssi_above_th|check auto_lbt_th in ad9361_rf_set_channel of sdr.c to estimate a proper value
Note: addr2 (source/sender's MAC address) target setting uses only 32bit. For address 6c:fd:b9:4c:b1:c1, you set b94cb1c1
Note: read register 37 of xpu for some addr2 captured by the receiver