[PATCH v2 1/6] plugins: remove dependency on ELL plugins
by James Prestwood
There has been a desire to remove the ELL plugin dependency from
IWD which is the only consumer of the plugin API. This removes
the dependency and prepares the tree for converting the existing
ofono plugin into a regular module.
sim_hardcoded was removed completely. This was originall implemented
before full ofono support purely to test the IWD side of EAP-SIM/AKA.
Since the ofono plugin (module-to-be) is now fully implemented there
really isn't a need for sim_hardcoded.
---
Makefile.am | 8 +-
bootstrap-configure | 1 -
configure.ac | 5 -
plugins/sim_hardcoded.c | 399 ---------------------------------------
src/main.c | 16 --
{plugins => src}/ofono.c | 0
6 files changed, 1 insertion(+), 428 deletions(-)
delete mode 100644 plugins/sim_hardcoded.c
rename {plugins => src}/ofono.c (100%)
-v2:
* Removed sim_hardcoded all together
diff --git a/Makefile.am b/Makefile.am
index 5f16920f..d85d3470 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -185,7 +185,6 @@ if DAEMON
libexec_PROGRAMS += src/iwd
src_iwd_SOURCES = src/main.c linux/nl80211.h src/iwd.h src/missing.h \
- src/plugin.h src/plugin.c \
src/netdev.h src/netdev.c \
src/wiphy.h src/wiphy.c \
src/device.c \
@@ -235,14 +234,9 @@ src_iwd_SOURCES = src/main.c linux/nl80211.h src/iwd.h src/missing.h \
src_iwd_LDADD = $(ell_ldadd) -ldl
src_iwd_DEPENDENCIES = $(ell_dependencies)
-if SIM_HARDCODED
-builtin_modules += sim_hardcoded
-builtin_sources += plugins/sim_hardcoded.c
-endif
-
if OFONO
builtin_modules += ofono
-builtin_sources += plugins/ofono.c
+builtin_sources += src/ofono.c
endif
if DBUS_POLICY
diff --git a/bootstrap-configure b/bootstrap-configure
index 195f2e48..7b907a28 100755
--- a/bootstrap-configure
+++ b/bootstrap-configure
@@ -13,6 +13,5 @@ fi
--enable-hwsim \
--enable-tools \
--enable-ofono \
- --enable-sim-hardcoded \
--disable-dbus-policy \
--disable-systemd-service $*
diff --git a/configure.ac b/configure.ac
index bf7e94df..78db15e9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -291,11 +291,6 @@ AC_ARG_ENABLE([ofono], AC_HELP_STRING([--enable-ofono],
[enable_ofono=${enableval}])
AM_CONDITIONAL(OFONO, test "${enable_ofono}" = "yes")
-AC_ARG_ENABLE([sim_hardcoded], AC_HELP_STRING([--enable-sim-hardcoded],
- [enable hard coded SIM keys]),
- [enable_sim_hardcoded=${enableval}])
-AM_CONDITIONAL(SIM_HARDCODED, test "${enable_sim_hardcoded}" = "yes")
-
AC_CONFIG_FILES(Makefile)
AC_OUTPUT
diff --git a/plugins/sim_hardcoded.c b/plugins/sim_hardcoded.c
deleted file mode 100644
index 463c39fe..00000000
--- a/plugins/sim_hardcoded.c
+++ /dev/null
@@ -1,399 +0,0 @@
-/*
- *
- * Wireless daemon for Linux
- *
- * Copyright (C) 2017-2019 Intel Corporation. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <errno.h>
-
-#include <ell/ell.h>
-#include <ell/plugin.h>
-
-#include "src/simauth.h"
-
-struct hardcoded_sim {
- char *identity;
- uint8_t sim_supported;
- uint8_t kc[NUM_RANDS_MAX][EAP_SIM_KC_LEN];
- uint8_t sres[NUM_RANDS_MAX][EAP_SIM_SRES_LEN];
- uint8_t aka_supported;
- uint8_t ki[EAP_AKA_KI_LEN];
- uint8_t opc[EAP_AKA_OPC_LEN];
- uint8_t amf[EAP_AKA_AMF_LEN];
- uint8_t sqn[EAP_AKA_SQN_LEN];
- struct iwd_sim_auth *auth;
-};
-
-static struct hardcoded_sim *sim;
-
-/*
- * Helper to XOR an array
- * to - result of XOR array
- * a - array 1
- * b - array 2
- * len - size of array
- */
-#define XOR(to, a, b, len) \
- for (i = 0; i < len; i++) { \
- to[i] = a[i] ^ b[i]; \
- }
-
-static int get_milenage(const uint8_t *opc, const uint8_t *k,
- const uint8_t *rand, const uint8_t *sqn, const uint8_t *amf,
- const uint8_t *autn_in, uint8_t *autn, uint8_t *ck, uint8_t *ik,
- uint8_t *res, uint8_t *auts)
-{
- /* algorithm variables: TEMP, IN1, OUT1, OUT2, OUT5 (OUT3/4 == IK/CK) */
- uint8_t temp[16];
- uint8_t in1[16];
- uint8_t out1[16], out2[16], out5[16];
- /* other variables */
- struct l_cipher *aes;
- int i;
- uint8_t tmp1[16];
- uint8_t tmp2[16];
- uint8_t sqn_autn[6];
-
- aes = l_cipher_new(L_CIPHER_AES, k, 16);
-
- /* temp = TEMP = E[RAND ^ OPc]k */
- XOR(tmp1, rand, opc, 16);
- l_cipher_encrypt(aes, tmp1, temp, 16);
-
- /* IN1[0-47] = SQN[0-47] */
- memcpy(in1, sqn, 6);
- /* IN1[48-63] = AMF[0-15] */
- memcpy(in1 + 6, amf, 2);
- /* IN1[64-111] = SQN[0-47] */
- memcpy(in1 + 8, sqn, 6);
- /* IN1[112-127] = AMF[0-15] */
- memcpy(in1 + 14, amf, 2);
-
- /*
- * f1 and f1* output OUT1
- */
- /*
- * tmp1 = rot(IN1 ^ OPc)r1
- * r1 = 64 bits = 8 bytes
- */
- for (i = 0; i < 16; i++)
- tmp1[(i + 8) % 16] = in1[i] ^ opc[i];
-
- /* tmp2 = TEMP ^ tmp1 */
- XOR(tmp2, temp, tmp1, 16);
- /* tmp2 = E[tmp2]k */
- l_cipher_encrypt(aes, tmp2, tmp1, 16);
- /* out1 = OUT1 = tmp1 ^ opc */
- XOR(out1, tmp1, opc, 16);
-
- /*
- * f2 outputs OUT2 (RES | AK)
- *
- * r2 = 0 == no rotation
- */
- /* tmp1 = rot(TEMP ^ OPc)r2 */
- XOR(tmp1, temp, opc, 16);
- /* tmp1 ^ c2. c2 at bit 127 == 1 */
- tmp1[15] ^= 1;
- l_cipher_encrypt(aes, tmp1, out2, 16);
-
- /* get RES from OUT2 */
- XOR(out2, out2, opc, 16);
- memcpy(res, out2 + 8, 8);
-
- /* check input autn (AUTN ^ AK = SQN)*/
- XOR(sqn_autn, autn_in, out2, 6);
-
- /* if SQN was not correct, generate AUTS */
- if (memcmp(sqn_autn, sqn, 6)) {
- /*
- * f5* outputs AK' (OUT5)
- */
- for (i = 0; i < 16; i++)
- tmp1[(i + 4) % 16] = temp[i] ^ opc[i];
-
- /* tmp1 ^ c5. c5 at bit 124 == 1 */
- tmp1[15] ^= 1 << 3;
- l_cipher_encrypt(aes, tmp1, out5, 16);
- /* out5 ^ opc */
- XOR(out5, out5, opc, 16);
-
- XOR(auts, sqn, out5, 6);
-
- /* run f1 with zero'd AMF to finish AUTS */
- in1[6] = 0x00;
- in1[7] = 0x00;
- in1[14] = 0x00;
- in1[15] = 0x00;
-
- for (i = 0; i < 16; i++)
- tmp1[(i + 8) % 16] = in1[i] ^ opc[i];
-
- /* tmp2 = TEMP ^ tmp1 */
- XOR(tmp2, temp, tmp1, 16);
- /* tmp2 = E[tmp2]k */
- l_cipher_encrypt(aes, tmp2, tmp1, 16);
- /* out1 = OUT1 = tmp1 ^ opc */
- XOR(out1, tmp1, opc, 16);
-
- memcpy(auts + 6, in1 + 8, 8);
-
- return -1;
- }
-
- /* AUTN = (SQN ^ AK) | AMF | MAC_A */
- XOR(autn, sqn, out2, 6);
- memcpy(autn + 6, amf, 2);
- memcpy(autn + 8, out1, 8);
-
- if (memcmp(autn, autn_in, 16))
- return -2;
-
- /*
- * f3 outputs CK (OUT3)
- *
- * tmp1 = rot(TEMP ^ OPc)r3
- *
- * r3 = 32 bits = 4 bytes
- */
- for (i = 0; i < 16; i++)
- tmp1[(i + 12) % 16] = temp[i] ^ opc[i];
-
- /* tmp1 ^ c3. c3 at bit 126 == 1 */
- tmp1[15] ^= 1 << 1;
- l_cipher_encrypt(aes, tmp1, ck, 16);
- /* ck ^ opc */
- XOR(ck, ck, opc, 16);
-
- /*
- * f4 outputs IK (OUT4)
- *
- * tmp1 = rot(TEMP ^ OPc)r4
- *
- * r4 = 64 bits = 8 bytes
- */
- for (i = 0; i < 16; i++)
- tmp1[(i + 8) % 16] = temp[i] ^ opc[i];
-
- /* tmp1 ^ c4. c4 at bit 125 == 1 */
- tmp1[15] ^= 1 << 2;
- l_cipher_encrypt(aes, tmp1, ik, 16);
- /* ik ^ opc */
- XOR(ik, ik, opc, 16);
-
- l_cipher_free(aes);
-
- return 0;
-}
-
-static int check_milenage(struct iwd_sim_auth *auth, const uint8_t *rand,
- const uint8_t *autn, sim_auth_check_milenage_cb_t cb,
- void *data)
-{
- uint8_t res[8];
- uint8_t ck[16];
- uint8_t ik[16];
- uint8_t _autn[16];
- uint8_t auts[14];
- int ret;
-
- if (!sim->aka_supported)
- return -ENOTSUP;
-
- ret = get_milenage(sim->opc, sim->ki, rand, sim->sqn, sim->amf,
- autn, _autn, ck, ik, res, auts);
-
- /* ret == 0, success; ret == -1, sync failure; ret == -2, failure */
- if (ret == 0)
- cb(res, ck, ik, NULL, data);
- else if (ret == -1)
- cb(NULL, NULL, NULL, auts, data);
- else
- cb(NULL, NULL, NULL, NULL, data);
-
- return 0;
-
-}
-
-static int run_gsm(struct iwd_sim_auth *auth, const uint8_t *rands,
- int num_rands, sim_auth_run_gsm_cb_t cb, void *data)
-{
- if (!sim->sim_supported)
- return -ENOTSUP;
-
- cb((const uint8_t *)sim->sres, (const uint8_t *)sim->kc, data);
-
- return 0;
-}
-
-static struct iwd_sim_auth_driver hardcoded_sim_driver = {
- .name = "Hardcoded SIM driver",
- .check_milenage = check_milenage,
- .run_gsm = run_gsm
-};
-
-static int sim_hardcoded_init(void)
-{
- void *kc;
- void *sres;
- void *ki;
- void *opc;
- void *amf;
- void *sqn;
- const char *str;
- size_t len;
- struct l_settings *key_settings;
- const char *config_path = getenv("IWD_SIM_KEYS");
-
- if (!config_path) {
- l_debug("IWD_SIM_KEYS not set in env");
- return -ENOENT;
- }
-
- key_settings = l_settings_new();
-
- if (!l_settings_load_from_file(key_settings, config_path)) {
- l_error("No %s file found", config_path);
- l_settings_free(key_settings);
- return -ENOENT;
- }
-
- sim = l_new(struct hardcoded_sim, 1);
-
- if (l_settings_has_group(key_settings, "SIM")) {
- str = l_settings_get_value(key_settings, "SIM", "Kc");
- if (!str) {
- l_debug("Kc value must be present for SIM");
- goto try_aka;
- }
-
- kc = l_util_from_hexstring(str, &len);
- memcpy(sim->kc, kc, len);
- l_free(kc);
-
- str = l_settings_get_value(key_settings, "SIM", "SRES");
- if (!str) {
- l_debug("SRES value must be present for SIM");
- goto try_aka;
- }
-
- sres = l_util_from_hexstring(str, &len);
- memcpy(sim->sres, sres, NUM_RANDS_MAX * EAP_SIM_SRES_LEN);
- l_free(sres);
-
- str = l_settings_get_value(key_settings, "SIM", "Identity");
- if (!str) {
- l_debug("Identity setting must be present for SIM");
- goto try_aka;
- }
-
- sim->identity = l_strdup(str);
-
- sim->sim_supported = 1;
- }
-
-try_aka:
- if (l_settings_has_group(key_settings, "AKA")) {
- str = l_settings_get_value(key_settings, "AKA", "KI");
- if (!str) {
- l_debug("KI value must be present for AKA");
- goto end;
- }
-
- ki = l_util_from_hexstring(str, &len);
- memcpy(sim->ki, ki, EAP_AKA_KI_LEN);
- l_free(ki);
-
- str = l_settings_get_value(key_settings, "AKA", "OPC");
- if (!str) {
- l_debug("OPC value must be preset for AKA");
- goto end;
- }
-
- opc = l_util_from_hexstring(str, &len);
- memcpy(sim->opc, opc, EAP_AKA_OPC_LEN);
- l_free(opc);
-
- str = l_settings_get_value(key_settings, "AKA", "AMF");
- if (!str) {
- l_debug("AMF value must be present for AKA");
- goto end;
- }
-
- amf = l_util_from_hexstring(str, &len);
- memcpy(sim->amf, amf, EAP_AKA_AMF_LEN);
- l_free(amf);
-
- str = l_settings_get_value(key_settings, "AKA", "SQN");
- if (!str) {
- l_debug("SQN value must be present for AKA");
- goto end;
- }
-
- sqn = l_util_from_hexstring(str, &len);
- memcpy(sim->sqn, sqn, EAP_AKA_SQN_LEN);
- l_free(sqn);
-
- str = l_settings_get_value(key_settings, "AKA", "Identity");
- if (!str) {
- l_debug("Identity setting must be present for AKA");
- goto end;
- }
-
- sim->identity = l_strdup(str);
-
- sim->aka_supported = 1;
- }
-end:
- l_settings_free(key_settings);
-
- if (!sim->sim_supported && !sim->aka_supported) {
- l_debug("error parsing config file, values missing");
-
- return -EINVAL;
- }
-
- sim->auth = iwd_sim_auth_create(&hardcoded_sim_driver);
-
- iwd_sim_auth_set_nai(sim->auth, sim->identity);
- iwd_sim_auth_set_capabilities(sim->auth, sim->sim_supported,
- sim->aka_supported);
-
- iwd_sim_auth_register(sim->auth);
-
- return 0;
-}
-
-static void sim_hardcoded_exit(void)
-{
- iwd_sim_auth_remove(sim->auth);
-
- if (sim)
- l_free(sim->identity);
-
- l_free(sim);
-}
-
-L_PLUGIN_DEFINE(__iwd_builtin_sim_hardcoded, sim_hardcoded,
- "Hardcoded SIM driver", "1.0", L_PLUGIN_PRIORITY_DEFAULT,
- sim_hardcoded_init, sim_hardcoded_exit)
diff --git a/src/main.c b/src/main.c
index 3216f508..2ee6188c 100644
--- a/src/main.c
+++ b/src/main.c
@@ -40,7 +40,6 @@
#include "src/eap.h"
#include "src/eapol.h"
#include "src/rfkill.h"
-#include "src/plugin.h"
#include "src/storage.h"
#include "src/anqp.h"
@@ -54,8 +53,6 @@ static const char *interfaces;
static const char *nointerfaces;
static const char *phys;
static const char *nophys;
-static const char *plugins;
-static const char *noplugins;
static const char *debugopt;
static bool terminating;
static bool nl80211_complete;
@@ -140,8 +137,6 @@ static void usage(void)
"\t-I, --nointerfaces Interfaces to ignore\n"
"\t-p, --phys Phys to manage\n"
"\t-P, --nophys Phys to ignore\n"
- "\t-l, --plugin Plugins to include\n"
- "\t-L, --noplugin Plugins to exclude\n"
"\t-d, --debug Enable debug output\n"
"\t-v, --version Show version\n"
"\t-h, --help Show help options\n");
@@ -154,8 +149,6 @@ static const struct option main_options[] = {
{ "nointerfaces", required_argument, NULL, 'I' },
{ "phys", required_argument, NULL, 'p' },
{ "nophys", required_argument, NULL, 'P' },
- { "plugin", required_argument, NULL, 'l' },
- { "noplugin", required_argument, NULL, 'L' },
{ "debug", optional_argument, NULL, 'd' },
{ "help", no_argument, NULL, 'h' },
{ }
@@ -179,8 +172,6 @@ static void nl80211_appeared(const struct l_genl_family_info *info,
l_main_quit();
return;
}
-
- plugin_init(plugins, noplugins);
}
static void request_name_callback(struct l_dbus *dbus, bool success,
@@ -393,12 +384,6 @@ int main(int argc, char *argv[])
case 'P':
nophys = optarg;
break;
- case 'l':
- plugins = optarg;
- break;
- case 'L':
- noplugins = optarg;
- break;
case 'd':
if (optarg)
debugopt = optarg;
@@ -504,7 +489,6 @@ int main(int argc, char *argv[])
exit_status = l_main_run_with_signal(signal_handler, NULL);
- plugin_exit();
iwd_modules_exit();
dbus_exit();
l_dbus_destroy(dbus);
diff --git a/plugins/ofono.c b/src/ofono.c
similarity index 100%
rename from plugins/ofono.c
rename to src/ofono.c
--
2.26.2
1 year, 8 months
[PATCH 1/7] plugins: remove dependency on ELL plugins
by James Prestwood
There has been a desire to remove the ELL plugin dependency from
IWD which is the only consumer of the plugin API. This removes
the dependency and prepares the tree for converting the existing
ofono and sim_hardcoded plugins into regular modules.
---
Makefile.am | 5 ++---
src/main.c | 16 ----------------
{plugins => src}/ofono.c | 0
{plugins => src}/sim_hardcoded.c | 0
4 files changed, 2 insertions(+), 19 deletions(-)
rename {plugins => src}/ofono.c (100%)
rename {plugins => src}/sim_hardcoded.c (100%)
diff --git a/Makefile.am b/Makefile.am
index 5f16920f..e327874b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -185,7 +185,6 @@ if DAEMON
libexec_PROGRAMS += src/iwd
src_iwd_SOURCES = src/main.c linux/nl80211.h src/iwd.h src/missing.h \
- src/plugin.h src/plugin.c \
src/netdev.h src/netdev.c \
src/wiphy.h src/wiphy.c \
src/device.c \
@@ -237,12 +236,12 @@ src_iwd_DEPENDENCIES = $(ell_dependencies)
if SIM_HARDCODED
builtin_modules += sim_hardcoded
-builtin_sources += plugins/sim_hardcoded.c
+builtin_sources += src/sim_hardcoded.c
endif
if OFONO
builtin_modules += ofono
-builtin_sources += plugins/ofono.c
+builtin_sources += src/ofono.c
endif
if DBUS_POLICY
diff --git a/src/main.c b/src/main.c
index 3216f508..2ee6188c 100644
--- a/src/main.c
+++ b/src/main.c
@@ -40,7 +40,6 @@
#include "src/eap.h"
#include "src/eapol.h"
#include "src/rfkill.h"
-#include "src/plugin.h"
#include "src/storage.h"
#include "src/anqp.h"
@@ -54,8 +53,6 @@ static const char *interfaces;
static const char *nointerfaces;
static const char *phys;
static const char *nophys;
-static const char *plugins;
-static const char *noplugins;
static const char *debugopt;
static bool terminating;
static bool nl80211_complete;
@@ -140,8 +137,6 @@ static void usage(void)
"\t-I, --nointerfaces Interfaces to ignore\n"
"\t-p, --phys Phys to manage\n"
"\t-P, --nophys Phys to ignore\n"
- "\t-l, --plugin Plugins to include\n"
- "\t-L, --noplugin Plugins to exclude\n"
"\t-d, --debug Enable debug output\n"
"\t-v, --version Show version\n"
"\t-h, --help Show help options\n");
@@ -154,8 +149,6 @@ static const struct option main_options[] = {
{ "nointerfaces", required_argument, NULL, 'I' },
{ "phys", required_argument, NULL, 'p' },
{ "nophys", required_argument, NULL, 'P' },
- { "plugin", required_argument, NULL, 'l' },
- { "noplugin", required_argument, NULL, 'L' },
{ "debug", optional_argument, NULL, 'd' },
{ "help", no_argument, NULL, 'h' },
{ }
@@ -179,8 +172,6 @@ static void nl80211_appeared(const struct l_genl_family_info *info,
l_main_quit();
return;
}
-
- plugin_init(plugins, noplugins);
}
static void request_name_callback(struct l_dbus *dbus, bool success,
@@ -393,12 +384,6 @@ int main(int argc, char *argv[])
case 'P':
nophys = optarg;
break;
- case 'l':
- plugins = optarg;
- break;
- case 'L':
- noplugins = optarg;
- break;
case 'd':
if (optarg)
debugopt = optarg;
@@ -504,7 +489,6 @@ int main(int argc, char *argv[])
exit_status = l_main_run_with_signal(signal_handler, NULL);
- plugin_exit();
iwd_modules_exit();
dbus_exit();
l_dbus_destroy(dbus);
diff --git a/plugins/ofono.c b/src/ofono.c
similarity index 100%
rename from plugins/ofono.c
rename to src/ofono.c
diff --git a/plugins/sim_hardcoded.c b/src/sim_hardcoded.c
similarity index 100%
rename from plugins/sim_hardcoded.c
rename to src/sim_hardcoded.c
--
2.26.2
1 year, 8 months
[PATCH v2] auto-t: add netconfig autotest
by James Prestwood
Tests that DHCP using IWD's internal netconfig functions properly.
The actual IP address assignment is not verified, but since IWD does
not signal the connection as successful unless DHCP succeeds we
can assume it was successful by checking that the device is connected.
The process of actually starting dhcpd and configuring the interfaces
is quite simple so it was left in the autotest itself. If (or when)
more tests require IP capabilities (p2p, FILS, etc) this could be
moved into test-runner itself and be made common. The reason I did not
put it in there now is a) because this is the only test and b) more
complex DHCP cases are likely to develop and may require more than this
simplistic setup (like multiple APs/interfaces)
---
autotests/testNetconfig/connection_test.py | 70 ++++++++++++++++++++++
autotests/testNetconfig/dhcpd.conf | 16 +++++
autotests/testNetconfig/hw.conf | 6 ++
autotests/testNetconfig/main.conf | 2 +
autotests/testNetconfig/ssidTKIP.conf | 7 +++
5 files changed, 101 insertions(+)
create mode 100644 autotests/testNetconfig/connection_test.py
create mode 100644 autotests/testNetconfig/dhcpd.conf
create mode 100644 autotests/testNetconfig/hw.conf
create mode 100644 autotests/testNetconfig/main.conf
create mode 100644 autotests/testNetconfig/ssidTKIP.conf
-v2:
* Removed dhcpd.leases. Its an empty file anyways which caused issues with applying
the patches. Instead we can just touch /tmp/dhcpd.leases before starting dhcpd.
diff --git a/autotests/testNetconfig/connection_test.py b/autotests/testNetconfig/connection_test.py
new file mode 100644
index 00000000..3a590aeb
--- /dev/null
+++ b/autotests/testNetconfig/connection_test.py
@@ -0,0 +1,70 @@
+#!/usr/bin/python3
+
+import unittest
+import sys
+
+sys.path.append('../util')
+import iwd
+from iwd import IWD
+from iwd import PSKAgent
+from iwd import NetworkType
+import testutil
+from config import ctx
+
+class Test(unittest.TestCase):
+
+ def test_connection_success(self):
+ wd = IWD()
+
+ psk_agent = PSKAgent("secret123")
+ wd.register_psk_agent(psk_agent)
+
+ devices = wd.list_devices(1)
+ device = devices[0]
+
+ condition = 'not obj.scanning'
+ wd.wait_for_object_condition(device, condition)
+
+ device.scan()
+
+ condition = 'not obj.scanning'
+ wd.wait_for_object_condition(device, condition)
+
+ ordered_network = device.get_ordered_network('ssidTKIP')
+
+ self.assertEqual(ordered_network.type, NetworkType.psk)
+
+ condition = 'not obj.connected'
+ wd.wait_for_object_condition(ordered_network.network_object, condition)
+
+ ordered_network.network_object.connect()
+
+ condition = 'obj.state == DeviceState.connected'
+ wd.wait_for_object_condition(device, condition)
+
+ testutil.test_iface_operstate()
+ testutil.test_ifaces_connected()
+
+ device.disconnect()
+
+ condition = 'not obj.connected'
+ wd.wait_for_object_condition(ordered_network.network_object, condition)
+
+ wd.unregister_psk_agent(psk_agent)
+
+ @classmethod
+ def setUpClass(cls):
+ # TODO: This could be moved into test-runner itself if other tests ever
+ # require this functionality (p2p, FILS, etc.). Since its simple
+ # enough it can stay here for now.
+ ctx.start_process(['ifconfig', 'wln0', '192.168.1.1', 'netmask', '255.255.255.0'],
+ wait=True)
+ ctx.start_process(['touch', '/tmp/dhcpd.leases'], wait=True)
+ ctx.start_process(['dhcpd', '-cf', '/tmp/dhcpd.conf', '-lf', '/tmp/dhcpd.leases'])
+
+ @classmethod
+ def tearDownClass(cls):
+ IWD.clear_storage()
+
+if __name__ == '__main__':
+ unittest.main(exit=True)
diff --git a/autotests/testNetconfig/dhcpd.conf b/autotests/testNetconfig/dhcpd.conf
new file mode 100644
index 00000000..77b4da1c
--- /dev/null
+++ b/autotests/testNetconfig/dhcpd.conf
@@ -0,0 +1,16 @@
+default-lease-time 600; # 10 minutes
+max-lease-time 7200; # 2 hours
+
+option broadcast-address 192.168.1.255;
+option routers 192.168.1.254;
+option subnet-mask 255.255.255.0;
+
+subnet 192.168.1.0 netmask 255.255.255.0
+ {
+ option routers 192.168.1.1;
+ option subnet-mask 255.255.255.0;
+ option domain-name-servers 192.168.1.1;
+ interface wln0;
+ range 192.168.1.10 192.168.1.20;
+ range 192.168.1.100 192.168.1.200;
+ }
diff --git a/autotests/testNetconfig/hw.conf b/autotests/testNetconfig/hw.conf
new file mode 100644
index 00000000..75c5ac6e
--- /dev/null
+++ b/autotests/testNetconfig/hw.conf
@@ -0,0 +1,6 @@
+[SETUP]
+num_radios=2
+max_test_exec_interval_sec=40
+
+[HOSTAPD]
+rad0=ssidTKIP.conf
diff --git a/autotests/testNetconfig/main.conf b/autotests/testNetconfig/main.conf
new file mode 100644
index 00000000..982e5445
--- /dev/null
+++ b/autotests/testNetconfig/main.conf
@@ -0,0 +1,2 @@
+[General]
+EnableNetworkConfiguration=true
diff --git a/autotests/testNetconfig/ssidTKIP.conf b/autotests/testNetconfig/ssidTKIP.conf
new file mode 100644
index 00000000..11ef15f0
--- /dev/null
+++ b/autotests/testNetconfig/ssidTKIP.conf
@@ -0,0 +1,7 @@
+hw_mode=g
+channel=1
+ssid=ssidTKIP
+
+wpa=1
+wpa_pairwise=TKIP
+wpa_passphrase=secret123
--
2.26.2
1 year, 8 months
[PATCH] auto-t: add netconfig autotest
by James Prestwood
Tests that DHCP using IWD's internal netconfig functions properly.
The actual IP address assignment is not verified, but since IWD does
not signal the connection as successful unless DHCP succeeds we
can assume it was successful by checking that the device is connected.
The process of actually starting dhcpd and configuring the interfaces
is quite simple so it was left in the autotest itself. If (or when)
more tests require IP capabilities (p2p, FILS, etc) this could be
moved into test-runner itself and be made common. The reason I did not
put it in there now is a) because this is the only test and b) more
complex DHCP cases are likely to develop and may require more than this
simplistic setup (like multiple APs/interfaces)
---
autotests/testNetconfig/connection_test.py | 69 ++++++++++++++++++++++
autotests/testNetconfig/dhcpd.conf | 16 +++++
autotests/testNetconfig/dhcpd.leases | 1 +
autotests/testNetconfig/hw.conf | 6 ++
autotests/testNetconfig/main.conf | 2 +
autotests/testNetconfig/ssidTKIP.conf | 7 +++
6 files changed, 101 insertions(+)
create mode 100644 autotests/testNetconfig/connection_test.py
create mode 100644 autotests/testNetconfig/dhcpd.conf
create mode 100644 autotests/testNetconfig/dhcpd.leases
create mode 100644 autotests/testNetconfig/hw.conf
create mode 100644 autotests/testNetconfig/main.conf
create mode 100644 autotests/testNetconfig/ssidTKIP.conf
diff --git a/autotests/testNetconfig/connection_test.py b/autotests/testNetconfig/connection_test.py
new file mode 100644
index 00000000..c5200c2b
--- /dev/null
+++ b/autotests/testNetconfig/connection_test.py
@@ -0,0 +1,69 @@
+#!/usr/bin/python3
+
+import unittest
+import sys
+
+sys.path.append('../util')
+import iwd
+from iwd import IWD
+from iwd import PSKAgent
+from iwd import NetworkType
+import testutil
+from config import ctx
+
+class Test(unittest.TestCase):
+
+ def test_connection_success(self):
+ wd = IWD()
+
+ psk_agent = PSKAgent("secret123")
+ wd.register_psk_agent(psk_agent)
+
+ devices = wd.list_devices(1)
+ device = devices[0]
+
+ condition = 'not obj.scanning'
+ wd.wait_for_object_condition(device, condition)
+
+ device.scan()
+
+ condition = 'not obj.scanning'
+ wd.wait_for_object_condition(device, condition)
+
+ ordered_network = device.get_ordered_network('ssidTKIP')
+
+ self.assertEqual(ordered_network.type, NetworkType.psk)
+
+ condition = 'not obj.connected'
+ wd.wait_for_object_condition(ordered_network.network_object, condition)
+
+ ordered_network.network_object.connect()
+
+ condition = 'obj.state == DeviceState.connected'
+ wd.wait_for_object_condition(device, condition)
+
+ testutil.test_iface_operstate()
+ testutil.test_ifaces_connected()
+
+ device.disconnect()
+
+ condition = 'not obj.connected'
+ wd.wait_for_object_condition(ordered_network.network_object, condition)
+
+ wd.unregister_psk_agent(psk_agent)
+
+ @classmethod
+ def setUpClass(cls):
+ # TODO: This could be moved into test-runner itself if other tests ever
+ # require this functionality (p2p, FILS, etc.). Since its simple
+ # enough it can stay here for now.
+ ctx.start_process(['ifconfig', 'wln0', '192.168.1.1', 'netmask', '255.255.255.0'],
+ wait=True)
+ ctx.start_process(['dhcpd', '-cf', '/tmp/dhcpd.conf', '-lf', '/tmp/dhcpd.leases'])
+
+ @classmethod
+ def tearDownClass(cls):
+ IWD.clear_storage()
+
+if __name__ == '__main__':
+ unittest.main(exit=True)
diff --git a/autotests/testNetconfig/dhcpd.conf b/autotests/testNetconfig/dhcpd.conf
new file mode 100644
index 00000000..77b4da1c
--- /dev/null
+++ b/autotests/testNetconfig/dhcpd.conf
@@ -0,0 +1,16 @@
+default-lease-time 600; # 10 minutes
+max-lease-time 7200; # 2 hours
+
+option broadcast-address 192.168.1.255;
+option routers 192.168.1.254;
+option subnet-mask 255.255.255.0;
+
+subnet 192.168.1.0 netmask 255.255.255.0
+ {
+ option routers 192.168.1.1;
+ option subnet-mask 255.255.255.0;
+ option domain-name-servers 192.168.1.1;
+ interface wln0;
+ range 192.168.1.10 192.168.1.20;
+ range 192.168.1.100 192.168.1.200;
+ }
diff --git a/autotests/testNetconfig/dhcpd.leases b/autotests/testNetconfig/dhcpd.leases
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/autotests/testNetconfig/dhcpd.leases
@@ -0,0 +1 @@
+
diff --git a/autotests/testNetconfig/hw.conf b/autotests/testNetconfig/hw.conf
new file mode 100644
index 00000000..75c5ac6e
--- /dev/null
+++ b/autotests/testNetconfig/hw.conf
@@ -0,0 +1,6 @@
+[SETUP]
+num_radios=2
+max_test_exec_interval_sec=40
+
+[HOSTAPD]
+rad0=ssidTKIP.conf
diff --git a/autotests/testNetconfig/main.conf b/autotests/testNetconfig/main.conf
new file mode 100644
index 00000000..982e5445
--- /dev/null
+++ b/autotests/testNetconfig/main.conf
@@ -0,0 +1,2 @@
+[General]
+EnableNetworkConfiguration=true
diff --git a/autotests/testNetconfig/ssidTKIP.conf b/autotests/testNetconfig/ssidTKIP.conf
new file mode 100644
index 00000000..11ef15f0
--- /dev/null
+++ b/autotests/testNetconfig/ssidTKIP.conf
@@ -0,0 +1,7 @@
+hw_mode=g
+channel=1
+ssid=ssidTKIP
+
+wpa=1
+wpa_pairwise=TKIP
+wpa_passphrase=secret123
--
2.26.2
1 year, 8 months
[PATCH] test-runner: use **kwargs for start_process
by James Prestwood
This is just a more concise/pythonic way of doing function arguments.
Since Process/start_process have basically the same argument names
we can simplify and use **kwargs which will pass the named arguments
directly to Process(). This also allows us to add arguments to Process
without touching start_process if we need.
---
tools/test-runner | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/tools/test-runner b/tools/test-runner
index a71b9ef6..d1e1d42c 100755
--- a/tools/test-runner
+++ b/tools/test-runner
@@ -465,10 +465,10 @@ class TestContext:
self.results = {}
self.mainloop = GLib.MainLoop()
- def start_process(self, args, wait=False, multi_test=False, env=None, check=False):
- p = Process(args, wait, multi_test, env, ctx=self, check=check)
+ def start_process(self, args, **kwargs):
+ p = Process(args, ctx=self, **kwargs)
- if not wait:
+ if not kwargs.get('wait', False):
self.processes.append(p)
return p
--
2.26.2
1 year, 8 months
[PATCH] tools: remove old test-runner.c
by James Prestwood
---
tools/test-runner.c | 3308 -------------------------------------------
1 file changed, 3308 deletions(-)
delete mode 100644 tools/test-runner.c
diff --git a/tools/test-runner.c b/tools/test-runner.c
deleted file mode 100644
index 232c0ba8..00000000
--- a/tools/test-runner.c
+++ /dev/null
@@ -1,3308 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2012-2019 Intel Corporation. All rights reserved.
- *
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <string.h>
-#include <getopt.h>
-#include <poll.h>
-#include <dirent.h>
-#include <sys/wait.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/mount.h>
-#include <sys/param.h>
-#include <sys/reboot.h>
-#include <sys/time.h>
-#include <glob.h>
-#include <time.h>
-#include <ell/ell.h>
-
-#include "linux/nl80211.h"
-
-#ifndef WAIT_ANY
-#define WAIT_ANY (-1)
-#endif
-
-#define CMDLINE_MAX 2048
-
-#define BIN_IW "iw"
-#define BIN_HWSIM "hwsim"
-#define BIN_OFONO "ofonod"
-#define BIN_PHONESIM "phonesim"
-#define BIN_HOSTAPD "hostapd"
-#define BIN_IWD "iwd"
-
-#define HWSIM_RADIOS_MAX 100
-#define TEST_MAX_EXEC_TIME_SEC 20
-
-static enum action {
- ACTION_AUTO_TEST,
- ACTION_UNIT_TEST,
-} test_action;
-
-static const char *own_binary;
-static char **test_argv;
-static int test_argc;
-static char **verbose_apps;
-static char *verbose_opt;
-static bool valgrind;
-static char *gdb_opt;
-static bool enable_debug;
-const char *debug_filter;
-static struct l_settings *hw_config;
-static bool native_hw;
-static bool shell;
-static bool log;
-static char log_dir[PATH_MAX];
-static uid_t log_uid;
-static gid_t log_gid;
-static const char *qemu_binary;
-static const char *kernel_image;
-static const char *exec_home;
-static const char *test_action_params;
-static char top_level_path[PATH_MAX];
-static struct l_queue *wiphy_list;
-
-#if defined(__i386__)
-/*
- * If iwd is being compiled for i386, prefer the i386 qemu but try the
- * X86-64 version as a fallback.
- */
-static const char * const qemu_table[] = {
- "qemu-system-i386",
- "/usr/bin/qemu-system-i386",
- "qemu-system-x86_64",
- "/usr/bin/qemu-system-x86_64",
- NULL
-};
-#elif defined(__x86_64__)
-/*
- * If iwd is being built for X86-64 bits there's no point booting a 32-bit
- * only system.
- */
-static const char * const qemu_table[] = {
- "qemu-system-x86_64",
- "/usr/bin/qemu-system-x86_64",
- NULL
-};
-#elif defined(__arm__)
-/*
- * If iwd is being built for ARM look for 32-bit version.
- */
-static const char * const qemu_table[] = {
- "qemu-system-arm",
- "/usr/bin/qemu-system-arm",
- NULL
-};
-#elif defined(__aarch64__)
-/*
- * If iwd is being built for AARCH64 look for 64-bit version.
- */
-static const char * const qemu_table[] = {
- "qemu-system-aarch64",
- "/usr/bin/qemu-system-aarch64",
- NULL
-};
-#elif defined(__powerpc__)
-/*
- * If iwd is being built for PowerPC look for 32-bit version.
- */
-static const char * const qemu_table[] = {
- "qemu-system-ppc",
- "/usr/bin/qemu-system-ppc",
- NULL
-};
-#elif defined(__powerpc64__)
-/*
- * If iwd is being built for PowerPC-64 look for 64-bit version.
- */
-static const char * const qemu_table[] = {
- "qemu-system-ppc64",
- "/usr/bin/qemu-system-ppc64",
- NULL
-};
-#else
-#warning Qemu binary name not defined for this architecture yet
-static const char * const qemu_table[] = { NULL };
-#endif
-
-struct wiphy {
- char name[20];
- int id;
- unsigned int interface_index;
- bool interface_created : 1;
- bool used_by_hostapd : 1;
- char *interface_name;
- char *hostapd_ctrl_interface;
- char *hostapd_config;
- bool can_ap;
-};
-
-static bool check_verbosity(const char *app)
-{
- char **apps = verbose_apps;
-
- /*
- * All processes are verbose if logging is enabled. Kernel is a bit
- * different as we just pipe dmesg into a log file at the end of
- * execution.
- */
- if (log && strcmp(app, "kernel") != 0)
- return true;
-
- /*
- * Turn on output if this is a unit test run. Nothing should output
- * anything except the tests themselves and the kernel.
- */
- if (test_action == ACTION_UNIT_TEST && strcmp(app, "kernel") != 0)
- return true;
-
- if (!apps)
- return false;
-
- while (*apps) {
- if (!strcmp(app, *apps))
- return true;
-
- apps++;
- }
-
- return false;
-}
-
-static bool path_exist(const char *path_name)
-{
- struct stat st;
-
- if (!stat(path_name, &st))
- return true;
-
- return false;
-}
-
-static const char *find_qemu(void)
-{
- int i;
-
- for (i = 0; qemu_table[i]; i++)
- if (path_exist(qemu_table[i]))
- return qemu_table[i];
-
- return NULL;
-}
-
-static const char * const kernel_table[] = {
- "bzImage",
- "arch/x86/boot/bzImage",
- "vmlinux",
- "arch/x86/boot/vmlinux",
- NULL
-};
-
-static const char *find_kernel(void)
-{
- int i;
-
- for (i = 0; kernel_table[i]; i++)
- if (path_exist(kernel_table[i]))
- return kernel_table[i];
-
- return NULL;
-}
-
-static const struct {
- const char *target;
- const char *linkpath;
-} dev_table[] = {
- { "/proc/self/fd", "/dev/fd" },
- { "/proc/self/fd/0", "/dev/stdin" },
- { "/proc/self/fd/1", "/dev/stdout" },
- { "/proc/self/fd/2", "/dev/stderr" },
- { }
-};
-
-static const struct {
- const char *fstype;
- const char *target;
- const char *options;
- unsigned long flags;
-} mount_table[] = {
- { "sysfs", "/sys", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV },
- { "proc", "/proc", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV },
- { "devpts", "/dev/pts", "mode=0620", MS_NOSUID|MS_NOEXEC },
- { "tmpfs", "/dev/shm", "mode=1777",
- MS_NOSUID|MS_NODEV|MS_STRICTATIME },
- { "tmpfs", "/run", "mode=0755",
- MS_NOSUID|MS_NODEV|MS_STRICTATIME },
- { "tmpfs", "/var/lib/iwd", "mode=0755", 0 },
- { "tmpfs", "/tmp", NULL, 0 },
- { "debugfs", "/sys/kernel/debug", NULL, 0 },
- { }
-};
-
-static const char * const config_table[] = {
- "/usr/share/dbus-1",
- NULL
-};
-
-static void prepare_sandbox(void)
-{
- int i;
-
- for (i = 0; mount_table[i].fstype; i++) {
- struct stat st;
-
- if (lstat(mount_table[i].target, &st) < 0) {
- mkdir(mount_table[i].target, 0755);
- }
-
- if (mount(mount_table[i].fstype,
- mount_table[i].target,
- mount_table[i].fstype,
- mount_table[i].flags,
- mount_table[i].options) < 0) {
- l_error("Error: Failed to mount filesystem %s",
- mount_table[i].target);
- }
- }
-
- for (i = 0; dev_table[i].target; i++) {
-
- if (symlink(dev_table[i].target, dev_table[i].linkpath) < 0)
- l_error("Failed to create device symlink: %s",
- strerror(errno));
- }
-
- setsid();
-
- ioctl(STDIN_FILENO, TIOCSCTTY, 1);
-
- for (i = 0; config_table[i]; i++) {
- if (mount("tmpfs", config_table[i], "tmpfs",
- MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
- "mode=0755") < 0)
- l_error("Failed to create filesystem: %s",
- strerror(errno));
- }
-}
-
-static char *const qemu_argv[] = {
- "",
- "-machine", "type=q35,accel=kvm:tcg",
- "-nodefaults",
- "-no-user-config",
- "-monitor", "none",
- "-display", "none",
- "-m", "192M",
- "-nographic",
- "-vga", "none",
- "-net", "none",
- "-no-acpi",
- "-no-hpet",
- "-no-reboot",
- "-fsdev", "local,id=fsdev-root,path=/,readonly,security_model=none",
- "-device", "virtio-9p-pci,fsdev=fsdev-root,mount_tag=/dev/root",
- "-chardev", "stdio,id=chardev-serial0,signal=off",
- "-device", "pci-serial,chardev=chardev-serial0",
- "-device", "virtio-rng-pci",
- NULL
-};
-
-static char *const qemu_envp[] = {
- "HOME=/",
- NULL
-};
-
-static bool check_virtualization(void)
-{
-#if defined(__GNUC__) && (defined(__i386__) || defined(__amd64__))
- uint32_t ecx;
-
- __asm__ __volatile__("cpuid" : "=c" (ecx) :
- "a" (1) : "%ebx", "%edx");
-
- if (!!(ecx & (1 << 5))) {
- l_info("Found support for Virtual Machine eXtensions");
- return true;
- }
-
- __asm__ __volatile__("cpuid" : "=c" (ecx) :
- "a" (0x80000001) : "%ebx", "%edx");
-
- if (ecx & (1 << 2)) {
- l_info("Found support for Secure Virtual Machine extension");
- return true;
- }
-#endif
- return false;
-}
-
-static bool start_qemu(void)
-{
- char cwd[PATH_MAX], testargs[PATH_MAX];
- char *initcmd, *cmdline;
- char **argv;
- int i, pos;
- bool has_virt;
- int num_pci = 0, num_usb = 0;
- char **pci_keys = NULL;
- char **usb_keys = NULL;
- L_AUTO_FREE_VAR(char *, log_option) = NULL;
-
- has_virt = check_virtualization();
-
- if (!getcwd(cwd, sizeof(cwd)))
- strcat(cwd, "/");
-
- if (own_binary[0] == '/')
- initcmd = l_strdup_printf("%s", own_binary);
- else
- initcmd = l_strdup_printf("%s/%s", cwd, own_binary);
-
- pos = snprintf(testargs, sizeof(testargs), "%s", test_argv[0]);
-
- for (i = 1; i < test_argc; i++) {
- int len;
-
- len = sizeof(testargs) - pos;
- pos += snprintf(testargs + pos, len, " %s", test_argv[i]);
- }
-
- cmdline = l_strdup_printf(
- "console=ttyS0,115200n8 earlyprintk=serial "
- "rootfstype=9p "
- "root=/dev/root "
- "rootflags=trans=virtio,version=9p2000.u "
- "acpi=off pci=noacpi noapic %s ro "
- "mac80211_hwsim.radios=0 init=%s TESTHOME=%s "
- "TESTVERBOUT=\'%s\' DEBUG_FILTER=\'%s\'"
- "TEST_ACTION=%u TEST_ACTION_PARAMS=\'%s\' "
- "TESTARGS=\'%s\' PATH=\'%s\' VALGRIND=%u "
- "GDB=\'%s\' HW=\'%s\' SHELL=%u "
- "LOG_PATH=\'%s\' LOG_UID=\'%d\' LOG_GID=\'%d\'",
- check_verbosity("kernel") ? "ignore_loglevel" : "quiet",
- initcmd, cwd, verbose_opt ? verbose_opt : "none",
- enable_debug ? debug_filter : "",
- test_action,
- test_action_params ? test_action_params : "",
- testargs,
- getenv("PATH"),
- valgrind,
- gdb_opt ? gdb_opt : "none",
- hw_config ? "real" : "virtual",
- shell,
- log ? log_dir : "none",
- log_uid, log_gid);
-
- if (hw_config) {
- if (l_settings_has_group(hw_config, "PCIAdapters")) {
- pci_keys = l_settings_get_keys(hw_config, "PCIAdapters");
-
- for (num_pci = 0; pci_keys[num_pci]; num_pci++);
- }
-
- if (l_settings_has_group(hw_config, "USBAdapters")) {
- usb_keys = l_settings_get_keys(hw_config, "USBAdapters");
-
- for (num_usb = 0; usb_keys[num_usb]; num_usb++);
- }
-
- if (!pci_keys && !usb_keys) {
- l_error("hs config had no PCIAdapters or USBAdapters");
- l_free(initcmd);
- l_free(cmdline);
- return false;
- }
- }
-
- /*
- * This got quite confusing. We need enough room for:
- *
- * qemu_argv (static list above with default parameters)
- * -kernel,-append,-cpu,-host parameters (7)
- * -enable-kvm and/or -usb (2)
- * PCI and/or USB parameters (num_pci * 2) (num_usb * 2)
- * Logging directory/device (2)
- */
- argv = alloca(sizeof(qemu_argv) + sizeof(char *) *
- (7 + (2 + (num_pci * 2) + (num_usb * 2) + 2)));
- memcpy(argv, qemu_argv, sizeof(qemu_argv));
-
- pos = (sizeof(qemu_argv) / sizeof(char *)) - 1;
-
- argv[0] = (char *) qemu_binary;
-
- argv[pos++] = "-kernel";
- argv[pos++] = (char *) kernel_image;
- argv[pos++] = "-append";
- argv[pos++] = (char *) cmdline;
- argv[pos++] = "-cpu";
- argv[pos++] = has_virt ? "host" : "max";
-
- if (pci_keys) {
- argv[pos++] = "-enable-kvm";
- for (i = 0; pci_keys[i]; i++) {
- argv[pos++] = "-device";
- argv[pos] = alloca(22);
- sprintf(argv[pos], "vfio-pci,host=%s",
- l_settings_get_value(hw_config,
- "PCIAdapters", pci_keys[i]));
- pos++;
- }
- }
-
- if (usb_keys) {
- argv[pos++] = "-usb";
- for (i = 0; usb_keys[i]; i++) {
- const char *value = l_settings_get_value(hw_config,
- "USBAdapters", usb_keys[i]);
- char **info = l_strsplit(value, ',');
-
- if (l_strv_length(info) != 2) {
- l_error("hw config formatting error");
- l_strv_free(info);
- return false;
- }
-
- argv[pos++] = "-device";
- argv[pos] = alloca(32);
- sprintf(argv[pos], "usb-host,hostbus=%s,hostaddr=%s",
- info[0], info[1]);
- pos++;
-
- l_strv_free(info);
- }
- }
-
- if (log) {
- /*
- * Create a virtfs device and tag it. This allows the guest to
- * mount 'logdir' in the path specified with --log.
- */
- log_option = l_strdup_printf("local,path=%s,mount_tag=logdir,"
- "security_model=passthrough,id=logdir",
- log_dir);
- argv[pos++] = "-virtfs";
- argv[pos++] = log_option;
- }
-
- argv[pos] = NULL;
-
- execve(argv[0], argv, qemu_envp);
-
- /* Don't expect to reach here */
- free(initcmd);
- free(cmdline);
-
- return true;
-}
-
-static pid_t execute_program(char *argv[], char *envp[], bool wait,
- const char *test_name)
-{
- int status;
- pid_t pid, child_pid;
- char *str;
- bool verbose;
- char *log_name = argv[0];
-
- if (!argv[0])
- return -1;
-
- /*
- * We have a few special cases here:
- *
- * Since execute_program automatically logs to <process>.log this would
- * put all iwd output into valgrind.log rather than iwd.log. Since we
- * are explicitly having valgrind output to a log file we can assume any
- * output from this is only IWD, and not valgrind.
- *
- * python3 is special cased so that tests which start IWD manually can
- * still show IWD output when using -v iwd.
- */
- if (!strcmp(log_name, "valgrind") || !strcmp(log_name, "python3"))
- log_name = "iwd";
-
- str = l_strjoinv(argv, ' ');
- l_debug("Executing: %s", str);
- l_free(str);
-
- child_pid = fork();
- if (child_pid < 0) {
- l_error("Failed to fork new process");
- return -1;
- }
-
- if (child_pid == 0) {
- int fd = -1;
- L_AUTO_FREE_VAR(char *, log_file) = NULL;
-
- verbose = check_verbosity(log_name);
-
- /* No stdout and no logging */
- if (!verbose && !log)
- fd = open("/dev/null", O_WRONLY);
- else if (log && verbose) {
- /*
- * Create the log file for this process. If no test name
- * was specified this is a 'global' process (only run
- * once, not per-test).
- */
- if (test_name) {
- log_file = l_strdup_printf("%s/%s/%s.log",
- log_dir, test_name, log_name);
- } else
- log_file = l_strdup_printf("%s/%s.log",
- log_dir, log_name);
-
- fd = open(log_file, O_WRONLY | O_CREAT | O_APPEND,
- S_IRUSR | S_IWUSR);
- if (fchown(fd, log_uid, log_gid) < 0)
- l_error("failed to fchown %s", log_file);
- }
-
- if (fd > -1) {
- dup2(fd, 1);
- dup2(fd, 2);
-
- close(fd);
- }
-
- execvpe(argv[0], argv, envp);
-
- l_error("Failed to call execvpe for: %s. Error: %s", argv[0],
- strerror(errno));
-
- exit(EXIT_FAILURE);
- }
-
- if (!wait)
- goto exit;
-
- do {
- pid = waitpid(child_pid, &status, 0);
- } while (!WIFEXITED(status) && pid == child_pid);
-
- if (WEXITSTATUS(status) != EXIT_SUCCESS)
- return -1;
-
-exit:
- return child_pid;
-}
-
-static void kill_process(pid_t pid)
-{
- int status;
- int i = 0;
-
- l_debug("Terminate pid: %d", pid);
-
- kill(pid, SIGTERM);
-
- do {
- if (waitpid(pid, &status, WNOHANG) == pid)
- return;
-
- usleep(100000);
- } while (!WIFEXITED(status) && !WIFSIGNALED(status) && i++ < 20);
-
- l_error("Failed to kill process %d gracefully", pid);
- kill(pid, SIGKILL);
-
- /* SIGKILL shouldn't need WNOHANG */
- waitpid(pid, &status, 0);
-}
-
-static bool wait_for_socket(const char *socket, useconds_t wait_time)
-{
- int i = 0;
-
- do {
- if (path_exist(socket))
- return true;
-
- usleep(wait_time);
- } while ((wait_time > 0) ? i++ < 20 : true);
-
- l_error("Error: cannot find socket: %s", socket);
- return false;
-}
-
-static void create_dbus_system_conf(void)
-{
- FILE *fp;
-
- fp = fopen("/usr/share/dbus-1/system.conf", "we");
- if (!fp)
- return;
-
- fputs("<!DOCTYPE busconfig PUBLIC ", fp);
- fputs("\"-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN\" ", fp);
- fputs("\"http://www.freedesktop.org/standards/dbus/1.0/", fp);
- fputs("busconfig.dtd\">\n", fp);
- fputs("<busconfig>\n", fp);
- fputs("<type>system</type>\n", fp);
- fputs("<listen>unix:path=/run/dbus/system_bus_socket</listen>\n", fp);
- fputs("<limit name=\"reply_timeout\">2147483647</limit>", fp);
- fputs("<policy context=\"default\">\n", fp);
- fputs("<allow user=\"*\"/>\n", fp);
- fputs("<allow own=\"*\"/>\n", fp);
- fputs("<allow send_type=\"method_call\"/>\n", fp);
- fputs("<allow send_type=\"signal\"/>\n", fp);
- fputs("<allow send_type=\"method_return\"/>\n", fp);
- fputs("<allow send_type=\"error\"/>\n", fp);
- fputs("<allow receive_type=\"method_call\"/>\n", fp);
- fputs("<allow receive_type=\"signal\"/>\n", fp);
- fputs("<allow receive_type=\"method_return\"/>\n", fp);
- fputs("<allow receive_type=\"error\"/>\n", fp);
- fputs("</policy>\n", fp);
- fputs("</busconfig>\n", fp);
-
- fclose(fp);
-
- mkdir("/run/dbus", 0755);
-}
-
-static bool start_dbus_daemon(void)
-{
- char *argv[4];
- pid_t pid;
-
- argv[0] = "dbus-daemon";
- argv[1] = "--system";
- argv[2] = "--nosyslog";
- argv[3] = NULL;
-
- if (check_verbosity("dbus"))
- setenv("DBUS_VERBOSE", "1", true);
-
- pid = execute_program(argv, environ, false, NULL);
- if (pid < 0)
- return false;
-
- if (!wait_for_socket("/run/dbus/system_bus_socket", 25 * 10000))
- return false;
-
- if (check_verbosity("dbus-monitor")) {
- argv[0] = "dbus-monitor";
- argv[1] = "--system";
- argv[2] = NULL;
- execute_program(argv, environ, false, NULL);
- }
-
- l_debug("D-Bus is running");
-
- return true;
-}
-
-static bool start_haveged(void)
-{
- char *argv[2];
- pid_t pid;
-
- argv[0] = "haveged";
- argv[1] = NULL;
-
- pid = execute_program(argv, environ, true, NULL);
- if (pid < 0)
- return false;
-
- return true;
-}
-
-static bool set_interface_state(const char *if_name, bool isUp)
-{
- char *state, *argv[4];
- pid_t pid;
-
- if (isUp)
- state = "up";
- else
- state = "down";
-
- argv[0] = "ifconfig";
- argv[1] = (char *) if_name;
- argv[2] = state;
- argv[3] = NULL;
-
- pid = execute_program(argv, environ, true, NULL);
- if (pid < 0)
- return false;
-
- return true;
-}
-
-static bool create_interface(const char *if_name, const char *phy_name)
-{
- char *argv[9];
- pid_t pid;
-
- argv[0] = BIN_IW;
- argv[1] = "phy";
- argv[2] = (char *) phy_name;
- argv[3] = "interface";
- argv[4] = "add";
- argv[5] = (char *) if_name;
- argv[6] = "type";
- argv[7] = "managed";
- argv[8] = NULL;
-
- pid = execute_program(argv, environ, true, NULL);
- if (pid < 0)
- return false;
-
- return true;
-}
-
-static bool delete_interface(const char *if_name)
-{
- char *argv[5];
- pid_t pid;
-
- argv[0] = BIN_IW;
- argv[1] = "dev";
- argv[2] = (char *) if_name;
- argv[3] = "del";
- argv[4] = NULL;
-
- pid = execute_program(argv, environ, true, NULL);
- if (pid < 0)
- return false;
-
- return true;
-}
-
-static bool list_interfaces(void)
-{
- char *argv[3];
- pid_t pid;
-
- argv[0] = "ifconfig";
- argv[1] = "-a";
- argv[2] = NULL;
-
- pid = execute_program(argv, environ, true, NULL);
- if (pid < 0)
- return false;
-
- return true;
-}
-
-static bool list_hwsim_radios(void)
-{
- char *argv[3];
- pid_t pid;
-
- argv[0] = BIN_HWSIM;
- argv[1] = "--list";
- argv[2] = NULL;
-
- pid = execute_program(argv, environ, true, NULL);
- if (pid < 0)
- return false;
-
- return true;
-}
-
-static int read_radio_id(void)
-{
- static int current_radio_id;
-
- return current_radio_id++;
-}
-
-struct hwsim_radio_params {
- unsigned int channels;
- bool p2p_device;
- bool use_chanctx;
- char *iftype_disable;
- char *cipher_disable;
-};
-
-static int create_hwsim_radio(const char *radio_name,
- struct hwsim_radio_params *params)
-{
- char *argv[10];
- pid_t pid;
- int idx = 0;
-
- /*TODO add the rest of params*/
- argv[idx++] = BIN_HWSIM;
- argv[idx++] = "--create";
- argv[idx++] = "--name";
- argv[idx++] = (char *) radio_name;
- argv[idx++] = "--nointerface";
-
- if (params->iftype_disable) {
- argv[idx++] = "--iftype-disable";
- argv[idx++] = params->iftype_disable;
- }
-
- if (params->cipher_disable) {
- argv[idx++] = "--cipher-disable";
- argv[idx++] = params->cipher_disable;
- }
-
- argv[idx] = NULL;
-
- pid = execute_program(argv, environ, true, NULL);
- if (pid < 0)
- return -1;
-
- return read_radio_id();
-}
-
-static bool destroy_hwsim_radio(int radio_id)
-{
- char *argv[4];
- char destroy_param[20];
- pid_t pid;
-
- sprintf(destroy_param, "--destroy=%d", radio_id);
-
- argv[0] = BIN_HWSIM;
- argv[1] = destroy_param;
- argv[2] = NULL;
-
- pid = execute_program(argv, environ, true, NULL);
- if (pid < 0)
- return false;
-
- return true;
-}
-
-static pid_t register_hwsim_as_trans_medium(void)
-{
- char *argv[16];
- unsigned int idx = 0;
-
- if (strcmp(gdb_opt, "hwsim") == 0) {
- argv[idx++] = "gdb";
- argv[idx++] = "--args";
- }
-
- argv[idx++] = BIN_HWSIM;
- argv[idx++] = NULL;
-
- return execute_program(argv, environ, false, NULL);
-}
-
-static void terminate_medium(pid_t medium_pid)
-{
- kill_process(medium_pid);
-}
-
-#define HOSTAPD_CTRL_INTERFACE_PREFIX "/var/run/hostapd"
-
-static bool loopback_started;
-
-static void start_loopback(void)
-{
- char *argv[7];
-
- if (loopback_started)
- return;
-
- argv[0] = "ifconfig";
- argv[1] = "lo";
- argv[2] = "127.0.0.1";
- argv[3] = "up";
- argv[4] = NULL;
- execute_program(argv, environ, false, NULL);
-
- argv[0] = "route";
- argv[1] = "add";
- argv[2] = "127.0.0.1";
- argv[3] = NULL;
- execute_program(argv, environ, false, NULL);
-
- loopback_started = true;
-}
-
-static pid_t start_phonesim(const char *test_name)
-{
- char *argv[5];
-
- argv[0] = BIN_PHONESIM;
- argv[1] = "-p";
- argv[2] = "12345";
- argv[3] = "/usr/share/phonesim/default.xml";
- argv[4] = NULL;
-
- start_loopback();
-
- setenv("OFONO_PHONESIM_CONFIG", "/tmp/phonesim.conf", true);
-
- return execute_program(argv, environ, false, test_name);
-}
-
-static void stop_phonesim(pid_t pid)
-{
- kill_process(pid);
-}
-
-static pid_t start_ofono(const char *test_name)
-{
- char *argv[5];
- bool verbose = check_verbosity(BIN_OFONO);
-
- argv[0] = BIN_OFONO;
- argv[1] = "-n";
- argv[2] = "--plugin=atmodem,phonesim";
-
- if (verbose)
- argv[3] = "-d";
- else
- argv[3] = NULL;
-
- argv[4] = NULL;
-
- start_loopback();
-
- return execute_program(argv, environ, false, test_name);
-}
-
-static void stop_ofono(pid_t pid)
-{
- kill_process(pid);
-}
-
-static pid_t start_hostapd(char **config_files, struct wiphy **wiphys,
- const char *test_name, const char *radius_conf)
-{
- char **argv;
- pid_t pid;
- int idx = 0;
- uint32_t wait = 25 * 10000;
- bool verbose = check_verbosity(BIN_HOSTAPD);
- size_t ifnames_size;
- char *ifnames;
- int i;
-
- for (i = 0, ifnames_size = 0; wiphys[i]; i++)
- ifnames_size += 1 + strlen(wiphys[i]->interface_name);
-
- argv = alloca(sizeof(char *) * (9 + i));
-
- if (strcmp(gdb_opt, "hostapd") == 0) {
- argv[idx++] = "gdb";
- argv[idx++] = "--args";
- wait = 0;
- }
-
- argv[idx++] = BIN_HOSTAPD;
-
- ifnames = alloca(ifnames_size);
- argv[idx++] = "-i";
- argv[idx++] = ifnames;
-
- argv[idx++] = "-g";
- argv[idx++] = wiphys[0]->hostapd_ctrl_interface;
-
- for (i = 0, ifnames_size = 0; wiphys[i]; i++) {
- if (ifnames_size)
- ifnames[ifnames_size++] = ',';
- strcpy(ifnames + ifnames_size, wiphys[i]->interface_name);
- ifnames_size += strlen(wiphys[i]->interface_name);
-
- argv[idx++] = config_files[i];
- }
-
- if (radius_conf)
- argv[idx++] = (void *)radius_conf;
-
- if (verbose) {
- argv[idx++] = "-d";
- argv[idx++] = NULL;
- } else {
- argv[idx++] = NULL;
- }
-
- pid = execute_program(argv, environ, false, log ? test_name : NULL);
- if (pid < 0) {
- goto exit;
- }
-
- if (!wait_for_socket(wiphys[0]->hostapd_ctrl_interface, wait))
- pid = -1;
-exit:
- return pid;
-}
-
-static void destroy_hostapd_instances(pid_t hostapd_pids[])
-{
- int i = 0;
-
- while (hostapd_pids[i] != -1) {
- kill_process(hostapd_pids[i]);
-
- l_debug("hostapd instance with pid=%d is destroyed",
- hostapd_pids[i]);
-
- hostapd_pids[i] = -1;
-
- i++;
- }
-}
-
-#define TEST_TOP_DIR_DEFAULT_NAME "autotests"
-#define TEST_DIR_PREFIX "test"
-
-static bool is_test_file(const char *file)
-{
- size_t i;
- static const char * const test_file_extension_table[] = {
- "test",
- "test.py",
- "Test",
- "Test.py",
- NULL
- };
-
- for (i = 0; test_file_extension_table[i]; i++) {
- if (l_str_has_suffix(file, test_file_extension_table[i]))
- return true;
- }
-
- return false;
-}
-
-static int is_test_dir(const char *dir)
-{
- return strncmp(dir, TEST_DIR_PREFIX, strlen(TEST_DIR_PREFIX)) == 0;
-}
-
-static bool find_test_configuration(const char *path, int level,
- struct l_queue *config_queue);
-
-struct test_entry {
- struct l_queue *test_queue;
- char *path;
-};
-
-static int insert_py_test(const void *a, const void *b, void *user_data)
-{
- return strcmp((const char *)a, (const char *)b);
-}
-
-static int insert_test_entry(const void *a, const void *b, void *user_data)
-{
- const struct test_entry *entry_a = a;
- const struct test_entry *entry_b = b;
-
- return strcmp(entry_a->path, entry_b->path);
-}
-
-static bool add_path(const char *path, int level, struct l_queue *config_queue)
-{
- DIR *dir = NULL;
- struct l_queue *py_test_queue = NULL;
- struct dirent *entry;
- char *npath;
-
- dir = opendir(path);
- if (!dir) {
- l_error("Test directory does not exist: %s", path);
- return false;
- }
-
- while ((entry = readdir(dir))) {
- if (entry->d_type == DT_DIR) {
- if (!strcmp(entry->d_name, ".") ||
- !strcmp(entry->d_name, ".."))
- continue;
-
- if (level == 0 && is_test_dir(entry->d_name)) {
- npath = l_strdup_printf("%s/%s", path,
- entry->d_name);
-
- find_test_configuration(npath, 1, config_queue);
-
- l_free(npath);
- }
- } else if (level == 1 && is_test_file(entry->d_name)) {
- if (!py_test_queue)
- py_test_queue = l_queue_new();
-
- l_queue_insert(py_test_queue, l_strdup(entry->d_name),
- insert_py_test, NULL);
- }
- }
-
- if (py_test_queue && !l_queue_isempty(py_test_queue)) {
- struct test_entry *entry = l_new(struct test_entry, 1);
-
- entry->test_queue = py_test_queue;
- entry->path = l_strdup(path);
-
- l_queue_insert(config_queue, entry, insert_test_entry, NULL);
- }
-
- closedir(dir);
- return true;
-}
-
-static bool find_test_configuration(const char *path, int level,
- struct l_queue *config_queue)
-{
- glob_t glist;
- int i = 0;
- int ret;
-
- if (!config_queue)
- return false;
-
- ret = glob(path, 0, NULL, &glist);
- if (ret != 0) {
- l_error("Could not match glob %s", path);
- return false;
- }
-
- while (glist.gl_pathv[i]) {
- if (!add_path(glist.gl_pathv[i], level, config_queue))
- return false;
-
- i++;
- }
-
- return true;
-}
-
-#define HW_CONFIG_FILE_NAME "hw.conf"
-#define HW_CONFIG_GROUP_HOSTAPD "HOSTAPD"
-#define HW_CONFIG_GROUP_SETUP "SETUP"
-
-#define HW_CONFIG_SETUP_NUM_RADIOS "num_radios"
-#define HW_CONFIG_SETUP_RADIO_CONFS "radio_confs"
-#define HW_CONFIG_SETUP_MAX_EXEC_SEC "max_test_exec_interval_sec"
-#define HW_CONFIG_SETUP_TMPFS_EXTRAS "tmpfs_extra_stuff"
-#define HW_CONFIG_SETUP_START_IWD "start_iwd"
-#define HW_CONFIG_SETUP_IWD_CONF_DIR "iwd_config_dir"
-#define HW_CONFIG_SETUP_REG_DOMAIN "reg_domain"
-#define HW_CONFIG_SETUP_NEEDS_HWSIM "needs_hwsim"
-
-static struct l_settings *read_hw_config(const char *test_dir_path)
-{
- struct l_settings *hw_settings;
- char *hw_file;
-
- hw_file = l_strdup_printf("%s/%s", test_dir_path, HW_CONFIG_FILE_NAME);
-
- hw_settings = l_settings_new();
-
- if (!l_settings_load_from_file(hw_settings, hw_file)) {
- l_error("No %s file found", HW_CONFIG_FILE_NAME);
- goto error_exit;
- }
-
- if (!l_settings_has_group(hw_settings, HW_CONFIG_GROUP_SETUP)) {
- l_error("No %s setting group found in %s",
- HW_CONFIG_GROUP_SETUP, hw_file);
- goto error_exit;
- }
-
- l_free(hw_file);
- return hw_settings;
-
-error_exit:
- l_free(hw_file);
- l_settings_free(hw_settings);
- return NULL;
-}
-
-#define HW_CONFIG_PHY_CHANNELS "channels"
-#define HW_CONFIG_PHY_CHANCTX "use_chanctx"
-#define HW_CONFIG_PHY_P2P "p2p_device"
-#define HW_CONFIG_PHY_IFTYPE_DISABLE "iftype_disable"
-#define HW_CONFIG_PHY_CIPHER_DISABLE "cipher_disable"
-
-#define HW_MIN_NUM_RADIOS 1
-
-#define HW_INTERFACE_PREFIX "wln"
-#define HW_INTERFACE_STATE_UP true
-#define HW_INTERFACE_STATE_DOWN false
-
-static bool configure_hw_radios(struct l_settings *hw_settings,
- struct l_queue *wiphy_list)
-{
- char **radio_conf_list;
- int i, num_radios_requested;
- bool status = false;
-
- l_settings_get_int(hw_settings, HW_CONFIG_GROUP_SETUP,
- HW_CONFIG_SETUP_NUM_RADIOS,
- &num_radios_requested);
-
- if (num_radios_requested < HW_MIN_NUM_RADIOS) {
- l_error("%s must be greater or equal to %d",
- HW_CONFIG_SETUP_NUM_RADIOS, HW_MIN_NUM_RADIOS);
- return false;
- }
-
- radio_conf_list =
- l_settings_get_string_list(hw_settings, HW_CONFIG_GROUP_SETUP,
- HW_CONFIG_SETUP_RADIO_CONFS,
- ':');
- for (i = 0; i < num_radios_requested; i++) {
- struct wiphy *wiphy;
- struct hwsim_radio_params params = { 0 };
-
- wiphy = l_new(struct wiphy, 1);
-
- sprintf(wiphy->name, "rad%d", i);
-
- /* radio not in radio_confs, use default parameters */
- if (!l_strv_contains(radio_conf_list, wiphy->name)) {
- params.channels = 1;
- params.p2p_device = true;
- params.use_chanctx = true;
- goto create;
- }
-
- if (!l_settings_get_uint(hw_settings, wiphy->name,
- HW_CONFIG_PHY_CHANNELS,
- ¶ms.channels))
- params.channels = 1;
-
- if (!l_settings_get_bool(hw_settings, wiphy->name,
- HW_CONFIG_PHY_P2P, ¶ms.p2p_device))
- params.p2p_device = true;
-
- if (!l_settings_get_bool(hw_settings, wiphy->name,
- HW_CONFIG_PHY_CHANCTX,
- ¶ms.use_chanctx))
- params.use_chanctx = true;
-
- params.iftype_disable = l_settings_get_string(hw_settings,
- wiphy->name,
- HW_CONFIG_PHY_IFTYPE_DISABLE);
- params.cipher_disable = l_settings_get_string(hw_settings,
- wiphy->name,
- HW_CONFIG_PHY_CIPHER_DISABLE);
-
-create:
- wiphy->id = create_hwsim_radio(wiphy->name, ¶ms);
- wiphy->can_ap = true;
-
- if (wiphy->id < 0) {
- l_free(wiphy);
- goto exit;
- }
-
- l_queue_push_tail(wiphy_list, wiphy);
- }
-
- status = true;
-
-exit:
- l_strfreev(radio_conf_list);
- return status;
-}
-
-static void wiphy_free(void *data)
-{
- struct wiphy *wiphy = data;
-
- if (wiphy->interface_created) {
- set_interface_state(wiphy->interface_name,
- HW_INTERFACE_STATE_DOWN);
-
- if (delete_interface(wiphy->interface_name))
- l_debug("Removed interface %s", wiphy->interface_name);
- else
- l_error("Failed to remove interface %s",
- wiphy->interface_name);
- }
-
- /* Native interfaces cannot be destroyed */
- if (native_hw) {
- set_interface_state(wiphy->interface_name,
- HW_INTERFACE_STATE_DOWN);
- } else {
- destroy_hwsim_radio(wiphy->id);
- l_debug("Removed radio id %d", wiphy->id);
- }
-
- l_free(wiphy->hostapd_config);
- l_free(wiphy->hostapd_ctrl_interface);
- l_free(wiphy->interface_name);
-
- l_free(wiphy);
-}
-
-static bool configure_hostapd_instances(struct l_settings *hw_settings,
- char *config_dir_path,
- struct l_queue *wiphy_list,
- pid_t hostapd_pids_out[],
- int *phys_used)
-{
- char **hostap_keys;
- int i;
- char **hostapd_config_file_paths;
- struct wiphy **wiphys;
- const char *radius_config = NULL;
-
- *phys_used = 0;
-
- if (!l_settings_has_group(hw_settings, HW_CONFIG_GROUP_HOSTAPD)) {
- l_info("No hostapd instances to create");
- return true;
- }
-
- hostap_keys =
- l_settings_get_keys(hw_settings, HW_CONFIG_GROUP_HOSTAPD);
-
- for (i = 0; hostap_keys[i]; i++);
-
- hostapd_config_file_paths = l_new(char *, i + 1);
- wiphys = alloca(sizeof(struct wiphy *) * (i + 1));
- memset(wiphys, 0, sizeof(struct wiphy *) * (i + 1));
-
- hostapd_pids_out[0] = -1;
-
- for (i = 0; hostap_keys[i]; i++) {
- const struct l_queue_entry *wiphy_entry;
- const char *hostapd_config_file;
- unsigned wiphy_idx = 0;
-
- hostapd_config_file =
- l_settings_get_value(hw_settings,
- HW_CONFIG_GROUP_HOSTAPD,
- hostap_keys[i]);
-
- hostapd_config_file_paths[i] =
- l_strdup_printf("%s/%s", config_dir_path,
- hostapd_config_file);
-
- if (!path_exist(hostapd_config_file_paths[i])) {
- l_error("%s : hostapd configuration file [%s] "
- "does not exist.", HW_CONFIG_FILE_NAME,
- hostapd_config_file_paths[i]);
- goto done;
- }
-
- if (!strcmp(hostap_keys[i], "radius_server")) {
- radius_config = l_settings_get_value(hw_settings,
- HW_CONFIG_GROUP_HOSTAPD,
- "radius_server");
- continue;
- }
-
- for (wiphy_entry = l_queue_get_entries(wiphy_list);
- wiphy_entry;
- wiphy_entry = wiphy_entry->next,
- wiphy_idx++) {
- struct wiphy *wiphy = wiphy_entry->data;
-
- /*
- * We can skip this check in native mode since we have
- * no control over the phy name. Any test requiring a
- * "special" radio should not be ran in native mode.
- */
- if (!native_hw && strcmp(wiphy->name, hostap_keys[i]))
- continue;
-
- if (wiphy->used_by_hostapd) {
- /*
- * Since we bypass the above check in native
- * mode we could still get here. We can just
- * continue searching for more adapters if this
- * one is already in use.
- */
- if (native_hw)
- continue;
-
- l_error("Wiphy %s already used by hostapd",
- wiphy->name);
- goto done;
- }
-
- if (!wiphy->can_ap)
- continue;
-
- wiphys[i] = wiphy;
- break;
- }
-
- if (!wiphy_entry) {
- l_error("Failed to find available wiphy.");
- goto done;
- }
-
- if (native_hw)
- goto hostapd_done;
-
- wiphys[i]->interface_name = l_strdup_printf("%s%d",
- HW_INTERFACE_PREFIX,
- wiphy_idx);
- if (!create_interface(wiphys[i]->interface_name,
- wiphys[i]->name)) {
- l_error("Failed to create hostapd interface %s on "
- "radio %s",
- wiphys[i]->interface_name, wiphys[i]->name);
- goto done;
- }
-
- wiphys[i]->interface_created = true;
- l_info("Created hostapd interface %s on %s radio",
- wiphys[i]->interface_name, wiphys[i]->name);
-
- if (!native_hw && !set_interface_state(wiphys[i]->interface_name,
- HW_INTERFACE_STATE_UP)) {
- l_error("Failed to set %s state UP",
- wiphys[i]->interface_name);
- goto done;
- }
-
-hostapd_done:
- wiphys[i]->used_by_hostapd = true;
- wiphys[i]->hostapd_ctrl_interface =
- l_strdup_printf("%s/%s", HOSTAPD_CTRL_INTERFACE_PREFIX,
- wiphys[0]->interface_name);
- wiphys[i]->hostapd_config = l_strdup(hostapd_config_file);
-
- (*phys_used)++;
- }
-
- hostapd_pids_out[0] = start_hostapd(hostapd_config_file_paths, wiphys,
- basename(config_dir_path),
- radius_config);
- hostapd_pids_out[1] = -1;
-
-done:
- l_strfreev(hostapd_config_file_paths);
-
- if (hostapd_pids_out[0] < 1)
- return false;
-
- return true;
-}
-
-static pid_t start_iwd(const char *config_dir, struct l_queue *wiphy_list,
- const char *ext_options, int num_phys, const char *test_name)
-{
- char *argv[13], **envp;
- char *iwd_phys = NULL;
- pid_t ret;
- int idx = 0;
- L_AUTO_FREE_VAR(char *, fd_option) = NULL;
-
- if (valgrind) {
- L_AUTO_FREE_VAR(char *, valgrind_log);
- int fd;
-
- argv[idx++] = "valgrind";
- argv[idx++] = "--leak-check=full";
-
- /*
- * Valgrind needs --log-fd if we want both stderr and stdout
- */
- if (log)
- valgrind_log = l_strdup_printf("%s/%s/valgrind.log",
- log_dir, test_name);
- else
- valgrind_log = l_strdup("/tmp/valgrind.log");
-
- fd = open(valgrind_log, O_WRONLY | O_CREAT | O_APPEND,
- S_IRUSR | S_IWUSR);
-
- if (log) {
- if (fchown(fd, log_uid, log_gid) < 0)
- l_error("chown failed");
- }
-
- fd_option = l_strdup_printf("--log-fd=%d", fd);
- argv[idx++] = fd_option;
- }
-
- if (strcmp(gdb_opt, "iwd") == 0) {
- argv[idx++] = "gdb";
- argv[idx++] = "--args";
- }
-
- argv[idx++] = BIN_IWD;
-
- if (check_verbosity(BIN_IWD) || shell)
- argv[idx++] = "-d";
-
- argv[idx] = NULL;
-
- if (wiphy_list) {
- const struct l_queue_entry *wiphy_entry;
- struct l_string *list = l_string_new(64);
-
- for (wiphy_entry = l_queue_get_entries(wiphy_list);
- wiphy_entry;
- wiphy_entry = wiphy_entry->next) {
- struct wiphy *wiphy = wiphy_entry->data;
-
- if (wiphy->used_by_hostapd)
- continue;
-
- /*
- * Break out, only adding the required number of phys
- * for this test.
- */
- if (num_phys == 0)
- break;
-
- l_string_append_printf(list, "%s,", wiphy->name);
-
- num_phys--;
- }
-
- iwd_phys = l_string_unwrap(list);
- /* Take care of last comma */
- iwd_phys[strlen(iwd_phys) - 1] = '\0';
-
- argv[idx++] = "-p";
- argv[idx++] = iwd_phys;
- argv[idx] = NULL;
- }
-
- argv[idx++] = (char *)ext_options;
- argv[idx] = NULL;
-
- envp = l_strv_copy(environ);
- envp = l_strv_append_printf(envp, "CONFIGURATION_DIRECTORY=%s",
- config_dir);
- envp = l_strv_append_printf(envp, "STATE_DIRECTORY=%s",
- DAEMON_STORAGEDIR);
-
- ret = execute_program(argv, envp, false, test_name);
-
- l_strv_free(envp);
-
- l_free(iwd_phys);
-
- return ret;
-}
-
-static void terminate_iwd(pid_t iwd_pid)
-{
- kill_process(iwd_pid);
-}
-
-static pid_t start_monitor(const char *test_name)
-{
- char *argv[6];
- char *write_arg;
- pid_t pid;
-
- write_arg = l_strdup_printf("%s/%s/monitor.pcap", log_dir, test_name);
-
- argv[0] = "iwmon";
- argv[1] = "--nortnl";
- argv[2] = "--nowiphy";
- argv[3] = "--write";
- argv[4] = write_arg;
- argv[5] = NULL;
-
- pid = execute_program(argv, environ, false, test_name);
-
- l_free(write_arg);
-
- return pid;
-}
-
-static bool create_tmpfs_extra_stuff(char **tmpfs_extra_stuff)
-{
- size_t i = 0;
-
- if (!tmpfs_extra_stuff)
- return true;
-
- while (tmpfs_extra_stuff[i]) {
- char *link_dir;
- char *target_dir;
-
- target_dir = realpath(tmpfs_extra_stuff[i], NULL);
-
- if (!path_exist(target_dir)) {
- l_error("No such directory: %s", target_dir);
- l_free(target_dir);
- return false;
- }
-
- link_dir = l_strdup_printf("%s%s", "/tmp",
- rindex(target_dir, '/'));
-
- if (symlink(target_dir, link_dir) < 0) {
- l_error("Failed to create symlink %s for %s: %s",
- link_dir, target_dir, strerror(errno));
-
- l_free(target_dir);
- l_free(link_dir);
- return false;
- }
-
- l_free(tmpfs_extra_stuff[i]);
- l_free(target_dir);
-
- tmpfs_extra_stuff[i] = link_dir;
- i++;
- }
-
- return true;
-}
-
-static bool remove_absolute_path_dirs(char **tmpfs_extra_stuff)
-{
- size_t i = 0;
-
- if (!tmpfs_extra_stuff)
- return true;
-
- while (tmpfs_extra_stuff[i]) {
- if (unlink(tmpfs_extra_stuff[i]) < 0) {
- l_error("Failed to remove symlink for %s: %s",
- tmpfs_extra_stuff[i], strerror(errno));
-
- return false;
- }
-
- i++;
- }
-
- return true;
-}
-
-#define CONSOLE_LN_DEFAULT "\x1B[0m"
-#define CONSOLE_LN_RED "\x1B[31m"
-#define CONSOLE_LN_GREEN "\x1B[32m"
-#define CONSOLE_LN_BLACK "\x1B[30m"
-#define CONSOLE_LN_YELLOW "\x1B[33m"
-#define CONSOLE_LN_RESET "\033[0m"
-
-#define CONSOLE_LN_BOLD "\x1b[1m"
-
-#define CONSOLE_BG_WHITE "\e[47m"
-#define CONSOLE_BG_DEFAULT "\e[0m"
-
-enum test_status {
- TEST_STATUS_STARTED,
- TEST_STATUS_PASSED,
- TEST_STATUS_FAILED,
- TEST_STATUS_TIMEDOUT,
-};
-
-static void print_test_status(char *test_name, enum test_status ts,
- double interval)
-{
- const char *clear_line = "\r";
- int int_len;
- char *color_str;
- char *status_str;
- char *interval_str;
- char *line_end = "";
-
- switch (ts) {
- case TEST_STATUS_STARTED:
- color_str = CONSOLE_LN_RESET;
- status_str = "STARTED ";
-
- if (strcmp(verbose_opt, "none"))
- line_end = "\n";
-
- break;
- case TEST_STATUS_PASSED:
- printf("%s", clear_line);
- color_str = CONSOLE_LN_GREEN;
- status_str = "PASSED ";
- line_end = "\n";
-
- break;
- case TEST_STATUS_FAILED:
- printf("%s", clear_line);
- color_str = CONSOLE_LN_RED;
- status_str = "FAILED ";
- line_end = "\n";
-
- break;
- case TEST_STATUS_TIMEDOUT:
- printf("%s", clear_line);
- color_str = CONSOLE_LN_YELLOW;
- status_str = "TIMED OUT ";
- line_end = "\n";
-
- break;
- }
-
- if (interval > 0)
- int_len = snprintf(NULL, 0, "%.3f", interval);
- else
- int_len = 3;
-
- int_len++;
-
- interval_str = l_malloc(int_len);
- memset(interval_str, ' ', int_len);
- interval_str[int_len - 1] = '\0';
-
- if (interval > 0)
- sprintf(interval_str, "%.3f sec", interval);
- else
- sprintf(interval_str, "%s", "...");
-
- printf("%s%s%s%-60s%7s%s", color_str, status_str, CONSOLE_LN_RESET,
- test_name, interval_str, line_end);
-
- fflush(stdout);
-
- l_free(interval_str);
-}
-
-static void test_timeout_timer_tick(struct l_timeout *timeout, void *user_data)
-{
- pid_t *test_exec_pid = (pid_t *) user_data;
-
- kill_process(*test_exec_pid);
-
- l_main_quit();
-}
-
-static void test_timeout_signal_handler(uint32_t signo, void *user_data)
-{
- switch (signo) {
- case SIGINT:
- case SIGTERM:
- l_main_quit();
- break;
- }
-}
-
-static pid_t start_execution_timeout_timer(unsigned int max_exec_interval_sec,
- pid_t *test_exec_pid)
-{
- struct l_timeout *test_exec_timeout;
- pid_t test_timer_pid;
-
- test_timer_pid = fork();
- if (test_timer_pid < 0) {
- l_error("Failed to fork new process");
- return -1;
- }
-
- if (test_timer_pid == 0) {
- if (!l_main_init())
- exit(EXIT_FAILURE);
-
- test_exec_timeout =
- l_timeout_create(max_exec_interval_sec,
- test_timeout_timer_tick,
- test_exec_pid,
- NULL);
-
- l_main_run_with_signal(test_timeout_signal_handler, NULL);
-
- l_timeout_remove(test_exec_timeout);
-
- l_main_exit();
-
- exit(EXIT_SUCCESS);
- }
-
- return test_timer_pid;
-}
-
-struct test_stats {
- char *config_cycle_name;
- unsigned int num_passed;
- unsigned int num_failed;
- unsigned int num_timedout;
- double py_run_time;
-};
-
-static void run_py_tests(struct l_settings *hw_settings,
- struct l_queue *test_queue,
- struct l_queue *test_stats_queue,
- const char *test_name)
-{
- char *argv[3];
- pid_t test_exec_pid, test_timer_pid = -1;
- struct timeval time_before, time_after, time_elapsed;
- unsigned int max_exec_interval;
- char *py_test = NULL;
- struct test_stats *test_stats;
- pid_t monitor_pid = -1;
-
- if (!l_settings_get_uint(hw_settings, HW_CONFIG_GROUP_SETUP,
- HW_CONFIG_SETUP_MAX_EXEC_SEC,
- &max_exec_interval))
- max_exec_interval = TEST_MAX_EXEC_TIME_SEC;
-
- l_info(CONSOLE_LN_BOLD "%-10s%-60s%s" CONSOLE_LN_RESET, "Status",
- "Test", "Duration");
-
-start_next_test:
-
- if (l_queue_isempty(test_queue))
- return;
-
- py_test = (char *) l_queue_pop_head(test_queue);
- if (!py_test)
- return;
-
- if (log) {
- char *test_path;
- char *ext;
- char *full_path;
-
- test_path = l_strdup_printf("%s/%s", test_name, py_test);
- ext = strchr(test_path, '.');
- ext[0] = '\0';
-
- full_path = l_strdup_printf("%s/%s", log_dir, test_path);
-
- mkdir(full_path, 0755);
- if (chown(full_path, log_uid, log_gid) < 0)
- l_error("chown failed %s", full_path);
-
- l_free(full_path);
-
- monitor_pid = start_monitor(test_path);
-
- l_free(test_path);
- }
-
- argv[0] = "python3";
- argv[1] = py_test;
- argv[2] = NULL;
-
- print_test_status(py_test, TEST_STATUS_STARTED, 0);
- test_exec_pid = execute_program(argv, environ, false, test_name);
-
- gettimeofday(&time_before, NULL);
-
- if (!strcmp(gdb_opt, "none"))
- test_timer_pid = start_execution_timeout_timer(
- max_exec_interval, &test_exec_pid);
-
- test_stats = (struct test_stats *) l_queue_peek_tail(test_stats_queue);
-
- while (true) {
- pid_t corpse;
- int status;
- double interval;
-
- corpse = waitpid(WAIT_ANY, &status, 0);
-
- if (corpse < 0 || corpse == 0)
- continue;
-
- if (test_exec_pid == corpse) {
- gettimeofday(&time_after, NULL);
-
- if (test_timer_pid != -1)
- kill_process(test_timer_pid);
-
- timersub(&time_after, &time_before, &time_elapsed);
- interval = time_elapsed.tv_sec +
- 1e-6 * time_elapsed.tv_usec;
-
- if (WIFEXITED(status) &&
- WEXITSTATUS(status) == EXIT_SUCCESS) {
- print_test_status(py_test, TEST_STATUS_PASSED,
- interval);
- test_stats->num_passed++;
- } else if (WIFSIGNALED(status)) {
- print_test_status(py_test, TEST_STATUS_TIMEDOUT,
- interval);
- test_stats->num_timedout++;
- } else {
- print_test_status(py_test, TEST_STATUS_FAILED,
- interval);
- test_stats->num_failed++;
- }
-
- test_stats->py_run_time += interval;
-
- break;
- } else if (WIFSTOPPED(status))
- l_info("Process %d stopped with signal %d", corpse,
- WSTOPSIG(status));
- else if (WIFCONTINUED(status))
- l_info("Process %d continued", corpse);
- }
-
- l_free(py_test);
- py_test = NULL;
-
- if (monitor_pid != -1) {
- kill_process(monitor_pid);
- monitor_pid = -1;
- }
-
- goto start_next_test;
-}
-
-static void set_config_cycle_info(const char *config_dir_path,
- struct l_queue *test_stats_queue)
-{
- char sep_line[80];
- char *config_name_ptr;
- struct test_stats *test_stats;
-
- memset(sep_line, '_', sizeof(sep_line) - 1);
- sep_line[sizeof(sep_line) - 1] = '\0';
-
- config_name_ptr = strrchr(config_dir_path, '/');
- config_name_ptr++;
-
- l_info("%s", sep_line);
- l_info(CONSOLE_LN_BOLD "Starting configuration cycle No: %d [%s]"
- CONSOLE_LN_RESET, l_queue_length(test_stats_queue) + 1,
- config_name_ptr);
-
- test_stats = l_new(struct test_stats, 1);
- test_stats->config_cycle_name = strdup(config_name_ptr);
-
- l_queue_push_tail(test_stats_queue, test_stats);
-}
-
-static void set_wiphy_list(struct l_queue *wiphy_list)
-{
- const struct l_queue_entry *wiphy_entry;
- int size = 32;
- char *var;
-
- for (wiphy_entry = l_queue_get_entries(wiphy_list);
- wiphy_entry; wiphy_entry = wiphy_entry->next) {
- struct wiphy *wiphy = wiphy_entry->data;
-
- size += 32 + strlen(wiphy->name);
- if (wiphy->used_by_hostapd) {
- size += 32 + strlen(wiphy->interface_name) +
- strlen(wiphy->hostapd_ctrl_interface) +
- strlen(wiphy->hostapd_config);
- }
- }
-
- var = alloca(size);
- size = 0;
-
- for (wiphy_entry = l_queue_get_entries(wiphy_list);
- wiphy_entry; wiphy_entry = wiphy_entry->next) {
- struct wiphy *wiphy = wiphy_entry->data;
-
- if (size)
- var[size++] = '\n';
-
- size += sprintf(var + size, "%s=", wiphy->name);
-
- if (wiphy->used_by_hostapd)
- size += sprintf(var + size,
- "hostapd,name=%s,ctrl_interface=%s,"
- "config=%s",
- wiphy->interface_name,
- wiphy->hostapd_ctrl_interface,
- wiphy->hostapd_config);
- else
- size += sprintf(var + size, "iwd");
- }
-
- var[size++] = '\0';
-
- setenv("TEST_WIPHY_LIST", var, true);
-}
-
-static void set_reg_domain(const char *domain)
-{
- char *argv[5];
-
- argv[0] = "iw";
- argv[1] = "reg";
- argv[2] = "set";
- argv[3] = (char *) domain;
- argv[4] = NULL;
-
- execute_program(argv, environ, false, NULL);
-}
-
-static void wiphy_up(void *data, void *user_data)
-{
- struct wiphy *wiphy = data;
-
- set_interface_state(wiphy->interface_name, true);
-}
-
-static void wiphy_reset(void *data, void *user_data)
-{
- struct wiphy *wiphy = data;
-
- wiphy->used_by_hostapd = false;
-
- l_free(wiphy->hostapd_config);
- wiphy->hostapd_config = NULL;
- l_free(wiphy->hostapd_ctrl_interface);
- wiphy->hostapd_ctrl_interface = NULL;
-}
-
-static void create_network_and_run_tests(void *data, void *user_data)
-{
- pid_t hostapd_pids[HWSIM_RADIOS_MAX];
- pid_t iwd_pid = -1;
- pid_t medium_pid = -1;
- pid_t ofono_pid = -1;
- pid_t phonesim_pid = -1;
- char *config_dir_path;
- char *iwd_config_dir;
- char **tmpfs_extra_stuff = NULL;
- struct l_settings *hw_settings;
- struct l_queue *test_queue;
- struct l_queue *test_stats_queue;
- bool start_iwd_daemon = true;
- bool needs_hwsim = false;
- bool ofono_req = false;
- const char *sim_keys;
- const char *iwd_ext_options = NULL;
- const char *reg_domain;
- int phys_used;
- int num_radios;
- struct test_entry *entry = data;
- char *test_name = NULL;
-
- memset(hostapd_pids, -1, sizeof(hostapd_pids));
-
- config_dir_path = (char *) entry->path;
- test_queue = (struct l_queue *) entry->test_queue;
- test_stats_queue = (struct l_queue *) user_data;
-
- if (l_queue_isempty(test_queue)) {
- l_error("No Python IWD tests have been found in %s",
- config_dir_path);
- return;
- }
-
- set_config_cycle_info(config_dir_path, test_stats_queue);
-
- hw_settings = read_hw_config(config_dir_path);
- if (!hw_settings)
- return;
-
- l_info("Configuring network...");
-
- if (log) {
- char *log_path;
-
- test_name = basename(config_dir_path);
- log_path = l_strdup_printf("%s/%s", log_dir, test_name);
-
- mkdir(log_path, 0755);
- if (chown(log_path, log_uid, log_gid) < 0)
- l_error("chown failed");
-
- l_free(log_path);
- }
-
- if (chdir(config_dir_path) < 0) {
- l_error("Failed to change to test directory: %s",
- strerror(errno));
- goto free_hw_settings;
- }
-
- tmpfs_extra_stuff =
- l_settings_get_string_list(hw_settings, HW_CONFIG_GROUP_SETUP,
- HW_CONFIG_SETUP_TMPFS_EXTRAS,
- ':');
-
- sim_keys = l_settings_get_value(hw_settings, HW_CONFIG_GROUP_SETUP,
- "sim_keys");
-
- if (sim_keys) {
- if (!strcmp(sim_keys, "ofono")) {
- bool ofono_found = false;
- bool phonesim_found = false;
-
- if (!system("which ofonod > /dev/null 2>&1"))
- ofono_found = true;
-
- if (!system("which phonesim > /dev/null 2>&1"))
- phonesim_found = true;
-
- if (!ofono_found || !phonesim_found) {
- l_info("ofono or phonesim not found, skipping");
- goto free_tmpfs_extra;
- }
-
- ofono_req = true;
- iwd_ext_options = "--plugin=ofono";
- } else {
- setenv("IWD_SIM_KEYS", sim_keys, true);
- iwd_ext_options = "--plugin=sim_hardcoded";
- }
- }
-
- /* turn on/off timeouts if GDB is being used */
- if (!strcmp(gdb_opt, "none"))
- setenv("IWD_TEST_TIMEOUTS", "on", true);
- else
- setenv("IWD_TEST_TIMEOUTS", "off", true);
-
- if (!create_tmpfs_extra_stuff(tmpfs_extra_stuff))
- goto remove_abs_paths;
-
- l_settings_get_int(hw_settings, HW_CONFIG_GROUP_SETUP,
- HW_CONFIG_SETUP_NUM_RADIOS,
- &num_radios);
-
- if (!native_hw) {
- reg_domain = l_settings_get_value(hw_settings,
- HW_CONFIG_GROUP_SETUP,
- HW_CONFIG_SETUP_REG_DOMAIN);
- if (reg_domain)
- set_reg_domain(reg_domain);
-
- wiphy_list = l_queue_new();
-
- if (!configure_hw_radios(hw_settings, wiphy_list))
- goto remove_abs_paths;
-
- medium_pid = register_hwsim_as_trans_medium();
- if (medium_pid < 0)
- goto remove_abs_paths;
-
- if (check_verbosity("hwsim")) {
- list_hwsim_radios();
- list_interfaces();
- }
- } else {
- int len;
-
- l_settings_get_bool(hw_settings, HW_CONFIG_GROUP_SETUP,
- HW_CONFIG_SETUP_NEEDS_HWSIM, &needs_hwsim);
-
- /* Skip test that require hwsim dbus APIs (hwsim not running) */
- if (needs_hwsim) {
- l_error("test requires hwsim, skipping");
- goto remove_abs_paths;
- }
-
- len = l_queue_length(wiphy_list);
-
- /* Skip tests that need more radios than we have */
- if (num_radios > len) {
- l_error("test requires %d radios, only %d found",
- num_radios, len);
- goto remove_abs_paths;
- }
-
- l_queue_foreach(wiphy_list, wiphy_up, NULL);
- }
-
- if (check_verbosity("tls"))
- setenv("IWD_TLS_DEBUG", "on", true);
-
- if (!configure_hostapd_instances(hw_settings, config_dir_path,
- wiphy_list, hostapd_pids,
- &phys_used))
- goto exit_hostapd;
-
- l_settings_get_bool(hw_settings, HW_CONFIG_GROUP_SETUP,
- HW_CONFIG_SETUP_START_IWD, &start_iwd_daemon);
-
- if (start_iwd_daemon) {
- /*
- * In native mode we may have more radios than a test actually
- * needs. This would result in IWD managing all phys that
- * hostapd wasn't using, which could throw off test results.
- * By passing the number of phys the test expects IWD to have
- * we can leave the remaining (unneeded) phys unmanaged.
- */
- int iwd_phys = num_radios - phys_used;
-
- iwd_config_dir =
- l_settings_get_string(hw_settings,
- HW_CONFIG_GROUP_SETUP,
- HW_CONFIG_SETUP_IWD_CONF_DIR);
- if (!iwd_config_dir)
- iwd_config_dir = "/tmp";
-
- iwd_pid = start_iwd(iwd_config_dir, wiphy_list,
- iwd_ext_options, iwd_phys, test_name);
-
- if (iwd_pid == -1)
- goto exit_hostapd;
- } else {
- /* tells pytest to start iwd with valgrind */
- if (valgrind)
- setenv("IWD_TEST_VALGRIND", "on", true);
- }
-
- if (ofono_req) {
- phonesim_pid = start_phonesim(test_name);
- ofono_pid = start_ofono(test_name);
- }
-
- set_wiphy_list(wiphy_list);
-
- if (!shell)
- run_py_tests(hw_settings, test_queue, test_stats_queue,
- test_name);
- else {
- if (system("/bin/sh"))
- l_info("executing /bin/sh failed");
- }
-
- l_info("Destructing network...");
-
- /* Script has responsibility to cleanup any iwd instances it started */
- if (iwd_pid > 0)
- terminate_iwd(iwd_pid);
-
- /* /tmp/valgrind.log will only exist without logging turned on */
- if (valgrind && !log) {
- if (system("cat /tmp/valgrind.log"))
- l_info("cat /tmp/valgrind.log failed");
-
- if (system("echo \"\" > /tmp/valgrind.log"))
- l_info("Failed to reset /tmp/valgrind.log");
- }
-
- if (log) {
- L_AUTO_FREE_VAR(char *, dmesg);
- L_AUTO_FREE_VAR(char *, kernel_log);
-
- kernel_log = l_strdup_printf("%s/kernel.log", log_dir);
- dmesg = l_strdup_printf("dmesg > %s", kernel_log);
-
- if (system(dmesg))
- l_error("dmesg failed");
- if (chown(kernel_log, log_uid, log_gid))
- l_error("chown failed");
- }
-
- if (ofono_req) {
- loopback_started = false;
- stop_ofono(ofono_pid);
- stop_phonesim(phonesim_pid);
- }
-
-exit_hostapd:
- destroy_hostapd_instances(hostapd_pids);
-
- if (!native_hw)
- terminate_medium(medium_pid);
-
-remove_abs_paths:
- remove_absolute_path_dirs(tmpfs_extra_stuff);
-
- /*
- * If running in hwsim mode, we want to completely free/destroy the
- * wiphy list since it will be re-populated on the next test. For the
- * native case we want to reset the list as if it was freshly
- * discovered. This ensures that all the hostapd flags get reset.
- */
- if (!native_hw)
- l_queue_destroy(wiphy_list, wiphy_free);
- else
- l_queue_foreach(wiphy_list, wiphy_reset, NULL);
-
-free_tmpfs_extra:
- l_strfreev(tmpfs_extra_stuff);
-free_hw_settings:
- l_settings_free(hw_settings);
-}
-
-struct stat_totals {
- unsigned int total_passed;
- unsigned int total_failed;
- unsigned int total_timedout;
- double total_duration;
-};
-
-static void print_test_stat(void *data, void *user_data)
-{
- struct test_stats *test_stats;
- struct stat_totals *stat_totals;
- char *str_runtime, *str_passed, *str_failed, *str_timedout;
-
- test_stats = (struct test_stats *) data;
- stat_totals = (struct stat_totals *) user_data;
-
- stat_totals->total_duration += test_stats->py_run_time;
- stat_totals->total_passed += test_stats->num_passed;
- stat_totals->total_failed += test_stats->num_failed;
- stat_totals->total_timedout += test_stats->num_timedout;
-
- if (test_stats->py_run_time)
- str_runtime = l_strdup_printf("| %9.3f sec",
- test_stats->py_run_time);
- else
- str_runtime = l_strdup_printf("| %9s", "Skipped");
-
- if (test_stats->num_passed)
- str_passed = l_strdup_printf(" %6d ", test_stats->num_passed);
- else
- str_passed = l_strdup_printf(" %6c ", '-');
-
- if (test_stats->num_failed)
- str_failed = l_strdup_printf(" %6d ", test_stats->num_failed);
- else
- str_failed = l_strdup_printf(" %6c ", '-');
-
- if (test_stats->num_timedout)
- str_timedout = l_strdup_printf(" %9d ",
- test_stats->num_timedout);
- else
- str_timedout = l_strdup_printf(" %9c ", '-');
-
- l_info(CONSOLE_LN_BOLD "%27s "
- CONSOLE_LN_DEFAULT "|" CONSOLE_LN_GREEN "%s"
- CONSOLE_LN_DEFAULT "|" CONSOLE_LN_RED "%s"
- CONSOLE_LN_DEFAULT "|" CONSOLE_LN_YELLOW "%s"
- CONSOLE_LN_RESET "%s", test_stats->config_cycle_name,
- str_passed, str_failed, str_timedout, str_runtime);
-
- l_free(str_passed);
- l_free(str_failed);
- l_free(str_timedout);
- l_free(str_runtime);
-}
-
-static void print_results(struct l_queue *test_stat_queue)
-{
- struct stat_totals stat_totals = { 0, 0, 0, 0 };
- char sep_line[80];
-
- memset(sep_line, '_', sizeof(sep_line) - 1);
- sep_line[sizeof(sep_line) - 1] = '\0';
-
- l_info("%s\n" CONSOLE_LN_RESET, sep_line);
- l_info("%27s " CONSOLE_LN_DEFAULT "|" CONSOLE_LN_GREEN " %s "
- CONSOLE_LN_DEFAULT "|" CONSOLE_LN_RED " %5s "
- CONSOLE_LN_DEFAULT "|" CONSOLE_LN_YELLOW " %9s "
- CONSOLE_LN_RESET "| Duration",
- "Configuration cycle", "PASSED", "FAILED", "TIMED OUT");
-
- memset(sep_line, '-', sizeof(sep_line) - 1);
- sep_line[sizeof(sep_line) - 1] = '\0';
- l_info("%s" CONSOLE_LN_RESET, sep_line);
-
- l_queue_foreach(test_stat_queue, print_test_stat, &stat_totals);
-
- l_info("%s" CONSOLE_LN_RESET, sep_line);
- l_info("%27s "
- CONSOLE_LN_DEFAULT "|" CONSOLE_LN_GREEN " %6d "
- CONSOLE_LN_DEFAULT "|" CONSOLE_LN_RED " %6d "
- CONSOLE_LN_DEFAULT "|" CONSOLE_LN_YELLOW " %9d "
- CONSOLE_LN_RESET "| %9.3f sec",
- "Total", stat_totals.total_passed, stat_totals.total_failed,
- stat_totals.total_timedout, stat_totals.total_duration);
-
- memset(sep_line, '_', sizeof(sep_line) - 1);
- sep_line[sizeof(sep_line) - 1] = '\0';
- l_info("%s" CONSOLE_LN_RESET, sep_line);
-}
-
-static void test_stat_queue_entry_destroy(void *data)
-{
- struct test_stats *ts;
-
- ts = (struct test_stats *) data;
-
- l_free(ts->config_cycle_name);
- l_free(ts);
-}
-
-static void free_test_entry(void *data)
-{
- struct test_entry *entry = data;
-
- l_free(entry->path);
- l_free(entry);
-}
-
-static void run_auto_tests(void)
-{
- L_AUTO_FREE_VAR(char*, test_home_path) = NULL;
- L_AUTO_FREE_VAR(char*, env_path) = NULL;
- int i;
- struct l_queue *test_config_queue;
- struct l_queue *test_stat_queue;
- char **test_config_dirs;
-
- if (log) {
- if (mount("logdir", log_dir, "9p", 0,
- "trans=virtio,version=9p2000.L") < 0) {
- l_error("Mounting %s failed", log_dir);
- return;
- }
- }
-
- env_path = l_strdup_printf("%s/src:%s/tools:%s", top_level_path,
- top_level_path, getenv("PATH"));
-
- setenv("PATH", env_path, true);
-
- test_home_path = l_strdup_printf("%s/%s", top_level_path,
- TEST_TOP_DIR_DEFAULT_NAME);
-
- if (!path_exist(test_home_path)) {
- l_error("Test directory %s does not exist", test_home_path);
- return;
- }
-
- test_config_queue = l_queue_new();
- if (!test_config_queue)
- return;
-
- test_config_dirs = l_strsplit(test_action_params, ',');
-
- if (test_config_dirs[0]) {
- i = 0;
-
- while (test_config_dirs[i]) {
- if (strchr(test_config_dirs[i], '/')) {
- if (!find_test_configuration(
- test_config_dirs[i], 1,
- test_config_queue))
- goto exit;
- } else {
- char *config_dir_path;
-
- config_dir_path =
- l_strdup_printf("%s/%s", test_home_path,
- test_config_dirs[i]);
-
- if (!find_test_configuration(config_dir_path, 1,
- test_config_queue)) {
- l_free(config_dir_path);
-
- goto exit;
- }
-
- l_free(config_dir_path);
- }
-
- i++;
- }
- } else {
- /*
- * --shell without any specific tests implies 'shell' test
- */
- if (shell) {
- char *config_dir_path;
- config_dir_path = l_strdup_printf("%s/shell",
- test_home_path);
-
- if (!find_test_configuration(config_dir_path, 1,
- test_config_queue)) {
- l_free(config_dir_path);
- goto exit;
- }
-
- l_free(config_dir_path);
- } else {
- l_info("Automatic test execution requested");
- l_info("Searching for the test configurations...");
-
- if (!find_test_configuration(test_home_path, 0,
- test_config_queue))
- goto exit;
- }
- }
-
- if (l_queue_isempty(test_config_queue)) {
- l_error("No test configuration discovered");
- goto exit;
- }
-
- create_dbus_system_conf();
-
- if (!start_dbus_daemon())
- goto exit;
-
- if (!start_haveged()) {
- l_error("Failed to start haveged");
- goto exit;
- }
-
- test_stat_queue = l_queue_new();
-
- l_queue_foreach(test_config_queue, create_network_and_run_tests,
- test_stat_queue);
-
- print_results(test_stat_queue);
-
- l_queue_destroy(test_stat_queue, test_stat_queue_entry_destroy);
-
-exit:
- l_strfreev(verbose_apps);
- l_strfreev(test_config_dirs);
- l_queue_destroy(test_config_queue, free_test_entry);
-}
-
-static void run_unit_tests(void)
-{
- DIR *d;
- struct dirent *dirent;
- char *argv[2];
- char *unit_test_abs_path = NULL;
- char **unit_tests = NULL;
-
- if (strcmp(test_action_params, "")) {
- unit_tests = l_strsplit(test_action_params, ',');
-
- if (!unit_tests || !unit_tests[0])
- goto exit;
- }
-
- if (chdir(top_level_path) < 0)
- goto exit;
-
- d = opendir("unit/");
- if (!d)
- goto exit;
-
- while ((dirent = readdir(d)) != NULL) {
- struct stat st;
-
- if (dirent->d_type != DT_REG)
- continue;
-
- unit_test_abs_path = l_strdup_printf("%s%s%s", top_level_path,
- "/unit/", dirent->d_name);
-
- if (stat(unit_test_abs_path, &st) < 0)
- goto next;
-
- if (!(st.st_mode & S_IEXEC))
- goto next;
-
- if (unit_tests) {
- if (!l_strv_contains(unit_tests, dirent->d_name))
- goto next;
- }
-
- argv[0] = unit_test_abs_path;
- argv[1] = NULL;
-
- l_info("\n---------- Unit %s ----------", dirent->d_name);
- execute_program(argv, environ, true, NULL);
-
-next:
- l_free(unit_test_abs_path);
- }
-
- closedir(d);
-
-exit:
- l_strfreev(unit_tests);
-}
-
-static bool wiphy_match(const void *a, const void *b)
-{
- const struct wiphy *wiphy = a;
- int id = L_PTR_TO_INT(b);
-
- return (wiphy->id == id);
-}
-
-static struct wiphy *wiphy_find(int wiphy_id)
-{
- return l_queue_find(wiphy_list, wiphy_match, L_INT_TO_PTR(wiphy_id));
-}
-
-static void parse_supported_iftypes(uint16_t *iftypes,
- struct l_genl_attr *attr)
-{
- uint16_t type, len;
- const void *data;
-
- while (l_genl_attr_next(attr, &type, &len, &data)) {
- /*
- * NL80211_IFTYPE_UNSPECIFIED can be ignored, so we start
- * at the first bit
- */
- if (type > sizeof(uint16_t) * 8) {
- l_warn("unsupported iftype: %u", type);
- continue;
- }
-
- *iftypes |= 1 << (type - 1);
- }
-}
-
-static void wiphy_dump_callback(struct l_genl_msg *msg, void *user_data)
-{
- struct wiphy *wiphy;
- struct l_genl_attr attr;
- struct l_genl_attr nested;
- uint32_t id = UINT32_MAX;
- uint16_t type, len;
- const void *data;
- const char *name = NULL;
- uint32_t name_len = 0;
- uint16_t iftypes = 0;
-
- if (!l_genl_attr_init(&attr, msg))
- return;
-
- while (l_genl_attr_next(&attr, &type, &len, &data)) {
- switch (type) {
- case NL80211_ATTR_WIPHY:
- if (len != sizeof(uint32_t))
- return;
-
- id = *((uint32_t *) data);
-
- if (wiphy_find(id))
- return;
-
- break;
- case NL80211_ATTR_WIPHY_NAME:
- if (len > sizeof(((struct wiphy *) 0)->name))
- return;
-
- name = data;
- name_len = len;
-
- break;
- case NL80211_ATTR_SUPPORTED_IFTYPES:
- if (l_genl_attr_recurse(&attr, &nested))
- parse_supported_iftypes(&iftypes, &nested);
-
- break;
- }
- }
-
- if (id == UINT32_MAX || !name)
- return;
-
- wiphy = l_new(struct wiphy, 1);
- strncpy(wiphy->name, name, name_len);
- wiphy->id = id;
- wiphy->can_ap = iftypes & (1 << NL80211_IFTYPE_AP);
-
- l_queue_push_tail(wiphy_list, wiphy);
-}
-
-static void iface_dump_callback(struct l_genl_msg *msg, void *user_data)
-{
- struct l_genl_attr attr;
- uint16_t type, len;
- const void *data;
- const char *ifname = NULL;
- struct wiphy *wiphy = NULL;
-
- if (!l_genl_attr_init(&attr, msg))
- return;
-
- while (l_genl_attr_next(&attr, &type, &len, &data)) {
- switch (type) {
-
- case NL80211_ATTR_IFNAME:
- if (len > 16) {
- l_warn("Invalid interface name attribute");
- return;
- }
-
- ifname = data;
- break;
-
- case NL80211_ATTR_WIPHY:
- if (len != sizeof(uint32_t)) {
- l_warn("Invalid wiphy attribute");
- return;
- }
-
- wiphy = wiphy_find(*((uint32_t *) data));
- break;
- }
- }
-
- if (!ifname || !wiphy)
- return;
-
- wiphy->interface_name = l_strdup(ifname);
- wiphy->interface_created = false;
-
- l_info("Discovered interface %s", wiphy->interface_name);
-}
-
-struct nl_data {
- struct l_genl *genl;
- struct l_genl_family *nl80211;
-};
-
-static void iface_dump_done(void *user_data)
-{
- struct nl_data *data = user_data;
-
- l_debug("Interface discovery complete, running tests");
-
- list_interfaces();
-
- run_auto_tests();
-
- l_queue_destroy(wiphy_list, wiphy_free);
-
- l_genl_family_free(data->nl80211);
- l_genl_unref(data->genl);
- l_free(data);
-
- l_main_quit();
-}
-
-static void wiphy_dump_done(void *user_data)
-{
- struct nl_data *data = user_data;
- struct l_genl_msg *msg;
-
- l_debug("Wiphy discovery complete, discovering interfaces");
-
- msg = l_genl_msg_new(NL80211_CMD_GET_INTERFACE);
- if (!l_genl_family_dump(data->nl80211, msg, iface_dump_callback,
- data, iface_dump_done))
- l_error("Getting all interface information failed");
-}
-
-static void nl80211_requested(const struct l_genl_family_info *info,
- void *user_data)
-{
- struct nl_data *data = user_data;
- struct l_genl_msg *msg;
-
- if (info == NULL) {
- l_info("No nl80211 family found");
- goto done;
- }
-
- l_debug("Found nl80211 interface");
-
- data->nl80211 = l_genl_family_new(data->genl, NL80211_GENL_NAME);
- wiphy_list = l_queue_new();
-
- msg = l_genl_msg_new(NL80211_CMD_GET_WIPHY);
- if (!l_genl_family_dump(data->nl80211, msg, wiphy_dump_callback,
- data, wiphy_dump_done))
- l_error("Getting all wiphy devices failed");
-
- return;
-done:
- l_main_quit();
-}
-
-static void start_hw_discovery(void)
-{
- struct nl_data *data = l_new(struct nl_data, 1);
-
- data->genl = l_genl_new();
- l_genl_request_family(data->genl, NL80211_GENL_NAME,
- nl80211_requested, data, NULL);
- /*
- * This is somewhat of a mystery, but it appears that
- * calling lshw causes the OS to re-enumerate the USB
- * bus. Without this no USB adapters are found when
- * doing the wiphy/iface dump from nl80211.
- *
- * This also conveniently prints all the network
- * adapters and their iface name, so its much easier
- * to know which adapter are being used by iwd/hostapd
- * after the test.
- */
- if (system("lshw -C network"))
- l_info("lshw failed");
-
- l_main_run();
-}
-
-static void run_tests(void)
-{
- char cmdline[CMDLINE_MAX], *ptr, *cmds;
- char *test_action_str;
- FILE *fp;
- int i;
-
- fp = fopen("/proc/cmdline", "re");
-
- if (!fp) {
- l_error("Failed to open kernel command line");
- return;
- }
-
- ptr = fgets(cmdline, sizeof(cmdline), fp);
- fclose(fp);
-
- if (!ptr) {
- l_error("Failed to read kernel command line");
- return;
- }
-
- ptr = strstr(cmdline, "LOG_GID=");
- if (ptr) {
- *ptr = '\0';
- test_action_str = ptr + 9;
- ptr = strchr(test_action_str, '\'');
- *ptr = '\0';
- log_gid = atoi(test_action_str);
- }
-
- ptr = strstr(cmdline, "LOG_UID=");
- if (ptr) {
- *ptr = '\0';
- test_action_str = ptr + 9;
- ptr = strchr(test_action_str, '\'');
- *ptr = '\0';
- log_uid = atoi(test_action_str);
- }
-
- ptr = strstr(cmdline, "LOG_PATH=");
- if (ptr) {
- *ptr = '\0';
- test_action_str = ptr + 10;
-
- ptr = strchr(test_action_str, '\'');
- *ptr = '\0';
-
- if (strcmp(test_action_str, "none")) {
- log = true;
- strcpy(log_dir, test_action_str);
- }
- }
-
- ptr = strstr(cmdline, "SHELL=");
- if (ptr) {
- *ptr = '\0';
- test_action_str = ptr + 6;
-
- shell = atoi(test_action_str);
- }
-
- ptr = strstr(cmdline, "HW=");
- if (ptr) {
- *ptr = '\0';
- test_action_str = ptr + 4;
-
- ptr = strchr(test_action_str, '\'');
- if (ptr)
- *ptr = '\0';
-
- if (!strcmp(test_action_str, "virtual"))
- native_hw = false;
- else
- native_hw = true;
- }
-
- ptr = strstr(cmdline, "GDB=");
- if (ptr) {
- *ptr = '\0';
- test_action_str = ptr + 5;
-
- ptr = strchr(test_action_str, '\'');
- *ptr = '\0';
- gdb_opt = l_strdup(test_action_str);
- }
-
- ptr = strstr(cmdline, "VALGRIND=");
- if (ptr) {
- char *end;
- unsigned long v;
-
- *ptr = '\0';
- test_action_str = ptr + 9;
- v = strtoul(test_action_str, &end, 10);
- if ((v != 0 && v != 1) || end != test_action_str + 1) {
- l_error("malformed valgrind option");
- return;
- }
-
- valgrind = (bool) v;
- }
-
- ptr = strstr(cmdline, "PATH=");
- if (!ptr) {
- l_error("No $PATH section found");
- return;
- }
-
- *ptr = '\0';
- test_action_str = ptr + 6;
- ptr = strchr(test_action_str, '\'');
- *ptr = '\0';
- l_info("%s", test_action_str);
- setenv("PATH", test_action_str, true);
-
- ptr = strstr(cmdline, "TESTARGS=");
-
- if (!ptr) {
- l_error("No test command section found");
- return;
- }
-
- cmds = ptr + 10;
- ptr = strchr(cmds, '\'');
-
- if (!ptr) {
- l_error("Malformed test command section");
- return;
- }
-
- *ptr = '\0';
-
- ptr = strstr(cmdline, "TEST_ACTION_PARAMS=");
-
- if (ptr) {
- test_action_params = ptr + 20;
- ptr = strchr(test_action_params, '\'');
-
- if (!ptr) {
- l_error("Malformed test action parameters section");
- return;
- }
-
- *ptr = '\0';
- }
-
- ptr = strstr(cmdline, "TEST_ACTION=");
-
- if (ptr) {
- test_action_str = ptr + 12;
- ptr = strchr(test_action_str, ' ');
-
- if (!ptr) {
- l_error("Malformed test action parameters section");
- return;
- }
-
- *ptr = '\0';
-
- test_action = (enum action) atoi(test_action_str);
- }
-
- ptr = strstr(cmdline, "DEBUG_FILTER=");
-
- if (ptr) {
- debug_filter = ptr + 14;
-
- ptr = strchr(debug_filter, '\'');
-
- if (!ptr) {
- l_error("Malformed debug filter section");
- return;
- }
-
- *ptr = '\0';
-
- if (debug_filter[0] != '\0') {
- enable_debug = true;
- l_debug_enable(debug_filter);
- setenv("HWSIM_DEBUG", "", true);
- }
- }
-
- ptr = strstr(cmdline, "TESTVERBOUT=");
-
- if (ptr) {
- verbose_opt = ptr + 13;
-
- ptr = strchr(verbose_opt, '\'');
- if (!ptr) {
- l_error("Malformed verbose parameter");
- return;
- }
-
- *ptr = '\0';
-
- l_info("Enable verbose output for %s", verbose_opt);
-
- verbose_apps = l_strsplit(verbose_opt, ',');
- }
-
- ptr = strstr(cmdline, "TESTHOME=");
-
- if (ptr) {
- exec_home = ptr + 4;
- ptr = strpbrk(exec_home + 9, " \r\n");
-
- if (ptr)
- *ptr = '\0';
- }
-
- ptr = strrchr(exec_home, '/');
-
- if (!ptr)
- exit(EXIT_FAILURE);
-
- i = ptr - exec_home;
-
- strncpy(top_level_path, exec_home + 5, i - 5);
- top_level_path[i - 5] = '\0';
-
- switch (test_action) {
- case ACTION_AUTO_TEST:
- if (native_hw)
- start_hw_discovery();
- else
- run_auto_tests();
- break;
- case ACTION_UNIT_TEST:
- run_unit_tests();
- break;
- }
-}
-
-static void usage(void)
-{
- l_info("test-runner - Automated test execution utility\n"
- "Usage:\n");
- l_info("\ttest-runner [options] [--] <command> [args]\n");
- l_info("Options:\n"
- "\t-q, --qemu <path> QEMU binary\n"
- "\t-k, --kernel <image> Kernel image (bzImage)\n"
- "\t-v, --verbose <apps> Comma separated list of "
- "applications to enable\n"
- "\t\t\t\tverbose output\n"
- "\t-h, --help Show help options\n"
- "\t-V, --valgrind Run valgrind on iwd. Note: \"-v"
- " iwd\" is required\n"
- "\t\t\t\tto see valgrind"
- " output\n"
- "\t-g, --gdb <iwd|hostapd> Run gdb on the specified"
- " executable\n"
- "\t-w, --hw <config> Run using a physical hardware "
- "configuration\n"
- "\t-s, --shell Boot into shell. If -A is used the"
- " environment\n"
- "\t\t\t\twill be setup exactly as it is"
- " in the test,\n"
- "\t\t\t\tbut no test will be run. If no"
- " test is specified\n"
- "\t\t\t\tthe 'shell' test"
- " will be used\n"
- "\t-l, --log <dir> Directory used for log output. "
- "This option sets \n"
- "\t\t\t\t--verbose on all apps");
- l_info("Commands:\n"
- "\t-A, --auto-tests <dirs> Comma separated list of the "
- "test configuration\n\t\t\t\t"
- "directories to run\n"
- "\t-U, --unit-tests <tests> Comma separated list of the "
- "unit tests to run\n");
-}
-
-static const struct option main_options[] = {
- { "auto-tests", required_argument, NULL, 'A' },
- { "unit-tests", optional_argument, NULL, 'U' },
- { "qemu", required_argument, NULL, 'q' },
- { "kernel", required_argument, NULL, 'k' },
- { "verbose", required_argument, NULL, 'v' },
- { "debug", optional_argument, NULL, 'd' },
- { "gdb", required_argument, NULL, 'g' },
- { "valgrind", no_argument, NULL, 'V' },
- { "hw", required_argument, NULL, 'w' },
- { "shell", optional_argument, NULL, 's' },
- { "log", required_argument, NULL, 'l' },
- { "help", no_argument, NULL, 'h' },
- { }
-};
-
-int main(int argc, char *argv[])
-{
- uint8_t actions = 0;
- struct tm *timeinfo;
- time_t t;
- char *gid;
- char *uid;
-
- l_log_set_stderr();
-
- if (getpid() == 1 && getppid() == 0) {
- if (!l_main_init())
- return EXIT_FAILURE;
-
- prepare_sandbox();
-
- run_tests();
-
- sync();
- l_info("Done running tests. Rebooting...");
-
- reboot(RB_AUTOBOOT);
- return EXIT_SUCCESS;
- }
-
- for (;;) {
- int opt;
-
- opt = getopt_long(argc, argv, "A:q:k:v:g:sl:UVdh", main_options,
- NULL);
- if (opt < 0)
- break;
-
- switch (opt) {
- case 'A':
- test_action = ACTION_AUTO_TEST;
- test_action_params = optarg;
- actions++;
- break;
- case 'U':
- test_action = ACTION_UNIT_TEST;
- test_action_params = optarg;
- actions++;
- break;
- case 'q':
- qemu_binary = optarg;
- break;
- case 'k':
- kernel_image = optarg;
- break;
- case 'd':
- enable_debug = true;
-
- if (optarg)
- debug_filter = optarg;
- else
- debug_filter = "*";
-
- l_debug_enable(debug_filter);
- break;
- case 'v':
- verbose_opt = optarg;
- verbose_apps = l_strsplit(optarg, ',');
- break;
- case 'V':
- valgrind = true;
- break;
- case 'g':
- gdb_opt = optarg;
- if (!gdb_opt || (strcmp(gdb_opt, "iwd") &&
- strcmp(gdb_opt, "hostapd") &&
- strcmp(gdb_opt, "hwsim"))) {
- l_error("--gdb can only be used with iwd"
- ", hwsim or hostapd");
- return EXIT_FAILURE;
- }
- break;
- case 'w':
- hw_config = l_settings_new();
- if (!l_settings_load_from_file(hw_config, optarg)) {
- l_error("could not read hw config from %s",
- optarg);
- l_settings_free(hw_config);
- return EXIT_FAILURE;
- }
- break;
- case 's':
- shell = true;
- break;
- case 'l':
- /*
- * Setup the log directory. This is created under the
- * passed in log dir (--log) in the format:
- * <logdir>/run-<year>-<month>-<day>-<PID>
- *
- * The created log dir is then chown'ed to the user
- * who started test-runner, as are all files created
- * under this directory.
- */
- log = true;
-
- if (!optarg)
- optarg = ".";
-
- time(&t);
- timeinfo = localtime(&t);
-
- gid = getenv("SUDO_GID");
- uid = getenv("SUDO_UID");
-
- if (!gid || !uid) {
- log_gid = getgid();
- log_uid = getuid();
- } else {
- log_gid = strtol(gid, NULL, 10);
- log_uid = strtol(uid, NULL, 10);
- }
-
- snprintf(log_dir, sizeof(log_dir), "%s/run-%d-%d-%d-%d",
- optarg, timeinfo->tm_year + 1900,
- timeinfo->tm_mon + 1, timeinfo->tm_mday,
- getpid());
- mkdir(log_dir, 0755);
-
- if (chown(log_dir, log_uid, log_gid) < 0)
- l_error("failed to fchown %s", log_dir);
-
- break;
- case 'h':
- usage();
- return EXIT_SUCCESS;
- default:
- return EXIT_FAILURE;
- }
- }
-
- if (argc - optind > 0) {
- l_error("Invalid command line parameters");
- return EXIT_FAILURE;
- }
-
- if (actions > 1) {
- l_error("Only one action can be specified");
- return EXIT_FAILURE;
- }
-
- if (!actions)
- test_action = ACTION_AUTO_TEST;
-
- own_binary = argv[0];
- test_argv = argv + optind;
- test_argc = argc - optind;
-
- if (!qemu_binary) {
- qemu_binary = find_qemu();
- if (!qemu_binary) {
- l_error("No default QEMU binary found");
- return EXIT_FAILURE;
- }
- }
-
- if (!kernel_image) {
- kernel_image = find_kernel();
- if (!kernel_image) {
- l_error("No default kernel image found");
- return EXIT_FAILURE;
- }
- }
-
- l_info("Using QEMU binary %s", qemu_binary);
- l_info("Using kernel image %s", kernel_image);
-
- if (!start_qemu())
- return EXIT_FAILURE;
-
- return EXIT_SUCCESS;
-}
--
2.26.2
1 year, 8 months
[PATCH 0/6] AdHoc fixes
by James Prestwood
These should make AdHoc pass very reliably now. There is still
the problem of the failure test. Its not really testing anything
at this point since there is no way of knowing if EAPoL was
successful or not via DBus.
James Prestwood (6):
adhoc: start both eapol SM's
adhoc: print handshake failure reason
adhoc: delay setting setting Started
auto-t: make AdHoc APIs behave like others
auto-t: update AdHoc tests to use AdHocDevice
auto-t: remove old AdHoc APIs
autotests/testAdHoc/adhoc_test.py | 18 ++++++--
autotests/testAdHoc/open_test.py | 19 ++++++---
autotests/util/iwd.py | 71 +++++++------------------------
src/adhoc.c | 51 ++++++++++++++++++++--
4 files changed, 92 insertions(+), 67 deletions(-)
--
2.26.2
1 year, 8 months
[PATCH 1/4] station: print which BSS is being connected to
by James Prestwood
For multi-bss networks its nice to know which BSS is being connected
to. The ranking can hint at it, but blacklisting or network capabilities
could effect which network is actually chosen. An explicit debug print
makes debugging much easier.
---
src/station.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/station.c b/src/station.c
index a8d8ad08..7fb4ae77 100644
--- a/src/station.c
+++ b/src/station.c
@@ -2423,6 +2423,8 @@ int __station_connect_network(struct station *station, struct network *network,
return r;
}
+ l_debug("connecting to BSS "MAC, MAC_STR(bss->addr));
+
station->connected_bss = bss;
station->connected_network = network;
--
2.26.2
1 year, 8 months
[PATCH 1/5] eapol: IP Allocation KDE support
by Andrew Zaborowski
Support IP allocation during the 4-Way Handshake as defined in the P2P
spec. This is the supplicant side implementation.
The API requires the user to set hs->support_ip_allocation true before
eapol_start(). On HANDSHAKE_EVENT_COMPLETE, if this same flag is still
set, we've received the IP lease, the netmask and the authenticator's
IP from the authenticator and there's no need to start DHCP. If the
flag is cleared, the user needs to use DHCP.
---
I can split this into two flags if preferred.
---
src/eapol.c | 76 +++++++++++++++++++++++++++++++++++++++++++------
src/handshake.h | 9 +++++-
2 files changed, 76 insertions(+), 9 deletions(-)
diff --git a/src/eapol.c b/src/eapol.c
index 977f720b..acf07c41 100644
--- a/src/eapol.c
+++ b/src/eapol.c
@@ -1088,7 +1088,7 @@ static void eapol_handle_ptk_1_of_4(struct eapol_sm *sm,
const uint8_t *kck;
struct eapol_key *step2;
uint8_t mic[MIC_MAXLEN];
- uint8_t *ies;
+ uint8_t ies[512];
size_t ies_len;
const uint8_t *own_ie = sm->handshake->supplicant_ie;
const uint8_t *pmkid;
@@ -1199,8 +1199,6 @@ static void eapol_handle_ptk_1_of_4(struct eapol_sm *sm,
* Rebuild the RSNE to include the PMKR1Name and append
* MDE + FTE.
*/
- ies = alloca(512);
-
rsn_info.num_pmkids = 1;
rsn_info.pmkids = sm->handshake->pmk_r1_name;
@@ -1214,7 +1212,16 @@ static void eapol_handle_ptk_1_of_4(struct eapol_sm *sm,
ies_len += fte[1] + 2;
} else {
ies_len = own_ie[1] + 2;
- ies = (uint8_t *) own_ie;
+ memcpy(ies, own_ie, ies_len);
+ }
+
+ if (sm->handshake->support_ip_allocation) {
+ /* Wi-Fi P2P Technical Specification v1.7 Table 58 */
+ ies[ies_len++] = IE_TYPE_VENDOR_SPECIFIC;
+ ies[ies_len++] = 4 + 1;
+ l_put_be32(HANDSHAKE_KDE_IP_ADDRESS_REQ, ies + ies_len);
+ ies_len += 4;
+ ies[ies_len++] = 0x01;
}
step2 = eapol_create_ptk_2_of_4(sm->protocol_version,
@@ -1381,7 +1388,8 @@ static const uint8_t *eapol_find_rsne(const uint8_t *data, size_t data_len,
return first;
}
-static const uint8_t *eapol_find_osen(const uint8_t *data, size_t data_len)
+static const uint8_t *eapol_find_wfa_kde(const uint8_t *data, size_t data_len,
+ uint8_t oi_type)
{
struct ie_tlv_iter iter;
@@ -1389,7 +1397,7 @@ static const uint8_t *eapol_find_osen(const uint8_t *data, size_t data_len)
while (ie_tlv_iter_next(&iter)) {
if (ie_tlv_iter_get_tag(&iter) == IE_TYPE_VENDOR_SPECIFIC) {
- if (!is_ie_wfa_ie(iter.data, iter.len, IE_WFA_OI_OSEN))
+ if (!is_ie_wfa_ie(iter.data, iter.len, oi_type))
continue;
} else
continue;
@@ -1474,6 +1482,28 @@ static const uint8_t *eapol_find_wpa_ie(const uint8_t *data, size_t data_len)
return NULL;
}
+static bool eapol_check_ip_mask(const uint8_t *mask,
+ const uint8_t *ip1, const uint8_t *ip2)
+{
+ uint32_t mask_uint = l_get_be32(mask);
+ uint32_t ip1_uint = l_get_be32(ip1);
+ uint32_t ip2_uint = l_get_be32(ip2);
+
+ return
+ /* Check IPs are in the same subnet */
+ ((ip1_uint ^ ip2_uint) & mask_uint) == 0 &&
+ /* Check IPs are different */
+ ip1_uint != ip2_uint &&
+ /* Check IPs are not subnet addresses */
+ (ip1_uint & ~mask_uint) != 0 &&
+ (ip2_uint & ~mask_uint) != 0 &&
+ /* Check IPs are not broadcast addresses */
+ (ip1_uint | mask_uint) != 0xffffffff &&
+ (ip2_uint | mask_uint) != 0xffffffff &&
+ /* Check the 1s are at the start of the mask */
+ (uint32_t) (mask_uint << __builtin_popcountl(mask_uint)) == 0;
+}
+
static void eapol_handle_ptk_3_of_4(struct eapol_sm *sm,
const struct eapol_key *ek,
const uint8_t *decrypted_key_data,
@@ -1520,8 +1550,9 @@ static void eapol_handle_ptk_3_of_4(struct eapol_sm *sm,
rsne = eapol_find_wpa_ie(decrypted_key_data,
decrypted_key_data_size);
else if (sm->handshake->osen_ie)
- rsne = eapol_find_osen(decrypted_key_data,
- decrypted_key_data_size);
+ rsne = eapol_find_wfa_kde(decrypted_key_data,
+ decrypted_key_data_size,
+ IE_WFA_OI_OSEN);
else
rsne = eapol_find_rsne(decrypted_key_data,
decrypted_key_data_size,
@@ -1667,6 +1698,35 @@ static void eapol_handle_ptk_3_of_4(struct eapol_sm *sm,
} else
igtk = NULL;
+ if (sm->handshake->support_ip_allocation) {
+ const uint8_t *ip_alloc_kde =
+ eapol_find_wfa_kde(decrypted_key_data,
+ decrypted_key_data_size,
+ HANDSHAKE_KDE_IP_ADDRESS_ALLOC & 255);
+
+ if (ip_alloc_kde &&
+ (ip_alloc_kde[1] < 16 ||
+ !eapol_check_ip_mask(ip_alloc_kde + 10,
+ ip_alloc_kde + 6,
+ ip_alloc_kde + 14))) {
+ l_debug("Invalid IP Allocation KDE in frame 3/4");
+ handshake_failed(sm, MMPDU_REASON_CODE_INVALID_IE);
+ return;
+ }
+
+ sm->handshake->support_ip_allocation = ip_alloc_kde != NULL;
+
+ if (ip_alloc_kde) {
+ sm->handshake->client_ip_addr =
+ l_get_be32(ip_alloc_kde + 6);
+ sm->handshake->subnet_mask =
+ l_get_be32(ip_alloc_kde + 10);
+ sm->handshake->go_ip_addr =
+ l_get_be32(ip_alloc_kde + 14);
+ } else
+ l_debug("Authenticator ignored our IP Address Request");
+ }
+
retransmit:
/*
* 802.11-2016, Section 12.7.6.4:
diff --git a/src/handshake.h b/src/handshake.h
index c88bb0d1..b738efd9 100644
--- a/src/handshake.h
+++ b/src/handshake.h
@@ -28,8 +28,8 @@
struct handshake_state;
enum crypto_cipher;
-/* 802.11-2016 Table 12-6 in section 12.7.2 */
enum handshake_kde {
+ /* 802.11-2016 Table 12-6 in section 12.7.2 */
HANDSHAKE_KDE_GTK = 0x000fac01,
HANDSHAKE_KDE_MAC_ADDRESS = 0x000fac03,
HANDSHAKE_KDE_PMKID = 0x000fac04,
@@ -41,6 +41,9 @@ enum handshake_kde {
HANDSHAKE_KDE_KEY_ID = 0x000fac0a,
HANDSHAKE_KDE_MULTIBAND_GTK = 0x000fac0b,
HANDSHAKE_KDE_MULTIBAND_KEY_ID = 0x000fac0c,
+ /* Wi-Fi P2P Technical Specification v1.7 4.2.8 */
+ HANDSHAKE_KDE_IP_ADDRESS_REQ = 0x506f9a04,
+ HANDSHAKE_KDE_IP_ADDRESS_ALLOC = 0x506f9a05,
};
enum handshake_event {
@@ -124,6 +127,10 @@ struct handshake_state {
uint8_t proto_version : 2;
unsigned int gtk_index;
struct erp_cache_entry *erp_cache;
+ bool support_ip_allocation : 1;
+ uint32_t client_ip_addr;
+ uint32_t subnet_mask;
+ uint32_t go_ip_addr;
void *user_data;
void (*free)(struct handshake_state *s);
--
2.25.1
1 year, 8 months
[PATCH 1/8] ap: Fix NULL ap->rares
by Andrew Zaborowski
Make sure ap->rates is non-NULL both with and without no_cck_rates.
---
src/ap.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/ap.c b/src/ap.c
index c972cfcb..ae33b461 100644
--- a/src/ap.c
+++ b/src/ap.c
@@ -2074,6 +2074,7 @@ struct ap_state *ap_start(struct netdev *netdev, struct ap_config *config,
ap->ciphers = wiphy_select_cipher(wiphy, 0xffff);
ap->group_cipher = wiphy_select_cipher(wiphy, 0xffff);
ap->beacon_interval = 100;
+ ap->rates = l_uintset_new(200);
/* TODO: Pick from actual supported rates */
if (config->no_cck_rates) {
@@ -2086,7 +2087,6 @@ struct ap_state *ap_start(struct netdev *netdev, struct ap_config *config,
l_uintset_put(ap->rates, 96); /* 48 Mbps*/
l_uintset_put(ap->rates, 108); /* 54 Mbps*/
} else {
- ap->rates = l_uintset_new(200);
l_uintset_put(ap->rates, 2); /* 1 Mbps*/
l_uintset_put(ap->rates, 11); /* 5.5 Mbps*/
l_uintset_put(ap->rates, 22); /* 11 Mbps*/
--
2.25.1
1 year, 8 months