>From bddc0a23f7c6d72f944907c6eb5ca303d9c0b4af Mon Sep 17 00:00:00 2001 From: David Weidenkopf Date: Thu, 7 Jul 2016 14:11:43 -0700 Subject: [PATCH 1/3] WNM: hostapd client station blacklist support. New CLI commands to add, remove, clear, and show the blacklist. Signed-off-by: Henry M. Bennett Signed-off-by: Alexis Green Signed-off-by: David Weidenkopf --- hostapd/Makefile | 1 + hostapd/ctrl_iface.c | 18 ++++++ hostapd/hostapd_cli.c | 68 ++++++++++++++++++++++- 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 | 11 ++++ src/ap/sta_blacklist.c | 145 ++++++++++++++++++++++++++++++++++++++++++++++++ src/ap/sta_blacklist.h | 18 ++++++ wpa_supplicant/Makefile | 1 + 12 files changed, 342 insertions(+), 3 deletions(-) create mode 100644 src/ap/sta_blacklist.c create mode 100644 src/ap/sta_blacklist.h diff --git a/hostapd/Makefile b/hostapd/Makefile index ba094ba..6231d4a 100644 --- a/hostapd/Makefile +++ b/hostapd/Makefile @@ -86,6 +86,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 OBJS_c += ../src/common/wpa_ctrl.o diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index 5f3d6bd..7889283 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -2519,6 +2519,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( diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c index 04819d1..8b9d176 100644 --- a/hostapd/hostapd_cli.c +++ b/hostapd/hostapd_cli.c @@ -300,6 +300,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[]) { @@ -1122,7 +1181,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[]) { @@ -1271,6 +1329,14 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = { { "disassociate", hostapd_cli_cmd_disassociate, hostapd_complete_disassociate, " = disassociate a station" }, + { "blacklist_add", hostapd_cli_cmd_blacklist_add_hostapd, NULL, + " = blacklist a station from an AP" }, + { "blacklist_rm", hostapd_cli_cmd_blacklist_rm_hostapd, NULL, + " = remove a station from the blacklist" }, + { "blacklist_show", hostapd_cli_cmd_blacklist_show, NULL, + "show entire blacklist" }, + { "blacklist_clr", hostapd_cli_cmd_blacklist_clr_hostapd, NULL, + "clear all stations from the blacklist" }, #ifdef CONFIG_IEEE80211W { "sa_query", hostapd_cli_cmd_sa_query, NULL, " = send SA Query to a station" }, diff --git a/src/ap/beacon.c b/src/ap/beacon.c index 0a006f9..8d3d185 100644 --- a/src/ap/beacon.c +++ b/src/ap/beacon.c @@ -29,6 +29,7 @@ #include "beacon.h" #include "hs20.h" #include "dfs.h" +#include "sta_blacklist.h" #ifdef NEED_AP_MLME @@ -840,6 +841,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 */ diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c index 23c8c60..23e7d27 100644 --- a/src/ap/ctrl_iface_ap.c +++ b/src/ap/ctrl_iface_ap.c @@ -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, @@ -558,6 +558,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) diff --git a/src/ap/ctrl_iface_ap.h b/src/ap/ctrl_iface_ap.h index 6095d7d..346c6f3 100644 --- a/src/ap/ctrl_iface_ap.h +++ b/src/ap/ctrl_iface_ap.h @@ -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 */ diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index a09d423..a4c0d27 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -1840,6 +1840,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: diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index 195679e..a77c97f 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -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; @@ -304,6 +305,8 @@ struct hostapd_data { u8 range_req_token; unsigned int lci_req_active:1; unsigned int range_req_active:1; + + struct sta_blacklist *blacklist; /* Client station blacklist support */ }; diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index 2ecd78f..6c9b455 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -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" @@ -1045,6 +1046,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, mgmt->sa, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_INFO, + "authentication rejected due to blacklist"); + + resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; + goto fail; + } + if (hapd->tkip_countermeasures) { resp = WLAN_REASON_MICHAEL_MIC_FAILURE; goto fail; diff --git a/src/ap/sta_blacklist.c b/src/ap/sta_blacklist.c new file mode 100644 index 0000000..4ce1552 --- /dev/null +++ b/src/ap/sta_blacklist.c @@ -0,0 +1,145 @@ +/* FIX: copyright and license statements */ + +#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 || !sta) + 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) +{ + return sta_blacklist_get(hapd, sta) != NULL; +} + + +/** + * 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 || !sta) + return -1; + + e = sta_blacklist_get(hapd, sta); + if (e) + return 0; + + e = os_zalloc(sizeof(*e)); + if (!e) + 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 || !sta) + return -1; + + e = hapd->blacklist; + while (e) { + if (os_memcmp(e->sta, sta, ETH_ALEN) == 0) { + if (!prev) + 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)); + os_free(prev); + } + + return 0; +} diff --git a/src/ap/sta_blacklist.h b/src/ap/sta_blacklist.h new file mode 100644 index 0000000..6846c41 --- /dev/null +++ b/src/ap/sta_blacklist.h @@ -0,0 +1,18 @@ +/* FIX: copyright and license statements */ + +#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 */ diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile index f3e86c1..ee6e39b 100644 --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile @@ -847,6 +847,7 @@ OBJS += ../src/ap/bss_load.o OBJS += ../src/ap/eap_user_db.o OBJS += ../src/ap/neighbor_db.o OBJS += ../src/ap/rrm.o +OBJS += ../src/ap/sta_blacklist.o ifdef CONFIG_IEEE80211N OBJS += ../src/ap/ieee802_11_ht.o ifdef CONFIG_IEEE80211AC -- 1.9.1