@@ -592,6 +592,23 @@ static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
return -1;
}
+static int hostapd_cli_cmd_disconnect_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ char cmd[128];
+ int res;
+
+ if (argc != 1) {
+ printf("Invalid command: needs one argument, sta mac address \n");
+ return -1;
+ }
+
+ res = os_snprintf(cmd, sizeof(cmd), "DISCONNECT_STA %s ", argv[0]);
+ if (res < 0 || (size_t) res >= sizeof(cmd))
+ return -1;
+ cmd[sizeof(cmd) - 1] = '\0';
+
+ return wpa_ctrl_command(ctrl, cmd);
+}
static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
@@ -732,6 +749,7 @@ static struct hostapd_cli_cmd hostapd_cli_commands[] = {
{ "relog", hostapd_cli_cmd_relog },
{ "sta", hostapd_cli_cmd_sta },
{ "all_sta", hostapd_cli_cmd_all_sta },
+ { "disconnect_sta", hostapd_cli_cmd_disconnect_sta },
{ "new_sta", hostapd_cli_cmd_new_sta },
{ "deauthenticate", hostapd_cli_cmd_deauthenticate },
{ "disassociate", hostapd_cli_cmd_disassociate },
@@ -19,6 +19,7 @@
#include "ieee802_1x.h"
#include "wpa_auth.h"
#include "ieee802_11.h"
+#include "common/ieee802_11_defs.h"
#include "sta_info.h"
#include "wps_hostapd.h"
#include "p2p_hostapd.h"
@@ -106,3 +107,24 @@ int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr,
}
return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
}
+
+int hostapd_ctrl_iface_disconnect_sta(struct hostapd_data *hapd, const char *txtaddr,
+ char *buf, size_t buflen)
+{
+ u8 addr[ETH_ALEN];
+ struct sta_info *sta;
+ int ret;
+
+ if (hwaddr_aton(txtaddr, addr) ||
+ (sta = ap_get_sta(hapd, addr)) == NULL) {
+ wpa_printf(MSG_ERROR, "AP: Couldn't find sta_info for the "
+ "given mac_addr-"MACSTR, MAC2STR(addr));
+ ret = os_snprintf(buf, buflen, "FAIL\n");
+ if (ret < 0 || (size_t) ret >= buflen)
+ return 0;
+ return ret;
+ }
+ ap_sta_abrupt_disconnect(hapd->iface->bss[0], sta, addr,
+ WLAN_REASON_UNSPECIFIED);
+ return 0;
+}
@@ -21,5 +21,7 @@ int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr,
char *buf, size_t buflen);
int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr,
char *buf, size_t buflen);
+int hostapd_ctrl_iface_disconnect_sta(struct hostapd_data *hapd, const char *txtaddr,
+ char *buf, size_t buflen);
#endif /* CTRL_IFACE_AP_H */
@@ -827,6 +827,27 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
sta->addr, authorized);
}
+/* This call won't wait for the deauth callback. The sta_info for the sta
+ * is immediately removed after sending the deauth frame. This is required
+ * when sta is explicitly disconnected from AP/P2P Go side. We can't wait
+ * till AP_MAX_INACTIVITY_AFTER_DEAUTH to clear sta_info, because client
+ * may connect back before timer expiry. This is primarily intended for
+ * testing purpose to force disconnect a STA/P2P Client from AP/P2P GO side.
+*/
+void ap_sta_abrupt_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *addr, u16 reason) {
+
+ if (sta == NULL)
+ return;
+
+ if (addr)
+ hostapd_drv_sta_deauth(hapd, addr, reason);
+ ap_sta_set_authorized(hapd, sta, 0);
+ mlme_deauthenticate_indication(
+ hapd, sta, WLAN_REASON_PREV_AUTH_NOT_VALID);
+ ap_free_sta(hapd, sta);
+
+}
void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *addr, u16 reason)
@@ -159,6 +159,8 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta);
+void ap_sta_abrupt_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *addr, u16 reason);
void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *addr, u16 reason);
@@ -485,6 +485,12 @@ p2p_peer <P2P Device Address>
Fetch information about a known P2P peer.
+disconnect_sta <mac addr>
+
+Force disconnect a P2P Client from P2P GO. Note that the P2P Client may or
+may not connect back depending on how the CTRL-EVENT-DISCONNECTED is handled
+by the client side application. This is primarly intended for testing purpose.
+
Group Status
(These are used on the group interface.)
@@ -515,7 +521,6 @@ remove_network <network id>
Remove a network entry from configuration.
-
wpa_cli action script
---------------------
@@ -875,6 +875,14 @@ int ap_ctrl_iface_sta_next(struct wpa_supplicant *wpa_s, const char *txtaddr,
buf, buflen);
}
+int ap_ctrl_iface_disconnect_sta(struct wpa_supplicant *wpa_s, const char *txtaddr,
+ char *buf, size_t buflen)
+{
+ if (wpa_s->ap_iface == NULL)
+ return -1;
+ return hostapd_ctrl_iface_disconnect_sta(wpa_s->ap_iface->bss[0], txtaddr,
+ buf, buflen);
+}
int ap_ctrl_iface_wpa_get_status(struct wpa_supplicant *wpa_s, char *buf,
size_t buflen, int verbose)
@@ -37,6 +37,8 @@ int ap_ctrl_iface_sta(struct wpa_supplicant *wpa_s, const char *txtaddr,
char *buf, size_t buflen);
int ap_ctrl_iface_sta_next(struct wpa_supplicant *wpa_s, const char *txtaddr,
char *buf, size_t buflen);
+int ap_ctrl_iface_disconnect_sta(struct wpa_supplicant *wpa_s, const char *txtaddr,
+ char *buf, size_t buflen);
int ap_ctrl_iface_wpa_get_status(struct wpa_supplicant *wpa_s, char *buf,
size_t buflen, int verbose);
void ap_tx_status(void *ctx, const u8 *addr,
@@ -3673,6 +3673,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
reply_len = ap_ctrl_iface_sta_next(wpa_s, buf + 9, reply,
reply_size);
+ } else if (os_strncmp(buf, "DISCONNECT_STA ", 15) == 0) {
+ reply_len = ap_ctrl_iface_disconnect_sta(wpa_s, buf + 15, reply,
+ reply_size);
#endif /* CONFIG_AP */
} else if (os_strcmp(buf, "SUSPEND") == 0) {
wpas_notify_suspend(wpa_s->global);
@@ -1879,6 +1879,24 @@ static int wpa_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
return -1;
}
+
+static int wpa_cli_cmd_disconnect_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ char cmd[128];
+ int res;
+
+ if (argc != 1) {
+ printf("Invalid command: needs one argument, sta mac address \n");
+ return -1;
+ }
+
+ res = os_snprintf(cmd, sizeof(cmd), "DISCONNECT_STA %s ", argv[0]);
+ if (res < 0 || (size_t) res >= sizeof(cmd))
+ return -1;
+ cmd[sizeof(cmd) - 1] = '\0';
+
+ return wpa_ctrl_command(ctrl, cmd);
+}
#endif /* CONFIG_AP */
@@ -2911,6 +2929,9 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
{ "all_sta", wpa_cli_cmd_all_sta,
cli_cmd_flag_none,
"= get information about all associated stations (AP)" },
+ { "disconnect_sta", wpa_cli_cmd_disconnect_sta,
+ cli_cmd_flag_none,
+ "= disconnect a particluar STA" },
#endif /* CONFIG_AP */
{ "suspend", wpa_cli_cmd_suspend, cli_cmd_flag_none,
"= notification of suspend/hibernate" },