| Automated hostapd/wpa_supplicant testing with mac80211_hwsim |
| ------------------------------------------------------------ |
| |
| This directory contains testing infrastructure and test cases to run |
| automated tests of full hostapd and wpa_supplicant functionality. This |
| testing is done with the help of mac80211_hwsim which is Linux kernel |
| driver that simulates IEEE 802.11 radios without requiring any |
| additional hardware. This setup most of the hostapd and wpa_supplicant |
| functionality (and large parts of the Linux cfg80211 and mac80211 |
| functionality for that matter) to be tested. |
| |
| mac80211_hwsim is loaded with five simulated radios to allow different |
| device combinations to be tested. wlantest is used analyze raw packets |
| captured through the hwsim0 monitor interface that capture all frames |
| sent on all channels. wlantest is used to store the frames for |
| analysis. Three wpa_supplicant processes are used to control three |
| virtual radios and one hostapd process is used to dynamically control |
| the other two virtual radios. wpa_supplicant/hostapd test functionality |
| is used to verify that data connection (both unicast and broadcast) |
| works between two netdevs. |
| |
| The python scripts and tools in this directory control test case |
| execution. They interact wpa_supplicant and hostapd through control |
| interfaces to perform the operations. In addition, wlantest_cli is used |
| to verify that operations have been performed correctly and that the |
| network connection works in the expected way. |
| |
| These test cases are run automatically against the hostap.git commits |
| for regression testing and to help in keeping the hostap.git master |
| branch in stable state. Results from these tests are available here: |
| http://buildbot.w1.fi/hwsim/ |
| |
| |
| Building binaries for testing |
| ----------------------------- |
| |
| You will need to build (or use already built) components to be |
| tested. These are available in the hostap.git repository and can be |
| built for example as follows: |
| |
| cd ../../wpa_supplicant |
| cp ../tests/hwsim/example-wpa_supplicant.config .config |
| make clean |
| make |
| cd ../hostapd |
| cp ../tests/hwsim/example-hostapd.config .config |
| make clean |
| make hostapd hlr_auc_gw |
| cd ../wlantest |
| make clean |
| make |
| |
| Alternatively, the build.sh script here can be used to run these steps |
| with conditional creation of .config files only if they do not exist. |
| |
| The test scripts can find the binaries in the locations where they were |
| built. It is also possible to install wlantest_cli somewhere on the path |
| to use pre-built tools. |
| |
| Please note that some of the configuration parameters used to enable |
| more testing coverage may require development packages that may not be |
| installed by default in many distributions. For example, following |
| Debian/Ubuntu packages are likely to be needed: |
| - binutils-dev |
| - libsqlite3-dev |
| - libpcap-dev |
| |
| example-setup.txt provides more complete step-by-step example on how a |
| test setup can be built. |
| |
| |
| wpaspy |
| ------ |
| |
| The python scripts use wpaspy.py to interact with the wpa_supplicant |
| control interface, but the run-tests.py script adds the (relative) |
| path into the environment so it doesn't need to be installed. |
| |
| |
| mac80211_hwsim |
| -------------- |
| |
| mac80211_hwsim kernel module is available from the upstream Linux |
| kernel. Some Linux distributions enable it by default. If that's not the |
| case, you can either enable it in the kernel configuration |
| (CONFIG_MAC80211_HWSIM=m) and rebuild your kernel or use Backports with |
| CPTCFG_MAC80211_HWSIM=m to replace the wireless LAN components in the |
| base kernel. |
| |
| |
| sudo |
| ---- |
| |
| Some parts of the testing process requires root privileges. The test |
| scripts are currently using sudo to achieve this. To be able to run the |
| tests, you'll probably want to enable sudo with a timeout to not expire |
| password entry very quickly. For example, use this in the sudoers file: |
| |
| Defaults env_reset,timestamp_timeout=180 |
| |
| Or on a dedicated test system, you could even disable password prompting |
| with this in sudoers: |
| |
| %sudo ALL=NOPASSWD: ALL |
| |
| |
| Other network interfaces |
| ------------------------ |
| |
| Some of the test scripts are still using hardcoded interface names, so |
| the easiest way of making things work is to avoid using other network |
| devices that may use conflicting interface names. For example, unload |
| any wireless LAN driver before running the tests and make sure that |
| wlan0..4 gets assigned as the interface names for the mac80211_hwsim |
| radios. It may also be possible to rename the interface expectations in |
| run-tests.py to allow other names to be used. |
| |
| Please also note that some commonly enabled tools, like NetworkManager, |
| may end up trying to control new network interfaces automatically. This |
| can result in conflicts with the test scripts and you may need to |
| disable such network services or at least mark the mac80211_hwsim wlan# |
| interfaces as umanaged. As an example, this can be done in |
| /etc/NetworkManager/NetworkManager.conf with following addition: |
| |
| [keyfile] |
| unmanaged-devices=mac:02:00:00:00:00:00;mac:02:00:00:00:01:00;mac:02:00:00:00:02:00;mac:02:00:00:00:03:00;mac:02:00:00:00:04:00 |
| |
| |
| Running tests |
| ------------- |
| |
| Simplest way to run a full set of the test cases is by running |
| run-all.sh in tests/hwsim directory. This will use start.sh to load the |
| mac80211_hwsim module and start wpa_supplicant, hostapd, and various |
| test tools. run-tests.sh is then used to run through all the defined |
| test cases and stop.sh to stop the programs and unload the kernel |
| module. |
| |
| run-all.sh can be used to run the same test cases under different |
| conditions: |
| |
| # run normal test cases |
| ./run-all.sh |
| |
| # run normal test cases under valgrind |
| ./run-all.sh valgrind |
| |
| # run normal test cases with Linux tracing |
| ./run-all.sh trace |
| |
| # run normal test cases with multi channel support (see details below) |
| ./run-all.sh channels=<num of channels> |
| |
| run-all.sh directs debug logs into the logs subdirectory (or $LOGDIR if |
| present in the environment). Log file names include the current UNIX |
| timestamp and a postfix to identify the specific log: |
| - *.log0 = wpa_supplicant debug log for the first radio |
| - *.log1 = wpa_supplicant debug log for the second radio |
| - *.log2 = wpa_supplicant debug log for the third radio |
| - *.hostapd = hostapd debug log |
| - hwsim0 = wlantest debug log |
| - hwsim0.pcapng = capture with all frames exchanged during the tests |
| - *.log = debug prints from the test scripts |
| - trace.dat = Linux tracing record (if enabled) |
| - hlr_auc_gw - hlr_auc_gw (EAP-SIM/AKA/AKA' authentication) log |
| - auth_serv - hostapd as RADIUS authentication server log |
| |
| |
| For manual testing, ./start.sh can be used to initialize interfaces and |
| programs and run-tests.py to execute one or more test |
| cases. run-tests.py output verbosity can be controlled with -d (more |
| verbose debug output) and -q (less verbose output) on the command |
| line. "-f <module name>" (pointing to file test_<module name>.py) can be |
| used to specify that all test cases from a single file are to be |
| run. Test name as the last command line argument can be specified that a |
| single test case is to be run (e.g., "./run-tests.py ap_pmf_required"). |
| |
| Notice that some tests require the driver to support concurrent |
| operation on multi channels in order to run. These tests will be skipped |
| in case the driver does not support multi channels. To enable support |
| for multi channel, the number of supported channel is passed as an |
| argument to run-all.sh or start.sh |
| |
| |
| Adding/modifying test cases |
| --------------------------- |
| |
| All the test cases are defined in the test_*.py files. These are python |
| scripts that can use the local helper classes to interact with the test |
| components. While various python constructs can be used in the scripts, |
| only a minimal level of python knowledge should really be needed to |
| modify and add new test cases. The easiest starting point for this is |
| likely to take a look at some of the example scripts. When working on a |
| new test, run-tests.py with -d and the test case name on the command |
| line is a convenient way of verifying functionality. |
| |
| run-tests.py will automatically import all test cases from the test_*.py |
| files in this directory. All functions starting with the "test_" prefix |
| in these files are assumed to be test cases. Each test case is named by |
| the function name following the "test_" prefix. |
| |
| |
| Results database |
| ---------------- |
| |
| run-tests.py can be requested to write results from the execution of |
| each test case into an sqlite database. The "-S <path to database>" and |
| "-b <build id>" command line arguments can be used to do that. The |
| database must have been prepared before this, e.g., with following: |
| |
| cat | sqlite3 /tmp/example.db <<EOF |
| CREATE TABLE results (test,result,run,time,duration,build,commitid); |
| CREATE INDEX results_idx ON results (test); |
| CREATE INDEX results_idx2 ON results (run); |
| CREATE TABLE tests (test,description); |
| CREATE UNIQUE INDEX tests_idx ON tests (test); |
| CREATE TABLE logs (test,run,type,contents); |
| CREATE INDEX logs_idx ON logs (test); |
| CREATE INDEX logs_idx2 ON logs (run); |
| EOF |