blob: 93ca4fd4db9be802f141fc50a6eec72d9c3916e2 [file] [log] [blame]
/*
* hostapd / Interface steering
* Copyright (c) 2015 Google, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "includes.h"
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include "common.h"
#include "common/defs.h"
#include "common/ieee802_11_defs.h"
#include "hostapd.h"
#include "steering.h"
static int get_timestamp_filename(const struct ieee80211_mgmt *mgmt,
const struct hostapd_data *hapd, char *buf,
size_t len) {
if (steering_timestamp_path == NULL) {
return 0;
}
if (os_snprintf(buf, len, "%s/" COMPACT_MACSTR ".%d",
steering_timestamp_path, MAC2STR(mgmt->sa),
hapd->iconf->hw_mode) < 0) {
wpa_printf(MSG_ERROR, "os_snprintf couldn't format filename: %s",
strerror(errno));
return 0;
}
return 1;
}
int write_timestamp_file(const struct ieee80211_mgmt *mgmt,
const struct hostapd_data *hapd,
const struct os_reltime timestamp) {
FILE *f;
char filename[1024], tmp_filename[1024];
int success = 0;
if (!get_timestamp_filename(mgmt, hapd, filename, sizeof(filename))) {
return 0;
}
/* Create a temporary filename to prevent multiple interfaces on the same band
* from touching each others' writes.
*/
if (os_snprintf(tmp_filename, sizeof(tmp_filename), "%s%s", filename,
os_strrchr(hapd->iface->config_fname, '.')) < 0) {
wpa_printf(MSG_ERROR, "os_snprintf couldn't format temp filename: %s",
strerror(errno));
}
if ((f = fopen(tmp_filename, "w")) == NULL) {
wpa_printf(MSG_ERROR, "fopen(%s) for write: %s", tmp_filename,
strerror(errno));
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 (fclose(f) == EOF) {
wpa_printf(MSG_ERROR, "fclose(%s): %s", tmp_filename, strerror(errno));
return 0;
}
if (rename(tmp_filename, filename) != 0) {
wpa_printf(MSG_ERROR, "rename(%s, %s): %s", tmp_filename, filename,
strerror(errno));
return 0;
}
return success;
}
int read_timestamp_file(const struct ieee80211_mgmt *mgmt,
const struct hostapd_data *hapd,
struct os_reltime *timestamp) {
FILE *f;
char filename[1024];
int success = 0;
struct stat st;
if (!get_timestamp_filename(mgmt, hapd, filename, sizeof(filename))) {
return 0;
}
if (stat(filename, &st) == -1) {
return 0;
}
f = fopen(filename, "r");
if (f == NULL) {
wpa_printf(MSG_ERROR, "open(%s) for read: %s", filename, strerror(errno));
return 0;
}
if (fscanf(f, "%d %d", &timestamp->sec, &timestamp->usec) < 0) {
wpa_printf(MSG_ERROR, "fscanf from %s: %s", filename, strerror(errno));
} else {
success = 1;
}
if (fclose(f) == EOF) {
wpa_printf(MSG_ERROR, "fclose(%s): %s", filename, strerror(errno));
return 0;
}
return success;
}
int file_ctime_lt(const struct dirent **a, const struct dirent **b) {
struct stat astat, bstat;
/* If we can't stat both of the files, give up and say they're equivalent. */
if (stat((*a)->d_name, &astat) == -1 || stat((*b)->d_name, &bstat) == -1) {
return 0;
}
return astat.st_ctime - bstat.st_ctime;
}
int garbage_collect_timestamp_files() {
int num_timestamp_files = 0, num_timestamp_files_deleted = 0, i = 0;
struct dirent **namelist;
char original_cwd[1024];
char *filename;
int error = 0;
if (getcwd(original_cwd, sizeof(original_cwd)) == NULL) {
wpa_printf(MSG_ERROR, "getcwd(): %s", strerror(errno));
return -1;
}
if (chdir(steering_timestamp_path) == -1) {
wpa_printf(MSG_ERROR, "chdir(%s): %s",
steering_timestamp_path, strerror(errno));
return -1;
}
num_timestamp_files = scandir(steering_timestamp_path, &namelist, NULL,
file_ctime_lt);
for (i = 0; i < num_timestamp_files; ++i) {
if (MAX_STEERING_TIMESTAMP_FILES <
/* The -2 is because scandir includes "." and "..". */
(num_timestamp_files - 2) - num_timestamp_files_deleted) {
filename = namelist[i]->d_name;
if (filename[0] != '.' && !error) {
if (unlink(filename) == -1) {
wpa_printf(MSG_ERROR, "unlink(%s): %s",
unlink(filename), strerror(errno));
error = 1;
} else {
++num_timestamp_files_deleted;
}
}
}
os_free(namelist[i]);
}
os_free(namelist);
if (chdir(original_cwd) == -1) {
wpa_printf(MSG_ERROR, "chdir(%s): %s", original_cwd, strerror(errno));
return -1;
}
return error ? -1 : num_timestamp_files_deleted;
}