Files
wlan-ap/feeds/wifi-ax/hostapd/patches/810-client-disconnect-when-rssi-is-low.patch
2021-03-25 12:19:47 +01:00

243 lines
8.8 KiB
Diff

--- a/src/ap/ubus.c
+++ b/src/ap/ubus.c
@@ -146,6 +146,49 @@ hostapd_bss_ban_client(struct hostapd_da
eloop_register_timeout(0, time * 1000, hostapd_bss_del_ban, ban, hapd);
}
+static void
+hostapd_bss_signal_check(void *eloop_data, void *user_ctx)
+/* This is called by an eloop timeout. All stations in the list are checked
+ * for signal level. This requires calling the driver, since hostapd doesn't
+ * see packets from a station once it is fully authorized.
+ * Stations with signal level below the threshold will be dropped.
+ */
+{
+ struct hostapd_data *hapd = user_ctx;
+ struct hostap_sta_driver_data data;
+ struct sta_info *sta, *sta_next;
+ u8 addr[ETH_ALEN]; /* Buffer the address for logging purposes, in case it is destroyed while dropping */
+ int strikes; /* same with strike count on this station. */
+ int num_sta = 0;
+ int num_drop = 0;
+ int signal;
+
+ for (sta = hapd->sta_list; sta; sta = sta_next) {
+ sta_next = sta->next;
+ memcpy(addr, sta->addr, ETH_ALEN);
+ if (!hostapd_drv_read_sta_data(hapd, &data, addr)) {
+ signal = data.signal;
+ num_sta++;
+ strikes = sta->sig_drop_strikes;
+ if (signal < hapd->conf->signal_stay_min) { /* signal bad. */
+ strikes = ++sta->sig_drop_strikes;
+ if (strikes >= hapd->conf->signal_strikes) { /* Struck out--, drop. */
+ hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO,
+ "Deauthenticating client due to low signal strength %i", data.signal);
+ ap_sta_deauthenticate(hapd, sta, hapd->conf->signal_drop_reason);
+ num_drop++;
+ }
+ } else {
+ sta->sig_drop_strikes = 0; /* signal OK, reset the strike counter. */
+ strikes = 0;
+ }
+ }
+ }
+
+ eloop_register_timeout(hapd->conf->signal_poll_time, 0, hostapd_bss_signal_check, eloop_data, hapd);
+
+}
+
static int
hostapd_bss_reload(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
@@ -580,6 +623,70 @@ hostapd_vendor_elements(struct ubus_cont
return UBUS_STATUS_OK;
}
+enum {
+ SIGNAL_CONNECT,
+ SIGNAL_STAY,
+ SIGNAL_STRIKES,
+ SIGNAL_POLL,
+ SIGNAL_DROP_REASON,
+ __SIGNAL_SETTINGS_MAX
+};
+
+static const struct blobmsg_policy sig_policy[__SIGNAL_SETTINGS_MAX] = {
+ [SIGNAL_CONNECT] = {"connect", BLOBMSG_TYPE_INT32},
+ [SIGNAL_STAY] = {"stay", BLOBMSG_TYPE_INT32},
+ [SIGNAL_STRIKES] = {"strikes", BLOBMSG_TYPE_INT32},
+ [SIGNAL_POLL] = {"poll_time", BLOBMSG_TYPE_INT32},
+ [SIGNAL_DROP_REASON] = {"reason", BLOBMSG_TYPE_INT32}
+};
+
+static int
+hostapd_bss_set_signal(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct blob_attr *tb[__SIGNAL_SETTINGS_MAX];
+ struct hostapd_data *hapd = get_hapd_from_object(obj);
+ int sig_stay;
+
+ blobmsg_parse(sig_policy, __SIGNAL_SETTINGS_MAX, tb, blob_data(msg), blob_len(msg));
+
+ if (!tb[SIGNAL_CONNECT])
+ return UBUS_STATUS_INVALID_ARGUMENT;
+ hapd->conf->signal_auth_min = blobmsg_get_u32(tb[SIGNAL_CONNECT]);
+ if (tb[SIGNAL_STAY]) {
+ sig_stay = blobmsg_get_u32(tb[SIGNAL_STAY]);
+ } else {
+ sig_stay = hapd->conf->signal_auth_min - 5; // Default is 5 dB lower to stay.
+ }
+ hapd->conf->signal_stay_min = sig_stay;
+ if (tb[SIGNAL_STRIKES]) {
+ hapd->conf->signal_strikes = blobmsg_get_u32(tb[SIGNAL_STRIKES]);
+ if (hapd->conf->signal_strikes < 1)
+ return UBUS_STATUS_INVALID_ARGUMENT;
+ } else {
+ hapd->conf->signal_strikes = 3;
+ }
+ if (tb[SIGNAL_POLL]) {
+ hapd->conf->signal_poll_time = blobmsg_get_u32(tb[SIGNAL_POLL]);
+ if (hapd->conf->signal_poll_time < 3)
+ return UBUS_STATUS_INVALID_ARGUMENT;
+ } else {
+ hapd->conf->signal_poll_time = 5;
+ }
+ if (tb[SIGNAL_DROP_REASON]) {
+ hapd->conf->signal_drop_reason = blobmsg_get_u32(tb[SIGNAL_DROP_REASON]);
+ if ((hapd->conf->signal_drop_reason < 1) || (hapd->conf->signal_drop_reason > 35)) // XXX -- look up real limit
+ return UBUS_STATUS_INVALID_ARGUMENT;
+ } else {
+ hapd->conf->signal_drop_reason = 3; // Local choice. 5 (AP too busy) is also a good one.
+ }
+ eloop_cancel_timeout(hostapd_bss_signal_check, ELOOP_ALL_CTX, ELOOP_ALL_CTX);
+ eloop_register_timeout(3, 0, hostapd_bss_signal_check, NULL, hapd); // Start up the poll timer.
+
+ return UBUS_STATUS_OK;
+}
+
static void
hostapd_rrm_print_nr(struct hostapd_neighbor_entry *nr)
{
@@ -1049,6 +1156,7 @@ static const struct ubus_method bss_meth
UBUS_METHOD_NOARG("rrm_nr_list", hostapd_rrm_nr_list),
UBUS_METHOD("rrm_nr_set", hostapd_rrm_nr_set, nr_set_policy),
UBUS_METHOD("rrm_beacon_req", hostapd_rrm_beacon_req, beacon_req_policy),
+ UBUS_METHOD("set_required_signal", hostapd_bss_set_signal, sig_policy),
#ifdef CONFIG_WNM_AP
UBUS_METHOD("wnm_disassoc_imminent", hostapd_wnm_disassoc_imminent, wnm_disassoc_policy),
#endif
@@ -1086,6 +1194,8 @@ void hostapd_ubus_add_bss(struct hostapd
obj->n_methods = bss_object_type.n_methods;
ret = ubus_add_object(ctx, obj);
hostapd_ubus_ref_inc();
+ if (hapd->conf->signal_stay_min > -128)
+ eloop_register_timeout(3, 0, hostapd_bss_signal_check, NULL, hapd); /* Start up the poll timer. */
}
void hostapd_ubus_free_bss(struct hostapd_data *hapd)
@@ -1174,6 +1284,15 @@ int hostapd_ubus_handle_event(struct hos
addr = req->mgmt_frame->sa;
else
addr = req->addr;
+ if (req->type < ARRAY_SIZE(types))
+ type = types[req->type];
+
+ if (req->ssi_signal && req->type != HOSTAPD_UBUS_PROBE_REQ) /* don't clutter the log with probes. */
+ hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "%s request, signal %i %s",
+ type, req->ssi_signal,
+ (req->ssi_signal >= hapd->conf->signal_auth_min) ? "(Accepted)" : "(DENIED)");
+ if (req->ssi_signal && req->ssi_signal < hapd->conf->signal_auth_min)
+ return WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
ban = avl_find_element(&hapd->ubus.banned, addr, ban, avl);
if (ban)
@@ -1182,9 +1301,6 @@ int hostapd_ubus_handle_event(struct hos
if (!hapd->ubus.obj.has_subscribers)
return WLAN_STATUS_SUCCESS;
- if (req->type < ARRAY_SIZE(types))
- type = types[req->type];
-
blob_buf_init(&b, 0);
blobmsg_add_macaddr(&b, "address", addr);
if (req->mgmt_frame)
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -3322,6 +3322,24 @@ static int hostapd_config_fill(struct ho
return 1;
}
bss->send_probe_response = val;
+ } else if (os_strcmp(buf, "signal_connect") == 0) {
+ bss->signal_auth_min = atoi(pos);
+ } else if (os_strcmp(buf, "signal_stay") == 0) {
+ bss->signal_stay_min = atoi(pos);
+ } else if (os_strcmp(buf, "signal_poll_time") == 0) {
+ bss->signal_poll_time = atoi(pos);
+ if (bss->signal_poll_time < 3) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid signal poll time", line);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "signal_strikes") == 0) {
+ bss->signal_strikes = atoi(pos);
+ } else if (os_strcmp(buf, "signal_drop_reason") == 0) {
+ bss->signal_drop_reason = atoi(pos);
+ if (bss->signal_drop_reason < 1 || bss->signal_drop_reason > 54) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid signal drop reason", line);
+ return 1;
+ }
} else if (os_strcmp(buf, "supported_rates") == 0) {
if (hostapd_parse_intlist(&conf->supported_rates, pos)) {
wpa_printf(MSG_ERROR, "Line %d: invalid rate list",
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -94,6 +94,11 @@ void hostapd_config_defaults_bss(struct
bss->eapol_version = EAPOL_VERSION;
bss->max_listen_interval = 65535;
+ bss->signal_auth_min = -128; /* this is lower than any real signal, so all stations will be accepted */
+ bss->signal_stay_min = -128;
+ bss->signal_strikes = 3;
+ bss->signal_poll_time = 5;
+ bss->signal_drop_reason = 3; /* "Local choice" */
bss->pwd_group = 19; /* ECC: GF(p=256) */
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -351,7 +351,11 @@ struct hostapd_bss_config {
int wds_sta;
int isolate;
int start_disabled;
-
+ int signal_auth_min; /* Minimum signal a STA needs to authenticate */
+ int signal_stay_min; /* Minimum signal needed to stay connected. */
+ int signal_poll_time; /* Time in seconds between checks of connected STAs */
+ int signal_strikes; /* Number of consecutive times signal can be low before dropping the STA. */
+ int signal_drop_reason; /* IEEE802.11 reason code transmitted when dropping a STA. */
int auth_algs; /* bitfield of allowed IEEE 802.11 authentication
* algorithms, WPA_AUTH_ALG_{OPEN,SHARED,LEAP} */
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -732,6 +732,7 @@ struct sta_info * ap_sta_add(struct host
sta_track_claim_taxonomy_info(hapd->iface, addr,
&sta->probe_ie_taxonomy);
#endif /* CONFIG_TAXONOMY */
+ sta->sig_drop_strikes = 0;
return sta;
}
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -286,6 +286,7 @@ struct sta_info {
unsigned int airtime_weight;
struct os_reltime backlogged_until;
#endif /* CONFIG_AIRTIME_POLICY */
+ int sig_drop_strikes; /* Number of times signal was below threshold. */
};