Merge "bandsteering: Robustness to STAs which re-join the network."
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 380167e..82fd7c4 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -549,7 +549,7 @@
enum ssid_match_result res;
if (request_logging_path) {
- maybe_write_timestamp_file(mgmt, hapd, LOG_PROBE);
+ maybe_write_timestamp_file(mgmt->sa, hapd, LOG_PROBE);
}
ie = mgmt->u.probe_req.variable;
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 7289598..9140f3e 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -1586,7 +1586,7 @@
}
if (request_logging_path) {
- maybe_write_timestamp_file(mgmt, hapd, LOG_ASSOC);
+ maybe_write_timestamp_file(mgmt->sa, hapd, LOG_ASSOC);
}
@@ -1641,9 +1641,18 @@
sta = ap_get_sta(hapd, mgmt->sa);
if (steering_timestamp_path) {
+ /* If the STA has successfully associated on the bandsteering target
+ * interface, reset the bandsteering state so that we try to bandsteer it
+ * again.
+ */
+ if (read_timestamp_file(mgmt->sa, LOG_ASSOC_SUCCESSFUL, STEERING_PATH, NULL)) {
+ delete_timestamp_file(mgmt->sa, LOG_ASSOC_SUCCESSFUL, STEERING_PATH);
+ delete_timestamp_file(mgmt->sa, LOG_ASSOC, LOGGING_PATH);
+ }
+
os_get_reltime(&now);
- if (read_timestamp_file(mgmt, LOG_PROBE, STEERING_PATH, &probe_time)) {
- if (!read_timestamp_file(mgmt, LOG_ASSOC, LOGGING_PATH,
+ if (read_timestamp_file(mgmt->sa, LOG_PROBE, STEERING_PATH, &probe_time)) {
+ if (!read_timestamp_file(mgmt->sa, LOG_ASSOC, LOGGING_PATH,
&bandsteer_until) ||
os_reltime_before(&now, &bandsteer_until)) {
wpa_printf(MSG_INFO, "Rejecting " MACSTR " until %d sec %d usec",
@@ -1652,7 +1661,7 @@
resp = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
goto fail;
} else {
- write_timestamp_file(mgmt, hapd, LOG_BANDSTEERING_FAILED, now);
+ write_timestamp_file(mgmt->sa, hapd, LOG_BANDSTEERING_FAILED, &now);
}
}
}
@@ -2324,6 +2333,13 @@
ap_sta_set_authorized(hapd, sta, 1);
}
+
+ if (request_logging_path && !steering_timestamp_path) {
+ /* Log the successful associate, so that the interface steering to this one
+ * knows it can keep bandsteering if it sees another assoc request. */
+ write_timestamp_file(mgmt->da, hapd, LOG_ASSOC_SUCCESSFUL, NULL);
+ }
+
if (reassoc)
mlme_reassociate_indication(hapd, sta);
else
diff --git a/src/ap/steering.c b/src/ap/steering.c
index f7a7f99..2916262 100644
--- a/src/ap/steering.c
+++ b/src/ap/steering.c
@@ -17,7 +17,7 @@
#include "hostapd.h"
#include "steering.h"
-static int get_timestamp_filename(const struct ieee80211_mgmt *mgmt,
+static int get_timestamp_filename(const u8 *mac,
logged_request_type type,
steering_path_type path_type, char *buf,
size_t len) {
@@ -29,7 +29,7 @@
}
if (os_snprintf(buf, len, "%s/" COMPACT_MACSTR ".%d", path,
- MAC2STR(mgmt->sa), type) < 0) {
+ MAC2STR(mac), type) < 0) {
wpa_printf(MSG_ERROR, "os_snprintf couldn't format filename: %s",
strerror(errno));
return 0;
@@ -38,15 +38,15 @@
return 1;
}
-int write_timestamp_file(const struct ieee80211_mgmt *mgmt,
+int write_timestamp_file(const u8 *mac,
const struct hostapd_data *hapd,
logged_request_type type,
- const struct os_reltime timestamp) {
+ const struct os_reltime *timestamp) {
FILE *f;
char filename[1024], tmp_filename[1024];
int success = 0;
- if (!get_timestamp_filename(mgmt, type, LOGGING_PATH, filename,
+ if (!get_timestamp_filename(mac, type, LOGGING_PATH, filename,
sizeof(filename))) {
return 0;
}
@@ -67,10 +67,12 @@
return 0;
}
- if (fprintf(f, "%d %d", timestamp.sec, timestamp.usec) < 0) {
- wpa_printf(MSG_ERROR, "fprintf to %s: %s", tmp_filename, strerror(errno));
- } else {
- success = 1;
+ if (timestamp) {
+ if (fprintf(f, "%d %d", timestamp->sec, timestamp->usec) < 0) {
+ wpa_printf(MSG_ERROR, "fprintf to %s: %s", tmp_filename, strerror(errno));
+ } else {
+ success = 1;
+ }
}
if (fclose(f) == EOF) {
@@ -87,7 +89,7 @@
return success;
}
-int maybe_write_timestamp_file(const struct ieee80211_mgmt *mgmt,
+int maybe_write_timestamp_file(const u8 *mac,
const struct hostapd_data *hapd,
logged_request_type type) {
struct os_reltime now, prev_logged_timestamp, new_timestamp;
@@ -102,33 +104,33 @@
strerror(errno));
return 0;
}
- if (!read_timestamp_file(mgmt, type, LOGGING_PATH, &prev_logged_timestamp) ||
+ if (!read_timestamp_file(mac, type, LOGGING_PATH, &prev_logged_timestamp) ||
os_reltime_expired(&now, &prev_logged_timestamp,
BANDSTEERING_EXPIRATION_SECONDS)) {
new_timestamp.sec = now.sec + BANDSTEERING_DELAY_SECONDS;
new_timestamp.usec = now.usec;
- if (!write_timestamp_file(mgmt, hapd, type, new_timestamp)) {
+ if (!write_timestamp_file(mac, hapd, type, &new_timestamp)) {
wpa_printf(MSG_ERROR, "Failed to write timestamp file.");
return 0;
} else {
wpa_printf(MSG_INFO, "Set timestamp for " MACSTR " (type=%d)",
- MAC2STR(mgmt->sa), type);
+ MAC2STR(mac), type);
return 1;
}
}
}
-int read_timestamp_file(const struct ieee80211_mgmt *mgmt,
+int read_timestamp_file(const u8 *mac,
logged_request_type type,
steering_path_type path_type,
struct os_reltime *timestamp) {
FILE *f;
char filename[1024];
- int success = 0;
+ int success = 1;
struct stat st;
os_time_t sec = 0, usec = 0;
- if (!get_timestamp_filename(mgmt, type, path_type, filename,
+ if (!get_timestamp_filename(mac, type, path_type, filename,
sizeof(filename))) {
return 0;
}
@@ -143,10 +145,11 @@
return 0;
}
- if (fscanf(f, "%d %d", ×tamp->sec, ×tamp->usec) != 2) {
- wpa_printf(MSG_ERROR, "fscanf from %s: %s", filename, strerror(errno));
- } else {
- success = 1;
+ if (timestamp) {
+ if (fscanf(f, "%d %d", ×tamp->sec, ×tamp->usec) != 2) {
+ wpa_printf(MSG_ERROR, "fscanf from %s: %s", filename, strerror(errno));
+ success = 0;
+ }
}
if (fclose(f) == EOF) {
@@ -157,6 +160,29 @@
return success;
}
+int delete_timestamp_file(const u8 *mac,
+ logged_request_type type,
+ steering_path_type path_type) {
+ char filename[1024];
+ struct stat st;
+
+ if (!get_timestamp_filename(mac, type, path_type, filename,
+ sizeof(filename))) {
+ return 0;
+ }
+
+ if (stat(filename, &st) == -1) {
+ return 1;
+ }
+
+ if (unlink(filename) == -1) {
+ wpa_printf(MSG_ERROR, "unlink(%s): %s", filename, strerror(errno));
+ return 0;
+ }
+
+ return 1;
+}
+
int file_ctime_lt(const struct dirent **a, const struct dirent **b) {
struct stat astat, bstat;
@@ -204,8 +230,7 @@
filename = namelist[i]->d_name;
if (filename[0] != '.' && !error) {
if (unlink(filename) == -1) {
- wpa_printf(MSG_ERROR, "unlink(%s): %s",
- unlink(filename), strerror(errno));
+ wpa_printf(MSG_ERROR, "unlink(%s): %s", filename, strerror(errno));
error = 1;
} else {
++num_timestamp_files_deleted;
diff --git a/src/ap/steering.h b/src/ap/steering.h
index 98b0c40..a17d79c 100644
--- a/src/ap/steering.h
+++ b/src/ap/steering.h
@@ -28,6 +28,7 @@
LOG_PROBE,
LOG_ASSOC,
LOG_BANDSTEERING_FAILED,
+ LOG_ASSOC_SUCCESSFUL,
NUM_LOGGED_REQUEST_TYPES } logged_request_type;
typedef enum {
LOGGING_PATH,
@@ -38,17 +39,17 @@
* Writes timestamp for the source address in mgmt to request_logging_path.
* Returns 1 if the write succeeded, 0 otherwise.
*/
-int write_timestamp_file(const struct ieee80211_mgmt *mgmt,
+int write_timestamp_file(const u8 *mac,
const struct hostapd_data *hapd,
logged_request_type type,
- const struct os_reltime timestamp);
+ const struct os_reltime *timestamp);
/**
* Calls write_timestamp_file unless there is an existing file younger than
* BANDSTEERING_EXPIRATION_SECONDS. Also garbage collects before writing.
* Returns 0 on write or garbage collection failure, 1 otherwise.
*/
-int maybe_write_timestamp_file(const struct ieee80211_mgmt *mgmt,
+int maybe_write_timestamp_file(const u8 *mac,
const struct hostapd_data *hapd,
logged_request_type type);
@@ -57,12 +58,21 @@
* (based on path) for the source address in mgmt, putting the result in
* timestamp. Returns 1 if the read succeeded, 0 otherwise.
*/
-int read_timestamp_file(const struct ieee80211_mgmt *mgmt,
+int read_timestamp_file(const u8 *mac,
logged_request_type type,
steering_path_type path_type,
struct os_reltime *timestamp);
/**
+ * Deletes a timestamp file from either request_logging_path or
+ * steering_timestamp_path (based on path) for the source address in mgmt.
+ * Returns 1 if the delete succeeded or the file does not exist, 0 otherwise.
+ */
+int delete_timestamp_file(const u8 *mac,
+ logged_request_type type,
+ steering_path_type path_type);
+
+/**
* Delete all but the most recent MAX_TIMESTAMP_FILES files of type LOG_PROBE in
* request_logging_path. Returns the number of files deleted.
*/