[PATCH] Force disconnect a P2P Client/STA from GO/AP side

Jithu Jance jithu at broadcom.com
Tue Dec 20 07:15:41 EST 2011


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 at 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(-)

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" },
--
1.7.4.1




- Jithu Jance


-----Original Message-----
From: hostap-bounces at lists.shmoo.com [mailto:hostap-bounces at lists.shmoo.com] On Behalf Of Jouni Malinen
Sent: Saturday, December 17, 2011 9:47 PM
To: hostap at 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
_______________________________________________
HostAP mailing list
HostAP at lists.shmoo.com
http://lists.shmoo.com/mailman/listinfo/hostap




More information about the HostAP mailing list