From d3e1d069c2a8bb6201f8b20ce73df3d1c79e5ba7 Mon Sep 17 00:00:00 2001
From: Matteo Croce <matteo.croce@canonical.com>
Date: Thu, 23 Feb 2017 17:24:54 +0000
Subject: [PATCH] hostapd: add command to ban a station

When a station gets disassociated usually it will rejoin the AP.
Add a `ban' command that adds the station in the ACL exclude list
and disassociates it, to prevent it from automatically rejoin the AP.

Signed-off-by: Matteo Croce <matteo@openwrt.org>
---
 hostapd/config_file.c  |  8 --------
 hostapd/ctrl_iface.c   |  3 +++
 hostapd/hostapd_cli.c  | 20 ++++++++++++++++++++
 src/ap/ap_config.c     |  8 ++++++++
 src/ap/ap_config.h     |  1 +
 src/ap/ctrl_iface_ap.c | 28 ++++++++++++++++++++++++++++
 6 files changed, 60 insertions(+), 8 deletions(-)

diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 9e95440..d52b781 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -111,14 +111,6 @@ static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
 #endif /* CONFIG_NO_VLAN */
 
 
-static int hostapd_acl_comp(const void *a, const void *b)
-{
-	const struct mac_acl_entry *aa = a;
-	const struct mac_acl_entry *bb = b;
-	return os_memcmp(aa->addr, bb->addr, sizeof(macaddr));
-}
-
-
 static int hostapd_config_read_maclist(const char *fname,
 				       struct mac_acl_entry **acl, int *num)
 {
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 62feaa4..9aa70a9 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -2521,6 +2521,9 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
 	} else if (os_strncmp(buf, "POLL_STA ", 9) == 0) {
 		if (hostapd_ctrl_iface_poll_sta(hapd, buf + 9))
 			reply_len = -1;
+	} else if (os_strncmp(buf, "BAN ", 4) == 0) {
+		if (hostapd_ctrl_iface_ban(hapd, buf + 4))
+			reply_len = -1;
 	} else if (os_strcmp(buf, "STOP_AP") == 0) {
 		if (hostapd_ctrl_iface_stop_ap(hapd))
 			reply_len = -1;
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index f8d1eda..0f6472c 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -401,6 +401,23 @@ static int hostapd_cli_cmd_signature(struct wpa_ctrl *ctrl, int argc,
 #endif /* CONFIG_TAXONOMY */
 
 
+static int hostapd_cli_cmd_ban(struct wpa_ctrl *ctrl, int argc,
+					  char *argv[])
+{
+	char buf[64];
+	if (argc < 1) {
+		printf("Invalid 'ban' command - exactly one "
+		       "argument, STA address, is required.\n");
+		return -1;
+	}
+	if (argc > 1)
+		os_snprintf(buf, sizeof(buf), "BAN %s %s",
+			    argv[0], argv[1]);
+	else
+		os_snprintf(buf, sizeof(buf), "BAN %s", argv[0]);
+	return wpa_ctrl_command(ctrl, buf);
+}
+
 #ifdef CONFIG_IEEE80211W
 static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
 				    char *argv[])
@@ -1394,6 +1411,9 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
 	{ "disassociate", hostapd_cli_cmd_disassociate,
 	  hostapd_complete_stations,
 	  "<addr> = disassociate a station" },
+	{ "ban", hostapd_cli_cmd_ban,
+	  hostapd_complete_stations,
+	  "<addr> = ban a station" },
 #ifdef CONFIG_TAXONOMY
 	{ "signature", hostapd_cli_cmd_signature, hostapd_complete_stations,
 	  "<addr> = get taxonomy signature for a station" },
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 9abcab7..8c53cef 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -208,6 +208,14 @@ struct hostapd_config * hostapd_config_defaults(void)
 }
 
 
+int hostapd_acl_comp(const void *a, const void *b)
+{
+	const struct mac_acl_entry *aa = a;
+	const struct mac_acl_entry *bb = b;
+	return hostapd_mac_comp(aa->addr, bb->addr);
+}
+
+
 int hostapd_mac_comp(const void *a, const void *b)
 {
 	return os_memcmp(a, b, sizeof(macaddr));
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index fdd5a1a..b8d509d 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -760,6 +760,7 @@ struct hostapd_config {
 
 
 int hostapd_mac_comp(const void *a, const void *b);
+int hostapd_acl_comp(const void *a, const void *b);
 struct hostapd_config * hostapd_config_defaults(void);
 void hostapd_config_defaults_bss(struct hostapd_bss_config *bss);
 void hostapd_config_free_eap_user(struct hostapd_eap_user *user);
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index a760e3a..291b5ca 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -472,6 +472,34 @@ int hostapd_ctrl_iface_poll_sta(struct hostapd_data *hapd,
 	return 0;
 }
 
+int hostapd_ctrl_iface_ban(struct hostapd_data *hapd,
+			   const char *txtaddr)
+{
+	u8 addr[ETH_ALEN];
+	struct mac_acl_entry *acl = hapd->conf->deny_mac;
+	int num_acl = hapd->conf->num_deny_mac + 1;
+
+	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE BAN %s",
+		txtaddr);
+
+	if (hwaddr_aton(txtaddr, addr))
+		return -1;
+
+	acl = os_realloc_array(acl, num_acl, sizeof(*acl));
+	if(!acl)
+		return -ENOMEM;
+
+	hapd->conf->macaddr_acl = 0;
+
+	os_memcpy(acl[num_acl - 1].addr, addr, ETH_ALEN);
+	acl[num_acl - 1].vlan_id.notempty = 0;
+	qsort(acl, num_acl, sizeof(*acl), hostapd_acl_comp);
+
+	hapd->conf->deny_mac = acl;
+	hapd->conf->num_deny_mac = num_acl;
+
+	return hostapd_ctrl_iface_deauthenticate(hapd, txtaddr);
+}
 
 int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
 			      size_t buflen)
-- 
2.9.3

