diff mbox

Force disconnect a P2P Client/STA from GO/AP side

Message ID 0BED5F74AB839C4796CA2BFC2BC311B419C4330443@SJEXCHCCR01.corp.ad.broadcom.com
State Accepted
Commit e60b295186f5a70ab066eb35c4cea0153f54976c
Headers show

Commit Message

Jithu Jance Dec. 20, 2011, 12:15 p.m. UTC
Hi Jouni,

> Why would a new command be needed for this? hostapd already has
> deauthenticate and disassociate ctrl_iface commands.

The command that I added is slightly different in functionality. New command will send disassociate req and
then remove sta_info abruptly without waiting to remove sta_info on ap_handle_timer. Few days back while testing
I saw that STA/P2P client state is showing inconsistent assoc status with normal disassociate cmd. This
is mostly seen when P2P Client/STA connects back before or during the ap_handle_timer INACTIVITY timeout. In this
scenario, AP shows the STA as disconnected, but the STA shows as associated. Seems like in those cases, the deauth
Frame was not been received by STA. With latest hostap code, I am unable to see this issue. Of course, it disconnects two times
on issuing disassociate (One on sending the disassoc frame and then on the inactivity timeout [sending deauth frame]).
Both AP and STA states are consistent. I will get back to you, if I could reproduce this inconsistent behavior and find the root cause.


> Those deauth/disassoc commands should be used rather than adding a new
> command. Sure, they would need to be moved from hostapd/ctrl_iface.c to
> src/ap/ctrl_iface_ap.c, but that is better than introducing duplicated
> functionality.

Yes, these commands need to be available for wpa_cli as well. Attaching the patch for the same below. Please see whether
the patch is okay.


[PATCH] Move disassociate, deauthenticate commands to ctrl_iface_ap.c so that
 it is accessible for wpa_cli(with CONFIG_AP option enabled).

 Signed-hostap: Jithu Jance <jithu@broadcom.com>

---
 hostapd/ctrl_iface.c     |  113 ---------------------------------------------
 src/ap/ctrl_iface_ap.c   |  114 ++++++++++++++++++++++++++++++++++++++++++++++
 src/ap/ctrl_iface_ap.h   |    5 ++-
 wpa_supplicant/ap.c      |   17 +++++++
 wpa_supplicant/ap.h      |    4 ++
 wpa_supplicant/wpa_cli.c |   40 ++++++++++++++++
 6 files changed, 179 insertions(+), 114 deletions(-)

--
1.7.4.1




- Jithu Jance


-----Original Message-----
From: hostap-bounces@lists.shmoo.com [mailto:hostap-bounces@lists.shmoo.com] On Behalf Of Jouni Malinen
Sent: Saturday, December 17, 2011 9:47 PM
To: hostap@lists.shmoo.com
Subject: Re: [PATCH] Force disconnect a P2P Client/STA from GO/AP side

On Wed, Dec 14, 2011 at 06:12:49AM -0800, Jithu Jance wrote:
> This patch adds a new command "disconnect_sta <mac addr>" to force disconnect
> a STA/P2P Client from AP/P2P GO side. Note that P2P Client/STA may connect back
> immediately since AP profile may not be disabled at the client/STA side. Currently, this
> is primarily useful for testing purposes.

Why would a new command be needed for this? hostapd already has
deauthenticate and disassociate ctrl_iface commands. Wouldn't one of
those be suitable for this need, too?

> This will be much more useful in scenarios where client side doesn't reconnect back (after disconnection).
> This will allow the applications to tear-down connections from the P2P-GO side as well.
> For e.g, if mobile acts a GO and it has around 2-3 connections, this cmd will allow to
> explicitly tear down a particular client from GO side. But again, this depends on the client side
> application framework. For temporary connections such as WiFi-Direct where roaming
> cases are extremely rare, Client side application framework may choose to disable P2P
> Client interface on getting the CTRL-EVENT-DISCONNECTED event rather than retrying
> to connect.

This does not sound like something that I would trust on. If the needed
functionality is to kick a P2P client away from the group, that client
would need to be prevented from reconnecting. Just sending a
Deauthentication frame to it does not guarantee anything. And well, even
this is not really suitable from the security view point if the stations
in the group share the same PSK. Unfortunately, P2P specification does
not provide a very good mechanism for handling this type of operations
reliably.

> diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
> index 527860c..5eeefea 100644
> --- a/hostapd/hostapd_cli.c
> +++ b/hostapd/hostapd_cli.c
> @@ -732,6 +749,7 @@ static struct hostapd_cli_cmd hostapd_cli_commands[] = {
> +     { "disconnect_sta", hostapd_cli_cmd_disconnect_sta },
>       { "new_sta", hostapd_cli_cmd_new_sta },
>       { "deauthenticate", hostapd_cli_cmd_deauthenticate },
>       { "disassociate", hostapd_cli_cmd_disassociate },

Those deauth/disassoc commands should be used rather than adding a new
command. Sure, they would need to be moved from hostapd/ctrl_iface.c to
src/ap/ctrl_iface_ap.c, but that is better than introducing duplicated
functionality.

--
Jouni Malinen                                            PGP id EFC895FA

Comments

Jouni Malinen Feb. 25, 2012, 3:27 p.m. UTC | #1
On Tue, Dec 20, 2011 at 04:15:41AM -0800, Jithu Jance wrote:
> The command that I added is slightly different in functionality. New command will send disassociate req and
> then remove sta_info abruptly without waiting to remove sta_info on ap_handle_timer. Few days back while testing
> I saw that STA/P2P client state is showing inconsistent assoc status with normal disassociate cmd. This
> is mostly seen when P2P Client/STA connects back before or during the ap_handle_timer INACTIVITY timeout. In this
> scenario, AP shows the STA as disconnected, but the STA shows as associated. Seems like in those cases, the deauth
> Frame was not been received by STA. With latest hostap code, I am unable to see this issue. Of course, it disconnects two times
> on issuing disassociate (One on sending the disassoc frame and then on the inactivity timeout [sending deauth frame]).
> Both AP and STA states are consistent. I will get back to you, if I could reproduce this inconsistent behavior and find the root cause.

If this issue shows up with the existing deauthenticate/disassociate
commands in hostapd, those commands need to be fixed. This area should
be identical between hostapd and wpa_supplicant AP mode operations.

> Yes, these commands need to be available for wpa_cli as well. Attaching the patch for the same below. Please see whether
> the patch is okay.
> 
> 
> [PATCH] Move disassociate, deauthenticate commands to ctrl_iface_ap.c so that
>  it is accessible for wpa_cli(with CONFIG_AP option enabled).

This missed the needed changes in wpa_supplicant/ctrl_iface.c for the
new commands and broke hostapd build. I fixed those and applied a
cleaned up version of the patch.
Jithu Jance Feb. 29, 2012, 1:14 p.m. UTC | #2
>>  The command that I added is slightly different in functionality. New
command will send disassociate req and
>> then remove sta_info abruptly without waiting to remove sta_info on
ap_handle_timer. Few days back while testing
>> I saw that STA/P2P client state is showing inconsistent assoc status
with normal disassociate cmd. This
>> is mostly seen when P2P Client/STA connects back before or during the
ap_handle_timer INACTIVITY timeout. In this
>> scenario, AP shows the STA as disconnected, but the STA shows as
associated. Seems like in those cases, the deauth
>> Frame was not been received by STA. With latest hostap code, I am unable
to see this issue. Of course, it disconnects two times
>> on issuing disassociate (One on sending the disassoc frame and then on
the inactivity timeout [sending deauth frame]).
>> Both AP and STA states are consistent. I will get back to you, if I
could reproduce this inconsistent behavior and find the root cause.
Didn't get a chance to further test this. If i come across similar
issue, i will update you.

> This missed the needed changes in wpa_supplicant/ctrl_iface.c
Looks like i missed the build before patch generation. Really sorry about
this and
 thanks for being kind enough to fix it.




- Jithu Jance* *


On Sat, Feb 25, 2012 at 8:57 PM, Jouni Malinen <j@w1.fi> wrote:

> On Tue, Dec 20, 2011 at 04:15:41AM -0800, Jithu Jance wrote:
> > The command that I added is slightly different in functionality. New
> command will send disassociate req and
> > then remove sta_info abruptly without waiting to remove sta_info on
> ap_handle_timer. Few days back while testing
> > I saw that STA/P2P client state is showing inconsistent assoc status
> with normal disassociate cmd. This
> > is mostly seen when P2P Client/STA connects back before or during the
> ap_handle_timer INACTIVITY timeout. In this
> > scenario, AP shows the STA as disconnected, but the STA shows as
> associated. Seems like in those cases, the deauth
> > Frame was not been received by STA. With latest hostap code, I am unable
> to see this issue. Of course, it disconnects two times
> > on issuing disassociate (One on sending the disassoc frame and then on
> the inactivity timeout [sending deauth frame]).
> > Both AP and STA states are consistent. I will get back to you, if I
> could reproduce this inconsistent behavior and find the root cause.
>
> If this issue shows up with the existing deauthenticate/disassociate
> commands in hostapd, those commands need to be fixed. This area should
> be identical between hostapd and wpa_supplicant AP mode operations.
>
> > Yes, these commands need to be available for wpa_cli as well. Attaching
> the patch for the same below. Please see whether
> > the patch is okay.
> >
> >
> > [PATCH] Move disassociate, deauthenticate commands to ctrl_iface_ap.c so
> that
> >  it is accessible for wpa_cli(with CONFIG_AP option enabled).
>
> This missed the needed changes in wpa_supplicant/ctrl_iface.c for the
> new commands and broke hostapd build. I fixed those and applied a
> cleaned up version of the patch.
>
> --
> Jouni Malinen                                            PGP id EFC895FA
> _______________________________________________
> HostAP mailing list
> HostAP@lists.shmoo.com
> http://lists.shmoo.com/mailman/listinfo/hostap
>
diff mbox

Patch

diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index a38d77c..6c08a3f 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -211,119 +211,6 @@  static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
 #endif /* CONFIG_P2P_MANAGER */


-static int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
-                                            const char *txtaddr)
-{
-       u8 addr[ETH_ALEN];
-       struct sta_info *sta;
-       const char *pos;
-
-       wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s",
-               txtaddr);
-
-       if (hwaddr_aton(txtaddr, addr))
-               return -1;
-
-       pos = os_strstr(txtaddr, " test=");
-       if (pos) {
-               struct ieee80211_mgmt mgmt;
-               int encrypt;
-               if (hapd->driver->send_frame == NULL)
-                       return -1;
-               pos += 6;
-               encrypt = atoi(pos);
-               os_memset(&mgmt, 0, sizeof(mgmt));
-               mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-                                                 WLAN_FC_STYPE_DEAUTH);
-               os_memcpy(mgmt.da, addr, ETH_ALEN);
-               os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
-               os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
-               mgmt.u.deauth.reason_code =
-                       host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
-               if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
-                                            IEEE80211_HDRLEN +
-                                            sizeof(mgmt.u.deauth),
-                                            encrypt) < 0)
-                       return -1;
-               return 0;
-       }
-
-#ifdef CONFIG_P2P_MANAGER
-       pos = os_strstr(txtaddr, " p2p=");
-       if (pos) {
-               return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DEAUTH,
-                                             atoi(pos + 5), addr);
-       }
-#endif /* CONFIG_P2P_MANAGER */
-
-       hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
-       sta = ap_get_sta(hapd, addr);
-       if (sta)
-               ap_sta_deauthenticate(hapd, sta,
-                                     WLAN_REASON_PREV_AUTH_NOT_VALID);
-       else if (addr[0] == 0xff)
-               hostapd_free_stas(hapd);
-
-       return 0;
-}
-
-
-static int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
-                                          const char *txtaddr)
-{
-       u8 addr[ETH_ALEN];
-       struct sta_info *sta;
-       const char *pos;
-
-       wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s",
-               txtaddr);
-
-       if (hwaddr_aton(txtaddr, addr))
-               return -1;
-
-       pos = os_strstr(txtaddr, " test=");
-       if (pos) {
-               struct ieee80211_mgmt mgmt;
-               int encrypt;
-               if (hapd->driver->send_frame == NULL)
-                       return -1;
-               pos += 6;
-               encrypt = atoi(pos);
-               os_memset(&mgmt, 0, sizeof(mgmt));
-               mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-                                                 WLAN_FC_STYPE_DISASSOC);
-               os_memcpy(mgmt.da, addr, ETH_ALEN);
-               os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
-               os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
-               mgmt.u.disassoc.reason_code =
-                       host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
-               if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
-                                            IEEE80211_HDRLEN +
-                                            sizeof(mgmt.u.deauth),
-                                            encrypt) < 0)
-                       return -1;
-               return 0;
-       }
-
-#ifdef CONFIG_P2P_MANAGER
-       pos = os_strstr(txtaddr, " p2p=");
-       if (pos) {
-               return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DISASSOC,
-                                             atoi(pos + 5), addr);
-       }
-#endif /* CONFIG_P2P_MANAGER */
-
-       hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
-       sta = ap_get_sta(hapd, addr);
-       if (sta)
-               ap_sta_disassociate(hapd, sta,
-                                   WLAN_REASON_PREV_AUTH_NOT_VALID);
-       else if (addr[0] == 0xff)
-               hostapd_free_stas(hapd);
-
-       return 0;
-}
-

 #ifdef CONFIG_IEEE80211W
 #ifdef NEED_AP_MLME
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index d348dc1..e8e24ae 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -17,12 +17,14 @@ 
 #include "utils/common.h"
 #include "hostapd.h"
 #include "ieee802_1x.h"
+#include "common/ieee802_11_defs.h"
 #include "wpa_auth.h"
 #include "ieee802_11.h"
 #include "sta_info.h"
 #include "wps_hostapd.h"
 #include "p2p_hostapd.h"
 #include "ctrl_iface_ap.h"
+#include "ap_drv_ops.h"


 static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
@@ -106,3 +108,115 @@  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_sta_deauthenticate(struct hostapd_data *hapd,
+                                             const char *txtaddr, char *buf, size_t buflen)
+{
+        u8 addr[ETH_ALEN];
+        struct sta_info *sta;
+        const char *pos;
+
+        wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s",
+                txtaddr);
+
+        if (hwaddr_aton(txtaddr, addr))
+                return -1;
+
+        pos = os_strstr(txtaddr, " test=");
+        if (pos) {
+                struct ieee80211_mgmt mgmt;
+                int encrypt;
+                if (hapd->driver->send_frame == NULL)
+                        return -1;
+                pos += 6;
+                encrypt = atoi(pos);
+                os_memset(&mgmt, 0, sizeof(mgmt));
+                mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+                                                  WLAN_FC_STYPE_DEAUTH);
+                os_memcpy(mgmt.da, addr, ETH_ALEN);
+                os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
+                os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
+                mgmt.u.deauth.reason_code =
+                        host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
+                if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
+                                             IEEE80211_HDRLEN +
+                                             sizeof(mgmt.u.deauth),
+                                             encrypt) < 0)
+                        return -1;
+                return 0;
+        }
+
+#ifdef CONFIG_P2P_MANAGER
+        pos = os_strstr(txtaddr, " p2p=");
+        if (pos) {
+                return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DEAUTH,
+                                              atoi(pos + 5), addr);
+        }
+#endif /* CONFIG_P2P_MANAGER */
+
+        hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
+        sta = ap_get_sta(hapd, addr);
+        if (sta)
+                ap_sta_deauthenticate(hapd, sta,
+                                      WLAN_REASON_PREV_AUTH_NOT_VALID);
+        else if (addr[0] == 0xff)
+               hostapd_free_stas(hapd);
+
+        return 0;
+}
+
+int hostapd_ctrl_iface_sta_disassociate(struct hostapd_data *hapd,
+                                           const char *txtaddr, char *buf, size_t buflen)
+{
+        u8 addr[ETH_ALEN];
+        struct sta_info *sta;
+        const char *pos;
+
+        wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s",
+                txtaddr);
+
+        if (hwaddr_aton(txtaddr, addr))
+                return -1;
+
+        pos = os_strstr(txtaddr, " test=");
+        if (pos) {
+                struct ieee80211_mgmt mgmt;
+                int encrypt;
+                if (hapd->driver->send_frame == NULL)
+                        return -1;
+                pos += 6;
+                encrypt = atoi(pos);
+                os_memset(&mgmt, 0, sizeof(mgmt));
+                mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+                                                  WLAN_FC_STYPE_DISASSOC);
+                os_memcpy(mgmt.da, addr, ETH_ALEN);
+                os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
+                os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
+                mgmt.u.disassoc.reason_code =
+                        host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
+                if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
+                                             IEEE80211_HDRLEN +
+                                             sizeof(mgmt.u.deauth),
+                                             encrypt) < 0)
+                        return -1;
+                return 0;
+        }
+
+#ifdef CONFIG_P2P_MANAGER
+        pos = os_strstr(txtaddr, " p2p=");
+        if (pos) {
+                return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DISASSOC,
+                                              atoi(pos + 5), addr);
+        }
+#endif /* CONFIG_P2P_MANAGER */
+
+        hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
+        sta = ap_get_sta(hapd, addr);
+        if (sta)
+                ap_sta_disassociate(hapd, sta,
+                                    WLAN_REASON_PREV_AUTH_NOT_VALID);
+        else if (addr[0] == 0xff)
+               hostapd_free_stas(hapd);
+
+        return 0;
+}
diff --git a/src/ap/ctrl_iface_ap.h b/src/ap/ctrl_iface_ap.h
index 8690bea..5c534ec 100644
--- a/src/ap/ctrl_iface_ap.h
+++ b/src/ap/ctrl_iface_ap.h
@@ -21,5 +21,8 @@  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_sta_deauthenticate(struct hostapd_data *hapd,
+                               const char *txtaddr, char *buf, size_t buflen);
+int hostapd_ctrl_iface_sta_disassociate(struct hostapd_data *hapd,
+                               const char *txtaddr, char *buf, size_t buflen);
 #endif /* CTRL_IFACE_AP_H */
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index a3b460e..133e588 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -875,6 +875,23 @@  int ap_ctrl_iface_sta_next(struct wpa_supplicant *wpa_s, const char *txtaddr,
                                           buf, buflen);
 }

+int ap_ctrl_iface_sta_disassociate(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_sta_disassociate(wpa_s->ap_iface->bss[0], txtaddr,
+                                          buf, buflen);
+}
+
+int ap_ctrl_iface_sta_deauthenticate(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_sta_deauthenticate(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)
diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h
index aa4c362..9394319 100644
--- a/wpa_supplicant/ap.h
+++ b/wpa_supplicant/ap.h
@@ -37,6 +37,10 @@  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_sta_deauthenticate(struct wpa_supplicant *wpa_s, const char *txtaddr,
+                          char *buf, size_t buflen);
+int ap_ctrl_iface_sta_disassociate(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,
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 6ca7939..f71d22c 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -1879,6 +1879,40 @@  static int wpa_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])

        return -1;
 }
+
+static int wpa_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
+                                         char *argv[])
+{
+       char buf[64];
+       if (argc < 1) {
+               printf("Invalid 'deauthenticate' command - exactly one "
+                      "argument, STA address, is required.\n");
+               return -1;
+       }
+       if (argc > 1)
+               os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s",
+                           argv[0], argv[1]);
+       else
+               os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]);
+       return wpa_ctrl_command(ctrl, buf);
+}
+
+static int wpa_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
+                                       char *argv[])
+{
+       char buf[64];
+       if (argc < 1) {
+               printf("Invalid 'disassociate' command - exactly one "
+                      "argument, STA address, is required.\n");
+               return -1;
+       }
+       if (argc > 1)
+               os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s",
+                           argv[0], argv[1]);
+       else
+               os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]);
+       return wpa_ctrl_command(ctrl, buf);
+}
 #endif /* CONFIG_AP */


@@ -2911,6 +2945,12 @@  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)" },
+       { "deauthenticate", wpa_cli_cmd_deauthenticate,
+         cli_cmd_flag_none,
+         "<addr> = deauthenticate a station" },
+       { "disassociate", wpa_cli_cmd_disassociate,
+         cli_cmd_flag_none,
+         "<addr> = disassociate a station" },
 #endif /* CONFIG_AP */
        { "suspend", wpa_cli_cmd_suspend, cli_cmd_flag_none,
          "= notification of suspend/hibernate" },