mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-10-29 17:42:41 +00:00
243 lines
8.8 KiB
Diff
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. */
|
|
};
|
|
|
|
|