diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c index 145b716dc..b50ec3a0e 100644 --- a/wpa_supplicant/bss.c +++ b/wpa_supplicant/bss.c @@ -30,25 +30,6 @@ */ #define WPA_BSS_EXPIRATION_PERIOD 10 -/** - * WPA_BSS_EXPIRATION_AGE - BSS entry age after which it can be expired - * - * This value control the time in seconds after which a BSS entry gets removed - * if it has not been updated or is not in use. - */ -#define WPA_BSS_EXPIRATION_AGE 180 - -/** - * WPA_BSS_EXPIRATION_SCAN_COUNT - Expire BSS after number of scans - * - * If the BSS entry has not been seen in this many scans, it will be removed. - * Value 1 means that the entry is removed after the first scan without the - * BSSID being seen. Larger values can be used to avoid BSS entries - * disappearing if they are not visible in every scan (e.g., low signal quality - * or interference). - */ -#define WPA_BSS_EXPIRATION_SCAN_COUNT 2 - #define WPA_BSS_FREQ_CHANGED_FLAG BIT(0) #define WPA_BSS_SIGNAL_CHANGED_FLAG BIT(1) #define WPA_BSS_PRIVACY_CHANGED_FLAG BIT(2) @@ -412,7 +393,8 @@ void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info, continue; /* expire only BSSes that were scanned */ if (bss->last_update_idx < wpa_s->bss_update_idx) bss->scan_miss_count++; - if (bss->scan_miss_count >= WPA_BSS_EXPIRATION_SCAN_COUNT) { + if (bss->scan_miss_count >= + wpa_s->conf->bss_expiration_scan_count) { wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Expire BSS %u due to " "no match in scan", bss->id); wpa_bss_remove(wpa_s, bss); @@ -450,7 +432,7 @@ static void wpa_bss_timeout(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; - wpa_bss_flush_by_age(wpa_s, WPA_BSS_EXPIRATION_AGE); + wpa_bss_flush_by_age(wpa_s, wpa_s->conf->bss_expiration_age); eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD, 0, wpa_bss_timeout, wpa_s, NULL); } diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index dd6bc43a1..7ec45310b 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -2170,6 +2170,8 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface, config->p2p_go_intent = DEFAULT_P2P_GO_INTENT; config->p2p_intra_bss = DEFAULT_P2P_INTRA_BSS; config->bss_max_count = DEFAULT_BSS_MAX_COUNT; + config->bss_expiration_age = DEFAULT_BSS_EXPIRATION_AGE; + config->bss_expiration_scan_count = DEFAULT_BSS_EXPIRATION_SCAN_COUNT; config->max_num_sta = DEFAULT_MAX_NUM_STA; if (ctrl_interface) @@ -2439,6 +2441,8 @@ static const struct global_parse_data global_fields[] = { #endif /* CONFIG_P2P */ { FUNC(country), CFG_CHANGED_COUNTRY }, { INT(bss_max_count), 0 }, + { INT(bss_expiration_age), 0 }, + { INT(bss_expiration_scan_count), 0 }, { INT_RANGE(filter_ssids, 0, 1), 0 }, { INT(max_num_sta), 0 }, { INT_RANGE(disassoc_low_ack, 0, 1), 0 } diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index 57cd0af81..c37036211 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -25,6 +25,8 @@ #define DEFAULT_P2P_GO_INTENT 7 #define DEFAULT_P2P_INTRA_BSS 1 #define DEFAULT_BSS_MAX_COUNT 200 +#define DEFAULT_BSS_EXPIRATION_AGE 180 +#define DEFAULT_BSS_EXPIRATION_SCAN_COUNT 2 #define DEFAULT_MAX_NUM_STA 128 #include "config_ssid.h" @@ -381,6 +383,25 @@ struct wpa_config { */ unsigned int bss_max_count; + /** + * bss_expiration_age - BSS entry age after which it can be expired + * + * This value controls the time in seconds after which a BSS entry + * gets removed if it has not been updated or is not in use. + */ + unsigned int bss_expiration_age; + + /** + * bss_expiration_scan_count - Expire BSS after number of scans + * + * If the BSS entry has not been seen in this many scans, it will be + * removed. A value of 1 means that entry is removed after the first + * scan in which the BSSID is not seen. Larger values can be used + * to avoid BSS entries disappearing if they are not visible in + * every scan (e.g., low signal quality or interference). + */ + unsigned int bss_expiration_scan_count; + /** * filter_ssids - SSID-based scan result filtering * diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index 464233539..2d5fdd6a0 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -690,6 +690,13 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) } if (config->bss_max_count != DEFAULT_BSS_MAX_COUNT) fprintf(f, "bss_max_count=%u\n", config->bss_max_count); + if (config->bss_expiration_age != DEFAULT_BSS_EXPIRATION_AGE) + fprintf(f, "bss_expiration_age=%u\n", + config->bss_expiration_age); + if (config->bss_expiration_scan_count != + DEFAULT_BSS_EXPIRATION_SCAN_COUNT) + fprintf(f, "bss_expiration_scan_count=%u\n", + config->bss_expiration_scan_count); if (config->filter_ssids) fprintf(f, "filter_ssids=%d\n", config->filter_ssids); if (config->max_num_sta != DEFAULT_MAX_NUM_STA) diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 0fe31a1a4..cb813ba79 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -1994,6 +1994,22 @@ static int wpa_supplicant_ctrl_iface_ap_scan( } +static int wpa_supplicant_ctrl_iface_bss_expire_age( + struct wpa_supplicant *wpa_s, char *cmd) +{ + int expire_age = atoi(cmd); + return wpa_supplicant_set_bss_expiration_age(wpa_s, expire_age); +} + + +static int wpa_supplicant_ctrl_iface_bss_expire_count( + struct wpa_supplicant *wpa_s, char *cmd) +{ + int expire_count = atoi(cmd); + return wpa_supplicant_set_bss_expiration_count(wpa_s, expire_count); +} + + static void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s) { wpa_printf(MSG_DEBUG, "Dropping SA without deauthentication"); @@ -3194,6 +3210,13 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strncmp(buf, "STA_AUTOCONNECT ", 16) == 0) { if (wpa_supplicant_ctrl_iface_sta_autoconnect(wpa_s, buf + 16)) reply_len = -1; + } else if (os_strncmp(buf, "BSS_EXPIRE_AGE ", 15) == 0) { + if (wpa_supplicant_ctrl_iface_bss_expire_age(wpa_s, buf + 15)) + reply_len = -1; + } else if (os_strncmp(buf, "BSS_EXPIRE_COUNT ", 17) == 0) { + if (wpa_supplicant_ctrl_iface_bss_expire_count(wpa_s, + buf + 17)) + reply_len = -1; #ifdef CONFIG_TDLS } else if (os_strncmp(buf, "TDLS_DISCOVER ", 14) == 0) { if (wpa_supplicant_ctrl_iface_tdls_discover(wpa_s, buf + 14)) diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c index 63bea98e8..d3698f8f7 100644 --- a/wpa_supplicant/dbus/dbus_new.c +++ b/wpa_supplicant/dbus/dbus_new.c @@ -1386,6 +1386,16 @@ static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = { (WPADBusPropertyAccessor) wpas_dbus_setter_ap_scan, RW }, + { "BSSExpireAge", WPAS_DBUS_NEW_IFACE_INTERFACE, "u", + (WPADBusPropertyAccessor) wpas_dbus_getter_bss_expire_age, + (WPADBusPropertyAccessor) wpas_dbus_setter_bss_expire_age, + RW + }, + { "BSSExpireCount", WPAS_DBUS_NEW_IFACE_INTERFACE, "u", + (WPADBusPropertyAccessor) wpas_dbus_getter_bss_expire_count, + (WPADBusPropertyAccessor) wpas_dbus_setter_bss_expire_count, + RW + }, { "Ifname", WPAS_DBUS_NEW_IFACE_INTERFACE, "s", (WPADBusPropertyAccessor) wpas_dbus_getter_ifname, NULL, R diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c index c7014328b..074a4a9ff 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers.c +++ b/wpa_supplicant/dbus/dbus_new_handlers.c @@ -2155,6 +2155,94 @@ DBusMessage * wpas_dbus_setter_ap_scan(DBusMessage *message, } +/** + * wpas_dbus_getter_bss_expire_age - Get BSS entry expiration age + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: A message containing value of bss_expiration_age variable + * + * Getter function for "BSSExpireAge" property. + */ +DBusMessage * wpas_dbus_getter_bss_expire_age(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + dbus_uint32_t expire_age = wpa_s->conf->bss_expiration_age; + return wpas_dbus_simple_property_getter(message, DBUS_TYPE_UINT32, + &expire_age); +} + + +/** + * wpas_dbus_setter_bss_expire_age - Control BSS entry expiration age + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: NULL + * + * Setter function for "BSSExpireAge" property. + */ +DBusMessage * wpas_dbus_setter_bss_expire_age(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + dbus_uint32_t expire_age; + + reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_UINT32, + &expire_age); + if (reply) + return reply; + + if (wpa_supplicant_set_bss_expiration_age(wpa_s, expire_age)) { + return wpas_dbus_error_invalid_args( + message, "BSSExpireAge must be >=10"); + } + return NULL; +} + + +/** + * wpas_dbus_getter_bss_expire_count - Get BSS entry expiration scan count + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: A message containing value of bss_expire_count variable + * + * Getter function for "BSSExpireCount" property. + */ +DBusMessage * wpas_dbus_getter_bss_expire_count(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + dbus_uint32_t expire_count = wpa_s->conf->bss_expiration_age; + return wpas_dbus_simple_property_getter(message, DBUS_TYPE_UINT32, + &expire_count); +} + + +/** + * wpas_dbus_setter_bss_expire_count - Control BSS entry expiration scan count + * @message: Pointer to incoming dbus message + * @wpa_s: wpa_supplicant structure for a network interface + * Returns: NULL + * + * Setter function for "BSSExpireCount" property. + */ +DBusMessage * wpas_dbus_setter_bss_expire_count(DBusMessage *message, + struct wpa_supplicant *wpa_s) +{ + DBusMessage *reply = NULL; + dbus_uint32_t expire_count; + + reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_UINT32, + &expire_count); + if (reply) + return reply; + + if (wpa_supplicant_set_bss_expiration_count(wpa_s, expire_count)) { + return wpas_dbus_error_invalid_args( + message, "BSSExpireCount must be >0"); + } + return NULL; +} + + /** * wpas_dbus_getter_ifname - Get interface name * @message: Pointer to incoming dbus message diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h index 288cd43b9..be7a9bf6a 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers.h +++ b/wpa_supplicant/dbus/dbus_new_handlers.h @@ -116,6 +116,18 @@ DBusMessage * wpas_dbus_getter_ap_scan(DBusMessage *message, DBusMessage * wpas_dbus_setter_ap_scan(DBusMessage *message, struct wpa_supplicant *wpa_s); +DBusMessage * wpas_dbus_getter_bss_expire_age(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_setter_bss_expire_age(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_getter_bss_expire_count(DBusMessage *message, + struct wpa_supplicant *wpa_s); + +DBusMessage * wpas_dbus_setter_bss_expire_count(DBusMessage *message, + struct wpa_supplicant *wpa_s); + DBusMessage * wpas_dbus_getter_ifname(DBusMessage *message, struct wpa_supplicant *wpa_s); diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c index f0ba62891..e4224029d 100644 --- a/wpa_supplicant/wpa_cli.c +++ b/wpa_supplicant/wpa_cli.c @@ -475,6 +475,46 @@ static int wpa_cli_cmd_ap_scan(struct wpa_ctrl *ctrl, int argc, char *argv[]) } +static int wpa_cli_cmd_bss_expire_age(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char cmd[256]; + int res; + + if (argc != 1) { + printf("Invalid BSS_EXPIRE_AGE command: needs one argument " + "(bss_expire_age value)\n"); + return -1; + } + res = os_snprintf(cmd, sizeof(cmd), "BSS_EXPIRE_AGE %s", argv[0]); + if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { + printf("Too long BSS_EXPIRE_AGE command.\n"); + return -1; + } + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_bss_expire_count(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char cmd[256]; + int res; + + if (argc != 1) { + printf("Invalid BSS_EXPIRE_COUNT command: needs one argument " + "(bss_expire_count value)\n"); + return -1; + } + res = os_snprintf(cmd, sizeof(cmd), "BSS_EXPIRE_COUNT %s", argv[0]); + if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { + printf("Too long BSS_EXPIRE_COUNT command.\n"); + return -1; + } + return wpa_ctrl_command(ctrl, cmd); +} + + static int wpa_cli_cmd_stkstart(struct wpa_ctrl *ctrl, int argc, char *argv[]) { @@ -2389,6 +2429,12 @@ static struct wpa_cli_cmd wpa_cli_commands[] = { { "ap_scan", wpa_cli_cmd_ap_scan, cli_cmd_flag_none, " = set ap_scan parameter" }, + { "bss_expire_age", wpa_cli_cmd_bss_expire_age, + cli_cmd_flag_none, + " = set BSS expiration age parameter" }, + { "bss_expire_count", wpa_cli_cmd_bss_expire_count, + cli_cmd_flag_none, + " = set BSS expiration scan count parameter" }, { "stkstart", wpa_cli_cmd_stkstart, cli_cmd_flag_none, " = request STK negotiation with " }, diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index def42d0bb..b34bf0395 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -1661,6 +1661,52 @@ int wpa_supplicant_set_ap_scan(struct wpa_supplicant *wpa_s, int ap_scan) } +/** + * wpa_supplicant_set_bss_expiration_age - Set BSS entry expiration age + * @wpa_s: wpa_supplicant structure for a network interface + * @expire_age: Expiration age in seconds + * Returns: 0 if succeed or -1 if expire_age has an invalid value + * + */ +int wpa_supplicant_set_bss_expiration_age(struct wpa_supplicant *wpa_s, + unsigned int bss_expire_age) +{ + if (bss_expire_age < 10) { + wpa_msg(wpa_s, MSG_ERROR, "Invalid bss expiration age %u", + bss_expire_age); + return -1; + } + wpa_msg(wpa_s, MSG_DEBUG, "Setting bss expiration age: %d sec", + bss_expire_age); + wpa_s->conf->bss_expiration_age = bss_expire_age; + + return 0; +} + + +/** + * wpa_supplicant_set_bss_expiration_count - Set BSS entry expiration scan count + * @wpa_s: wpa_supplicant structure for a network interface + * @expire_count: number of scans after which an unseen BSS is reclaimed + * Returns: 0 if succeed or -1 if expire_count has an invalid value + * + */ +int wpa_supplicant_set_bss_expiration_count(struct wpa_supplicant *wpa_s, + unsigned int bss_expire_count) +{ + if (bss_expire_count < 1) { + wpa_msg(wpa_s, MSG_ERROR, "Invalid bss expiration count %u", + bss_expire_count); + return -1; + } + wpa_msg(wpa_s, MSG_DEBUG, "Setting bss expiration scan count: %u", + bss_expire_count); + wpa_s->conf->bss_expiration_scan_count = bss_expire_count; + + return 0; +} + + /** * wpa_supplicant_set_debug_params - Set global debug params * @global: wpa_global structure diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 056ffa016..859a65b89 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -590,6 +590,10 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); int wpa_supplicant_set_ap_scan(struct wpa_supplicant *wpa_s, int ap_scan); +int wpa_supplicant_set_bss_expiration_age(struct wpa_supplicant *wpa_s, + unsigned int expire_age); +int wpa_supplicant_set_bss_expiration_count(struct wpa_supplicant *wpa_s, + unsigned int expire_count); int wpa_supplicant_set_debug_params(struct wpa_global *global, int debug_level, int debug_timestamp, int debug_show_keys);