From 709f5fdc2cf5bcb4660389fbe291192c349e9c9d Mon Sep 17 00:00:00 2001
From: David Weidenkopf <dweidenkopf@cococorp.com>
Date: Thu, 7 Jul 2016 14:11:43 -0700
Subject: [PATCH] WNM: hostapd client station blacklist support. New CLI
commands to add, remove, clear, and show the blacklist.
Signed-off-by: Henry M. Bennett <hbennett@cococorp.com>
Signed-off-by: Alexis Green <agreen@cococorp.com>
Signed-off-by: David Weidenkopf <dweidenkopf@cococorp.com>
---
hostapd/Makefile | 2 +-
hostapd/ctrl_iface.c | 18 +++++++
hostapd/hostapd_cli.c | 72 ++++++++++++++++++++++++-
src/ap/beacon.c | 6 +++
src/ap/ctrl_iface_ap.c | 65 ++++++++++++++++++++++-
src/ap/ctrl_iface_ap.h | 8 ++-
src/ap/hostapd.c | 1 +
src/ap/hostapd.h | 3 ++
src/ap/ieee802_11.c | 12 ++++-
src/ap/sta_blacklist.c | 140 +++++++++++++++++++++++++++++++++++++++++++++++++
src/ap/sta_blacklist.h | 14 +++++
11 files changed, 335 insertions(+), 6 deletions(-)
create mode 100644 src/ap/sta_blacklist.c
create mode 100644 src/ap/sta_blacklist.h
@@ -63,7 +63,6 @@ endif
OBJS += main.o
OBJS += config_file.o
-
OBJS += ../src/ap/hostapd.o
OBJS += ../src/ap/wpa_auth_glue.o
OBJS += ../src/ap/drv_callbacks.o
@@ -86,6 +85,7 @@ OBJS += ../src/ap/beacon.o
OBJS += ../src/ap/bss_load.o
OBJS += ../src/ap/neighbor_db.o
OBJS += ../src/ap/rrm.o
+OBJS += ../src/ap/sta_blacklist.o
OBJS_c = hostapd_cli.o ../src/common/wpa_ctrl.o ../src/utils/os_$(CONFIG_OS).o
@@ -2488,6 +2488,24 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
} else if (os_strncmp(buf, "LOG_LEVEL", 9) == 0) {
reply_len = hostapd_ctrl_iface_log_level(
hapd, buf + 9, reply, reply_size);
+ /* BEGIN HOSTAPD BLACKLIST SUPPORT */
+ } else if (os_strncmp(buf, "BLACKLIST_ADD ", 14) == 0) {
+ if (hostapd_ctrl_iface_blacklist_add(hapd, buf + 14))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "BLACKLIST_RM ", 13) == 0) {
+ if (hostapd_ctrl_iface_blacklist_rm(hapd, buf + 13))
+ reply_len = -1;
+ } else if (os_strcmp(buf, "BLACKLIST_SHOW") == 0) {
+ reply_len = hostapd_ctrl_iface_blacklist_show(hapd, reply,
+ reply_size);
+ if(reply_len == 0) {
+ os_memcpy(reply, "EMPTY\n", 6);
+ reply_len = 6;
+ }
+ } else if (os_strcmp(buf, "BLACKLIST_CLR") == 0) {
+ if(hostapd_ctrl_iface_blacklist_clr(hapd))
+ reply_len = -1;
+ /* END HOSTAPD BLACKLIST SUPPORT */
#ifdef NEED_AP_MLME
} else if (os_strcmp(buf, "TRACK_STA_LIST") == 0) {
reply_len = hostapd_ctrl_iface_track_sta_list(
@@ -65,6 +65,11 @@ static const char *const commands_help =
" all_sta get MIB variables for all stations\n"
" new_sta <addr> add a new station\n"
" deauthenticate <addr> deauthenticate a station\n"
+" blacklist_add <addr> blacklist a station from an AP\n"
+" blacklist_rm <addr> remove a station from the blacklist\n"
+" blacklist_clr clear all stations from the blacklist\n"
+" blacklist_show show entire blacklist\n"
+" bss_transition <addr> <beacon timer count> <AP addr> <AP channel> disassociate a WNM station telling the station which AP to connect to\n"
" disassociate <addr> disassociate a station\n"
#ifdef CONFIG_IEEE80211W
" sa_query <addr> send SA Query to a station\n"
@@ -351,7 +356,6 @@ static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
return wpa_ctrl_command(ctrl, buf);
}
-
static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -366,6 +370,65 @@ static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
}
+/* BEGIN HOSTAPD BLACKLIST SUPPORT */
+static int hostapd_cli_cmd_blacklist_add_hostapd(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char buf[64];
+
+ if (argc != 1) {
+ printf("Invalid 'blacklist_add_hostapd' command - exactly one argument, STA address, is required.\n");
+ return -1;
+ }
+
+ os_snprintf(buf, sizeof(buf), "BLACKLIST_ADD %s", argv[0]);
+ return wpa_ctrl_command(ctrl, buf);
+}
+
+static int hostapd_cli_cmd_blacklist_rm_hostapd(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char buf[64];
+
+ if (argc != 1) {
+ printf("Invalid 'blacklist_rm_hostapd' command - exactly one argument, STA address, is required.\n");
+ return -1;
+ }
+
+ os_snprintf(buf, sizeof(buf), "BLACKLIST_RM %s", argv[0]);
+ return wpa_ctrl_command(ctrl, buf);
+}
+
+static int hostapd_cli_cmd_blacklist_show(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char buf[64];
+
+ if (argc > 0) {
+ printf("Invalid 'blacklist_show' command - this command takes no arguments.\n");
+ return -1;
+ }
+
+ os_snprintf(buf, sizeof(buf), "BLACKLIST_SHOW");
+ return wpa_ctrl_command(ctrl, buf);
+}
+
+static int hostapd_cli_cmd_blacklist_clr_hostapd(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char buf[64];
+
+ if (argc != 0) {
+ printf("Invalid 'blacklist_add_hostapd' command - exactly zero arguments is required.\n");
+ return -1;
+ }
+
+ os_snprintf(buf, sizeof(buf), "BLACKLIST_CLR");
+ return wpa_ctrl_command(ctrl, buf);
+}
+
+/* END HOSTAPD BLACKLIST SUPPORT */
+
static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -1102,7 +1165,6 @@ static int hostapd_cli_cmd_erp_flush(struct wpa_ctrl *ctrl, int argc,
return wpa_ctrl_command(ctrl, "ERP_FLUSH");
}
-
static int hostapd_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -1233,6 +1295,12 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
{ "new_sta", hostapd_cli_cmd_new_sta },
{ "deauthenticate", hostapd_cli_cmd_deauthenticate },
{ "disassociate", hostapd_cli_cmd_disassociate },
+
+ { "blacklist_add", hostapd_cli_cmd_blacklist_add_hostapd },
+ { "blacklist_rm", hostapd_cli_cmd_blacklist_rm_hostapd },
+ { "blacklist_show", hostapd_cli_cmd_blacklist_show },
+ { "blacklist_clr", hostapd_cli_cmd_blacklist_clr_hostapd },
+
#ifdef CONFIG_IEEE80211W
{ "sa_query", hostapd_cli_cmd_sa_query },
#endif /* CONFIG_IEEE80211W */
@@ -29,6 +29,7 @@
#include "beacon.h"
#include "hs20.h"
#include "dfs.h"
+#include "sta_blacklist.h"
#ifdef NEED_AP_MLME
@@ -838,6 +839,11 @@ void handle_probe_req(struct hostapd_data *hapd,
}
#endif /* CONFIG_P2P */
+ if(sta_blacklist_present(hapd, mgmt->sa)) {
+ wpa_printf(MSG_DEBUG, "ignoring probe request from " MACSTR " due to blacklist", MAC2STR(mgmt->sa));
+ return;
+ }
+
/* TODO: verify that supp_rates contains at least one matching rate
* with AP configuration */
@@ -23,7 +23,7 @@
#include "ctrl_iface_ap.h"
#include "ap_drv_ops.h"
#include "mbo_ap.h"
-
+#include "sta_blacklist.h"
static int hostapd_get_sta_tx_rx(struct hostapd_data *hapd,
struct sta_info *sta,
@@ -550,6 +550,69 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
return len;
}
+int hostapd_ctrl_iface_blacklist_add(struct hostapd_data *hapd,
+ const char *txtaddr)
+{
+ u8 addr[ETH_ALEN];
+ int ret = -1;
+
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE BLACKLIST_ADD %s",
+ txtaddr);
+
+ if (hwaddr_aton(txtaddr, addr))
+ return -1;
+
+ ret = sta_blacklist_add(hapd, addr);
+
+ return ret;
+}
+
+int hostapd_ctrl_iface_blacklist_rm(struct hostapd_data *hapd,
+ const char *txtaddr)
+{
+ u8 addr[ETH_ALEN];
+ int ret = -1;
+
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE BLACKLIST_RM %s",
+ txtaddr);
+
+ if (hwaddr_aton(txtaddr, addr))
+ return -1;
+
+ ret = sta_blacklist_rm(hapd, addr);
+
+ return ret;
+}
+
+int hostapd_ctrl_iface_blacklist_show(struct hostapd_data *hapd, char *buf,
+ size_t buflen)
+{
+ int len = 0, ret = 0;
+ struct sta_blacklist *e = hapd->blacklist;
+
+ while (e) {
+ ret = os_snprintf(buf + len, buflen - len,
+ MACSTR "\n",
+ MAC2STR(e->sta));
+ if (ret < 0 || (size_t) ret >= buflen - len)
+ return len;
+ len += ret;
+ e = e->next;
+ }
+
+ return ret;
+}
+
+int hostapd_ctrl_iface_blacklist_clr(struct hostapd_data *hapd)
+{
+ int ret = -1;
+
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE BLACKLIST_CLR");
+
+ ret = sta_blacklist_clear(hapd);
+
+ return ret;
+}
int hostapd_parse_csa_settings(const char *pos,
struct csa_settings *settings)
@@ -29,5 +29,11 @@ int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd);
int hostapd_ctrl_iface_pmksa_list(struct hostapd_data *hapd, char *buf,
size_t len);
void hostapd_ctrl_iface_pmksa_flush(struct hostapd_data *hapd);
-
+int hostapd_ctrl_iface_blacklist_add(struct hostapd_data *hapd,
+ const char *txtaddr);
+int hostapd_ctrl_iface_blacklist_rm(struct hostapd_data *hapd,
+ const char *txtaddr);
+int hostapd_ctrl_iface_blacklist_show(struct hostapd_data *hapd, char *buf,
+ size_t buflen);
+int hostapd_ctrl_iface_blacklist_clr(struct hostapd_data *hapd);
#endif /* CTRL_IFACE_AP_H */
@@ -1839,6 +1839,7 @@ dfs_offload:
for (j = 0; j < iface->num_bss; j++)
hostapd_set_own_neighbor_report(iface->bss[j]);
+ hapd->blacklist = NULL;
return 0;
fail:
@@ -19,6 +19,7 @@ struct radius_server_data;
struct upnp_wps_device_sm;
struct hostapd_data;
struct sta_info;
+struct sta_blacklist;
struct ieee80211_ht_capabilities;
struct full_dynamic_vlan;
enum wps_event;
@@ -120,6 +121,8 @@ struct hostapd_data {
struct hostapd_bss_config *conf;
int interface_added; /* virtual interface added for this BSS */
unsigned int started:1;
+ /* Client station blacklist support */
+ struct sta_blacklist *blacklist;
unsigned int disabled:1;
unsigned int reenable_beacon:1;
@@ -28,6 +28,7 @@
#include "beacon.h"
#include "ieee802_11_auth.h"
#include "sta_info.h"
+#include "sta_blacklist.h"
#include "ieee802_1x.h"
#include "wpa_auth.h"
#include "pmksa_cache_auth.h"
@@ -944,7 +945,6 @@ remove_sta:
wpabuf_free(data);
}
-
/**
* auth_sae_init_committed - Send COMMIT and start SAE in committed state
* @hapd: BSS data for the device initiating the authentication
@@ -1045,6 +1045,16 @@ static void handle_auth(struct hostapd_data *hapd,
}
#endif /* CONFIG_NO_RC4 */
+ // Check for existence in blacklist
+ if(sta_blacklist_present(hapd, mgmt->sa)) {
+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO, "auth failed from " MACSTR " due to blacklist", MAC2STR(mgmt->sa));
+
+ resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
+ goto fail;
+ }
+
+
if (hapd->tkip_countermeasures) {
resp = WLAN_REASON_MICHAEL_MIC_FAILURE;
goto fail;
new file mode 100644
@@ -0,0 +1,140 @@
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "eapol_auth/eapol_auth_sm.h"
+#include "hostapd.h"
+#include "ieee802_1x.h"
+#include "wpa_auth.h"
+#include "ieee802_11.h"
+#include "sta_info.h"
+#include "sta_blacklist.h"
+
+/**
+ * sta_blacklist_get - Get the blacklist entry for a BSSID
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID
+ * Returns: Matching blacklist entry for the BSSID or %NULL if not found
+ */
+struct sta_blacklist * sta_blacklist_get(struct hostapd_data *hapd, const u8 *sta) {
+ struct sta_blacklist *e;
+
+ if (hapd == NULL || sta == NULL)
+ return NULL;
+
+ e = hapd->blacklist;
+ while (e) {
+ if (os_memcmp(e->sta, sta, ETH_ALEN) == 0)
+ return e;
+ e = e->next;
+ }
+
+ return NULL;
+}
+
+int sta_blacklist_present(struct hostapd_data *hapd, const u8 *sta)
+{
+ if(sta_blacklist_get(hapd, sta) != NULL)
+ return 1;
+
+ return 0;
+}
+
+
+
+/**
+ * wpa_blacklist_add - Add an BSSID to the blacklist
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID to be added to the blacklist
+ * Returns: Current blacklist count on success, -1 on failure
+ *
+ * This function adds the specified BSSID to the blacklist or increases the
+ * blacklist count if the BSSID was already listed. It should be called when
+ * an association attempt fails either due to the selected BSS rejecting
+ * association or due to timeout.
+ *
+ * This blacklist is used to force %wpa_supplicant to go through all available
+ * BSSes before retrying to associate with an BSS that rejected or timed out
+ * association. It does not prevent the listed BSS from being used; it only
+ * changes the order in which they are tried.
+ */
+int sta_blacklist_add(struct hostapd_data *hapd, const u8 *sta) {
+ struct sta_blacklist *e;
+
+ if (hapd == NULL || sta == NULL)
+ return -1;
+
+ e = sta_blacklist_get(hapd, sta);
+ if (e) {
+ return 0;
+ }
+
+ e = os_zalloc(sizeof(*e));
+ if (e == NULL)
+ return -1;
+ os_memcpy(e->sta, sta, ETH_ALEN);
+
+
+ e->next = hapd->blacklist;
+ hapd->blacklist = e;
+
+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO, "Added BSSID " MACSTR " into blacklist", MAC2STR(sta));
+
+ return 0;
+}
+
+/**
+ * wpa_blacklist_del - Remove an BSSID from the blacklist
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID to be removed from the blacklist
+ * Returns: 0 on success, -1 on failure
+ */
+int sta_blacklist_rm(struct hostapd_data *hapd, const u8 *sta) {
+ struct sta_blacklist *e, *prev = NULL;
+
+ if (hapd == NULL || sta == NULL)
+ return -1;
+
+ e = hapd->blacklist;
+ while (e) {
+ if (os_memcmp(e->sta, sta, ETH_ALEN) == 0) {
+ if (prev == NULL) {
+ hapd->blacklist = e->next;
+ } else {
+ prev->next = e->next;
+ }
+
+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO, "Removed BSSID " MACSTR " from blacklist", MAC2STR(sta));
+
+ os_free(e);
+
+ return 0;
+ }
+ prev = e;
+ e = e->next;
+ }
+ return -1;
+}
+
+/**
+ * wpa_blacklist_clear - Clear the blacklist of all entries
+ * @wpa_s: Pointer to wpa_supplicant data
+ */
+int sta_blacklist_clear(struct hostapd_data *hapd) {
+ struct sta_blacklist *e, *prev;
+
+ e = hapd->blacklist;
+ hapd->blacklist = NULL;
+ while (e) {
+ prev = e;
+ e = e->next;
+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO, "Removed BSSID " MACSTR " from blacklist", MAC2STR(prev->sta));
+ //wpa_printf(MSG_ERROR, "Removed BSSID " MACSTR " from blacklist (clear)", MAC2STR(prev->sta));
+ os_free(prev);
+ }
+
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,14 @@
+#ifndef STA_BLACKLIST_H
+#define STA_BLACKLIST_H
+
+struct sta_blacklist {
+ struct sta_blacklist *next;
+ u8 sta[ETH_ALEN];
+};
+
+struct sta_blacklist * sta_blacklist_get(struct hostapd_data *hapd, const u8 *sta);
+int sta_blacklist_present(struct hostapd_data *hapd, const u8 *sta);
+int sta_blacklist_add(struct hostapd_data *hapd, const u8 *sta);
+int sta_blacklist_rm(struct hostapd_data *hapd, const u8 *sta);
+int sta_blacklist_clear(struct hostapd_data *hapd);
+#endif /* STA_BLACKLIST_H */
--
1.9.1