Test functionality to override driver reported signal levels

"SET driver_signal_override <BSSID> [<si_signal< <si_avg_signal>
<si_avg_beacon_signal> <si_noise> <scan_level>]" command can now be used
to request wpa_supplicant to override driver reported signal levels for
signal_poll and scan results. This can be used to test roaming behavior.

Signed-off-by: Jouni Malinen <j@w1.fi>
This commit is contained in:
Jouni Malinen 2020-01-02 20:29:24 +02:00
parent c8eb7fe66c
commit 6c57019376
4 changed files with 180 additions and 14 deletions

View file

@ -419,6 +419,64 @@ static int wpas_ctrl_iface_set_ric_ies(struct wpa_supplicant *wpa_s,
}
#ifdef CONFIG_TESTING_OPTIONS
static int wpas_ctrl_iface_set_dso(struct wpa_supplicant *wpa_s,
const char *val)
{
u8 bssid[ETH_ALEN];
const char *pos = val;
struct driver_signal_override *dso = NULL, *tmp, parsed;
if (hwaddr_aton(pos, bssid))
return -1;
pos = os_strchr(pos, ' ');
dl_list_for_each(tmp, &wpa_s->drv_signal_override,
struct driver_signal_override, list) {
if (os_memcmp(bssid, tmp->bssid, ETH_ALEN) == 0) {
dso = tmp;
break;
}
}
if (!pos) {
/* Remove existing entry */
if (dso) {
dl_list_del(&dso->list);
os_free(dso);
}
return 0;
}
pos++;
/* Update an existing entry or add a new one */
os_memset(&parsed, 0, sizeof(parsed));
if (sscanf(pos, "%d %d %d %d %d",
&parsed.si_current_signal,
&parsed.si_avg_signal,
&parsed.si_avg_beacon_signal,
&parsed.si_current_noise,
&parsed.scan_level) != 5)
return -1;
if (!dso) {
dso = os_zalloc(sizeof(*dso));
if (!dso)
return -1;
os_memcpy(dso->bssid, bssid, ETH_ALEN);
dl_list_add(&wpa_s->drv_signal_override, &dso->list);
}
dso->si_current_signal = parsed.si_current_signal;
dso->si_avg_signal = parsed.si_avg_signal;
dso->si_avg_beacon_signal = parsed.si_avg_beacon_signal;
dso->si_current_noise = parsed.si_current_noise;
dso->scan_level = parsed.scan_level;
return 0;
}
#endif /* CONFIG_TESTING_OPTIONS */
static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
char *cmd)
{
@ -713,6 +771,8 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
wpa_s->sae_commit_override = NULL;
else
wpa_s->sae_commit_override = wpabuf_parse_bin(value);
} else if (os_strcasecmp(cmd, "driver_signal_override") == 0) {
ret = wpas_ctrl_iface_set_dso(wpa_s, value);
#ifdef CONFIG_DPP
} else if (os_strcasecmp(cmd, "dpp_config_obj_override") == 0) {
os_free(wpa_s->dpp_config_obj_override);
@ -8104,6 +8164,7 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
wpa_s->rsnxe_override_assoc = NULL;
wpabuf_free(wpa_s->rsnxe_override_eapol);
wpa_s->rsnxe_override_eapol = NULL;
wpas_clear_driver_signal_override(wpa_s);
#ifdef CONFIG_DPP
os_free(wpa_s->dpp_config_obj_override);
wpa_s->dpp_config_obj_override = NULL;

View file

@ -124,13 +124,8 @@ static inline int wpa_drv_stop_sched_scan(struct wpa_supplicant *wpa_s)
return -1;
}
static inline struct wpa_scan_results * wpa_drv_get_scan_results2(
struct wpa_supplicant *wpa_s)
{
if (wpa_s->driver->get_scan_results2)
return wpa_s->driver->get_scan_results2(wpa_s->drv_priv);
return NULL;
}
struct wpa_scan_results *
wpa_drv_get_scan_results2(struct wpa_supplicant *wpa_s);
static inline int wpa_drv_get_bssid(struct wpa_supplicant *wpa_s, u8 *bssid)
{
@ -494,13 +489,8 @@ static inline int wpa_drv_signal_monitor(struct wpa_supplicant *wpa_s,
return -1;
}
static inline int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s,
struct wpa_signal_info *si)
{
if (wpa_s->driver->signal_poll)
return wpa_s->driver->signal_poll(wpa_s->drv_priv, si);
return -1;
}
int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s,
struct wpa_signal_info *si);
static inline int wpa_drv_channel_info(struct wpa_supplicant *wpa_s,
struct wpa_channel_info *ci)

View file

@ -487,6 +487,20 @@ void wpas_clear_disabled_interface(void *eloop_ctx, void *timeout_ctx)
}
#ifdef CONFIG_TESTING_OPTIONS
void wpas_clear_driver_signal_override(struct wpa_supplicant *wpa_s)
{
struct driver_signal_override *dso;
while ((dso = dl_list_first(&wpa_s->drv_signal_override,
struct driver_signal_override, list))) {
dl_list_del(&dso->list);
os_free(dso);
}
}
#endif /* CONFIG_TESTING_OPTIONS */
static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
{
int i;
@ -516,6 +530,7 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
wpa_s->rsnxe_override_assoc = NULL;
wpabuf_free(wpa_s->rsnxe_override_eapol);
wpa_s->rsnxe_override_eapol = NULL;
wpas_clear_driver_signal_override(wpa_s);
#endif /* CONFIG_TESTING_OPTIONS */
if (wpa_s->conf != NULL) {
@ -4802,6 +4817,9 @@ wpa_supplicant_alloc(struct wpa_supplicant *parent)
dl_list_init(&wpa_s->bss_tmp_disallowed);
dl_list_init(&wpa_s->fils_hlp_req);
#ifdef CONFIG_TESTING_OPTIONS
dl_list_init(&wpa_s->drv_signal_override);
#endif /* CONFIG_TESTING_OPTIONS */
return wpa_s;
}
@ -7884,3 +7902,87 @@ int wpas_disable_mac_addr_randomization(struct wpa_supplicant *wpa_s,
return 0;
}
int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s,
struct wpa_signal_info *si)
{
int res;
if (!wpa_s->driver->signal_poll)
return -1;
res = wpa_s->driver->signal_poll(wpa_s->drv_priv, si);
#ifdef CONFIG_TESTING_OPTIONS
if (res == 0) {
struct driver_signal_override *dso;
dl_list_for_each(dso, &wpa_s->drv_signal_override,
struct driver_signal_override, list) {
if (os_memcmp(wpa_s->bssid, dso->bssid,
ETH_ALEN) != 0)
continue;
wpa_printf(MSG_DEBUG,
"Override driver signal_poll information: current_signal: %d->%d avg_signal: %d->%d avg_beacon_signal: %d->%d current_noise: %d->%d",
si->current_signal,
dso->si_current_signal,
si->avg_signal,
dso->si_avg_signal,
si->avg_beacon_signal,
dso->si_avg_beacon_signal,
si->current_noise,
dso->si_current_noise);
si->current_signal = dso->si_current_signal;
si->avg_signal = dso->si_avg_signal;
si->avg_beacon_signal = dso->si_avg_beacon_signal;
si->current_noise = dso->si_current_noise;
break;
}
}
#endif /* CONFIG_TESTING_OPTIONS */
return res;
}
struct wpa_scan_results *
wpa_drv_get_scan_results2(struct wpa_supplicant *wpa_s)
{
struct wpa_scan_results *scan_res;
#ifdef CONFIG_TESTING_OPTIONS
size_t idx;
#endif /* CONFIG_TESTING_OPTIONS */
if (!wpa_s->driver->get_scan_results2)
return NULL;
scan_res = wpa_s->driver->get_scan_results2(wpa_s->drv_priv);
#ifdef CONFIG_TESTING_OPTIONS
for (idx = 0; scan_res && idx < scan_res->num; idx++) {
struct driver_signal_override *dso;
struct wpa_scan_res *res = scan_res->res[idx];
dl_list_for_each(dso, &wpa_s->drv_signal_override,
struct driver_signal_override, list) {
if (os_memcmp(res->bssid, dso->bssid, ETH_ALEN) != 0)
continue;
wpa_printf(MSG_DEBUG,
"Override driver scan signal level %d->%d for "
MACSTR,
res->level, dso->scan_level,
MAC2STR(res->bssid));
res->flags |= WPA_SCAN_QUAL_INVALID;
if (dso->scan_level < 0)
res->flags |= WPA_SCAN_LEVEL_DBM;
else
res->flags &= ~WPA_SCAN_LEVEL_DBM;
res->level = dso->scan_level;
break;
}
}
#endif /* CONFIG_TESTING_OPTIONS */
return scan_res;
}

View file

@ -480,6 +480,16 @@ struct fils_hlp_req {
struct wpabuf *pkt;
};
struct driver_signal_override {
struct dl_list list;
u8 bssid[ETH_ALEN];
int si_current_signal;
int si_avg_signal;
int si_avg_beacon_signal;
int si_current_noise;
int scan_level;
};
/**
* struct wpa_supplicant - Internal data for wpa_supplicant interface
*
@ -1132,6 +1142,7 @@ struct wpa_supplicant {
int *extra_sae_rejected_groups;
struct wpabuf *rsnxe_override_assoc;
struct wpabuf *rsnxe_override_eapol;
struct dl_list drv_signal_override;
#endif /* CONFIG_TESTING_OPTIONS */
struct wmm_ac_assoc_data *wmm_ac_assoc_info;
@ -1570,4 +1581,6 @@ int wpas_ctrl_iface_get_pref_freq_list_override(struct wpa_supplicant *wpa_s,
int wpa_is_fils_supported(struct wpa_supplicant *wpa_s);
int wpa_is_fils_sk_pfs_supported(struct wpa_supplicant *wpa_s);
void wpas_clear_driver_signal_override(struct wpa_supplicant *wpa_s);
#endif /* WPA_SUPPLICANT_I_H */