WPS: Allow pending WPS operation to be cancelled
authorArdong Chen <ardongchen@atheros.com>
Mon, 6 Sep 2010 17:51:06 +0000 (20:51 +0300)
committerJouni Malinen <j@w1.fi>
Fri, 10 Sep 2010 17:30:25 +0000 (10:30 -0700)
A new ctrl_interface command, WPS_CANCEL, can now be used to cancel
a pending or ongoing WPS operation. For now, this is only available
with wpa_supplicant (either in station or AP mode). Similar
functionality should be added for hostapd, too.

src/wps/wps.h
src/wps/wps_registrar.c
wpa_supplicant/ap.c
wpa_supplicant/ap.h
wpa_supplicant/ctrl_iface.c
wpa_supplicant/wpa_cli.c
wpa_supplicant/wps_supplicant.c
wpa_supplicant/wps_supplicant.h

index 6667b02..1b0fcea 100644 (file)
@@ -721,6 +721,7 @@ int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *addr,
                          const u8 *uuid, const u8 *pin, size_t pin_len,
                          int timeout);
 int wps_registrar_invalidate_pin(struct wps_registrar *reg, const u8 *uuid);
+int wps_registrar_wps_cancel(struct wps_registrar *reg);
 int wps_registrar_unlock_pin(struct wps_registrar *reg, const u8 *uuid);
 int wps_registrar_button_pushed(struct wps_registrar *reg);
 void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr,
index 6c47967..0b71484 100644 (file)
@@ -662,6 +662,22 @@ int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *addr,
 }
 
 
+static void wps_registrar_remove_pin(struct wps_registrar *reg,
+                                    struct wps_uuid_pin *pin)
+{
+       u8 *addr;
+       u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+       if (is_zero_ether_addr(pin->enrollee_addr))
+               addr = bcast;
+       else
+               addr = pin->enrollee_addr;
+       wps_registrar_remove_authorized_mac(reg, addr);
+       wps_remove_pin(pin);
+       wps_registrar_selected_registrar_changed(reg);
+}
+
+
 static void wps_registrar_expire_pins(struct wps_registrar *reg)
 {
        struct wps_uuid_pin *pin, *prev;
@@ -672,24 +688,38 @@ static void wps_registrar_expire_pins(struct wps_registrar *reg)
        {
                if ((pin->flags & PIN_EXPIRES) &&
                    os_time_before(&pin->expiration, &now)) {
-                       u8 *addr;
-                       u8 bcast[ETH_ALEN] =
-                               { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
                        wpa_hexdump(MSG_DEBUG, "WPS: Expired PIN for UUID",
                                    pin->uuid, WPS_UUID_LEN);
-                       if (is_zero_ether_addr(pin->enrollee_addr))
-                               addr = bcast;
-                       else
-                               addr = pin->enrollee_addr;
-                       wps_registrar_remove_authorized_mac(reg, addr);
-                       wps_remove_pin(pin);
-                       wps_registrar_selected_registrar_changed(reg);
+                       wps_registrar_remove_pin(reg, pin);
                }
        }
 }
 
 
 /**
+ * wps_registrar_invalidate_wildcard_pin - Invalidate a wildcard PIN
+ * @reg: Registrar data from wps_registrar_init()
+ * Returns: 0 on success, -1 if not wildcard PIN is enabled
+ */
+static int wps_registrar_invalidate_wildcard_pin(struct wps_registrar *reg)
+{
+       struct wps_uuid_pin *pin, *prev;
+
+       dl_list_for_each_safe(pin, prev, &reg->pins, struct wps_uuid_pin, list)
+       {
+               if (pin->wildcard_uuid) {
+                       wpa_hexdump(MSG_DEBUG, "WPS: Invalidated PIN for UUID",
+                                   pin->uuid, WPS_UUID_LEN);
+                       wps_registrar_remove_pin(reg, pin);
+                       return 0;
+               }
+       }
+
+       return -1;
+}
+
+
+/**
  * wps_registrar_invalidate_pin - Invalidate a PIN for a specific UUID-E
  * @reg: Registrar data from wps_registrar_init()
  * @uuid: UUID-E
@@ -702,18 +732,9 @@ int wps_registrar_invalidate_pin(struct wps_registrar *reg, const u8 *uuid)
        dl_list_for_each_safe(pin, prev, &reg->pins, struct wps_uuid_pin, list)
        {
                if (os_memcmp(pin->uuid, uuid, WPS_UUID_LEN) == 0) {
-                       u8 *addr;
-                       u8 bcast[ETH_ALEN] =
-                               { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
                        wpa_hexdump(MSG_DEBUG, "WPS: Invalidated PIN for UUID",
                                    pin->uuid, WPS_UUID_LEN);
-                       if (is_zero_ether_addr(pin->enrollee_addr))
-                               addr = bcast;
-                       else
-                               addr = pin->enrollee_addr;
-                       wps_registrar_remove_authorized_mac(reg, addr);
-                       wps_remove_pin(pin);
-                       wps_registrar_selected_registrar_changed(reg);
+                       wps_registrar_remove_pin(reg, pin);
                        return 0;
                }
        }
@@ -865,6 +886,23 @@ static void wps_registrar_pin_completed(struct wps_registrar *reg)
 }
 
 
+int wps_registrar_wps_cancel(struct wps_registrar *reg)
+{
+       if (reg->pbc) {
+               wpa_printf(MSG_DEBUG, "WPS: PBC is set - cancelling it");
+               wps_registrar_pbc_timeout(reg, NULL);
+               return 1;
+       } else if (reg->selected_registrar) {
+               /* PIN Method */
+               wpa_printf(MSG_DEBUG, "WPS: PIN is set - cancelling it");
+               wps_registrar_pin_completed(reg);
+               wps_registrar_invalidate_wildcard_pin(reg);
+               return 1;
+       }
+       return 0;
+}
+
+
 /**
  * wps_registrar_probe_req_rx - Notify Registrar of Probe Request
  * @reg: Registrar data from wps_registrar_init()
index b77bea4..5d9edfa 100644 (file)
@@ -37,6 +37,7 @@
 #include "driver_i.h"
 #include "p2p_supplicant.h"
 #include "ap.h"
+#include "ap/sta_info.h"
 
 
 static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
@@ -477,6 +478,51 @@ int wpa_supplicant_ap_wps_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid)
 }
 
 
+static int wpa_supplicant_ap_wps_sta_cancel(struct hostapd_data *hapd,
+                                           struct sta_info *sta, void *ctx)
+{
+       if (sta && (sta->flags & WLAN_STA_WPS)) {
+               ap_sta_deauthenticate(hapd, sta,
+                                     WLAN_REASON_PREV_AUTH_NOT_VALID);
+               wpa_printf(MSG_DEBUG, "WPS: %s: Deauth sta=" MACSTR,
+                          __func__, MAC2STR(sta->addr));
+               return 1;
+       }
+
+       return 0;
+}
+
+
+int wpa_supplicant_ap_wps_cancel(struct wpa_supplicant *wpa_s)
+{
+       struct wps_registrar *reg;
+       int reg_sel = 0, wps_sta = 0;
+
+       if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0]->wps)
+               return -1;
+
+       reg = wpa_s->ap_iface->bss[0]->wps->registrar;
+       reg_sel = wps_registrar_wps_cancel(reg);
+       wps_sta = ap_for_each_sta(wpa_s->ap_iface->bss[0],
+                                 wpa_supplicant_ap_wps_sta_cancel, NULL);
+
+       if (!reg_sel && !wps_sta) {
+               wpa_printf(MSG_DEBUG, "No WPS operation in progress at this "
+                          "time");
+               return -1;
+       }
+
+       /*
+        * There are 2 cases to return wps cancel as success:
+        * 1. When wps cancel was initiated but no connection has been
+        *    established with client yet.
+        * 2. Client is in the middle of exchanging WPS messages.
+        */
+
+       return 0;
+}
+
+
 int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
                              const char *pin, char *buf, size_t buflen)
 {
index b162d14..30eeca9 100644 (file)
@@ -24,6 +24,7 @@ void wpa_supplicant_ap_rx_eapol(struct wpa_supplicant *wpa_s,
 int wpa_supplicant_ap_wps_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid);
 int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
                              const char *pin, char *buf, size_t buflen);
+int wpa_supplicant_ap_wps_cancel(struct wpa_supplicant *wpa_s);
 int ap_ctrl_iface_sta_first(struct wpa_supplicant *wpa_s,
                            char *buf, size_t buflen);
 int ap_ctrl_iface_sta(struct wpa_supplicant *wpa_s, const char *txtaddr,
index 0871b39..7ffac96 100644 (file)
@@ -2687,6 +2687,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                reply_len = wpa_supplicant_ctrl_iface_wps_pin(wpa_s, buf + 8,
                                                              reply,
                                                              reply_size);
+       } else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
+               if (wpas_wps_cancel(wpa_s))
+                       reply_len = -1;
 #ifdef CONFIG_WPS_OOB
        } else if (os_strncmp(buf, "WPS_OOB ", 8) == 0) {
                if (wpa_supplicant_ctrl_iface_wps_oob(wpa_s, buf + 8))
index 624c38f..cf2ab80 100644 (file)
@@ -615,6 +615,13 @@ static int wpa_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc, char *argv[])
 }
 
 
+static int wpa_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc,
+                                 char *argv[])
+{
+       return wpa_ctrl_command(ctrl, "WPS_CANCEL");
+}
+
+
 #ifdef CONFIG_WPS_OOB
 static int wpa_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
@@ -2244,6 +2251,8 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
          cli_cmd_flag_sensitive,
          "<BSSID> [PIN] = start WPS PIN method (returns PIN, if not "
          "hardcoded)" },
+       { "wps_cancel", wpa_cli_cmd_wps_cancel, cli_cmd_flag_none,
+         "Cancels the pending WPS operation" },
 #ifdef CONFIG_WPS_OOB
        { "wps_oob", wpa_cli_cmd_wps_oob,
          cli_cmd_flag_sensitive,
index 3d9836b..8f4ed51 100644 (file)
@@ -32,6 +32,7 @@
 #include "blacklist.h"
 #include "bss.h"
 #include "scan.h"
+#include "ap.h"
 #include "p2p/p2p.h"
 #include "p2p_supplicant.h"
 #include "wps_supplicant.h"
@@ -757,6 +758,32 @@ int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
 }
 
 
+/* Cancel the wps pbc/pin requests */
+int wpas_wps_cancel(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_AP
+       if (wpa_s->ap_iface) {
+               wpa_printf(MSG_DEBUG, "WPS: Cancelling in AP mode");
+               return wpa_supplicant_ap_wps_cancel(wpa_s);
+       }
+#endif /* CONFIG_AP */
+
+       if (wpa_s->wpa_state == WPA_SCANNING) {
+               wpa_printf(MSG_DEBUG, "WPS: Cancel operation - cancel scan");
+               wpa_supplicant_cancel_scan(wpa_s);
+               wpas_clear_wps(wpa_s);
+       } else if (wpa_s->wpa_state >= WPA_ASSOCIATED) {
+               wpa_printf(MSG_DEBUG, "WPS: Cancel operation - "
+                          "deauthenticate");
+               wpa_supplicant_deauthenticate(wpa_s,
+                                             WLAN_REASON_DEAUTH_LEAVING);
+               wpas_clear_wps(wpa_s);
+       }
+
+       return 0;
+}
+
+
 #ifdef CONFIG_WPS_OOB
 int wpas_wps_start_oob(struct wpa_supplicant *wpa_s, char *device_type,
                       char *path, char *method, char *name)
index 59d37b4..ce1776f 100644 (file)
@@ -39,6 +39,7 @@ int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
                       int p2p_group);
 int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
                       const char *pin, int p2p_group, u16 dev_pw_id);
+int wpas_wps_cancel(struct wpa_supplicant *wpa_s);
 int wpas_wps_start_oob(struct wpa_supplicant *wpa_s, char *device_type,
                       char *path, char *method, char *name);
 int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid,