aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJouni Malinen <jouni.malinen@atheros.com>2010-11-17 14:46:55 (GMT)
committerJouni Malinen <j@w1.fi>2010-11-17 14:46:55 (GMT)
commit70d84f11febaefe0bbd3b24ecb88101b1789e37d (patch)
treecc472cbacbdbd7ad792acf35b6387c6a96e5c668
parentbb79dc720b3c439ad9748b235061850c63d07fec (diff)
downloadhostap-70d84f11febaefe0bbd3b24ecb88101b1789e37d.zip
hostap-70d84f11febaefe0bbd3b24ecb88101b1789e37d.tar.gz
hostap-70d84f11febaefe0bbd3b24ecb88101b1789e37d.tar.bz2
WPS: Add wps_ap_pin ctrl_iface command for wpa_supplicant AP mode
This can be used to control the AP PIN in wpa_supplicant AP mode in the same way as the identical command in hostapd ctrl_iface.
-rw-r--r--wpa_supplicant/ap.c123
-rw-r--r--wpa_supplicant/ap.h6
-rw-r--r--wpa_supplicant/ctrl_iface.c64
-rw-r--r--wpa_supplicant/wpa_cli.c32
-rw-r--r--wpa_supplicant/wps_supplicant.c4
5 files changed, 229 insertions, 0 deletions
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 3c3b92f..1a8d519 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -16,6 +16,7 @@
#include "utils/includes.h"
#include "utils/common.h"
+#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "common/wpa_ctrl.h"
#include "ap/hostapd.h"
@@ -41,6 +42,9 @@
#include "ap/sta_info.h"
+static void wpas_wps_ap_pin_timeout(void *eloop_data, void *user_ctx);
+
+
static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
struct hostapd_config *conf)
@@ -428,6 +432,8 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
void wpa_supplicant_ap_deinit(struct wpa_supplicant *wpa_s)
{
+ eloop_cancel_timeout(wpas_wps_ap_pin_timeout, wpa_s, NULL);
+
if (wpa_s->ap_iface == NULL)
return;
@@ -575,6 +581,123 @@ int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
return ret_len;
}
+
+static void wpas_wps_ap_pin_timeout(void *eloop_data, void *user_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_data;
+ wpa_printf(MSG_DEBUG, "WPS: AP PIN timed out");
+ wpas_wps_ap_pin_disable(wpa_s);
+}
+
+
+static void wpas_wps_ap_pin_enable(struct wpa_supplicant *wpa_s, int timeout)
+{
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface == NULL)
+ return;
+ hapd = wpa_s->ap_iface->bss[0];
+ wpa_printf(MSG_DEBUG, "WPS: Enabling AP PIN (timeout=%d)", timeout);
+ hapd->ap_pin_failures = 0;
+ eloop_cancel_timeout(wpas_wps_ap_pin_timeout, wpa_s, NULL);
+ if (timeout > 0)
+ eloop_register_timeout(timeout, 0,
+ wpas_wps_ap_pin_timeout, wpa_s, NULL);
+}
+
+
+void wpas_wps_ap_pin_disable(struct wpa_supplicant *wpa_s)
+{
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface == NULL)
+ return;
+ wpa_printf(MSG_DEBUG, "WPS: Disabling AP PIN");
+ hapd = wpa_s->ap_iface->bss[0];
+ os_free(hapd->conf->ap_pin);
+ hapd->conf->ap_pin = NULL;
+ eloop_cancel_timeout(wpas_wps_ap_pin_timeout, wpa_s, NULL);
+}
+
+
+const char * wpas_wps_ap_pin_random(struct wpa_supplicant *wpa_s, int timeout)
+{
+ struct hostapd_data *hapd;
+ unsigned int pin;
+ char pin_txt[9];
+
+ if (wpa_s->ap_iface == NULL)
+ return NULL;
+ hapd = wpa_s->ap_iface->bss[0];
+ pin = wps_generate_pin();
+ os_snprintf(pin_txt, sizeof(pin_txt), "%u", pin);
+ os_free(hapd->conf->ap_pin);
+ hapd->conf->ap_pin = os_strdup(pin_txt);
+ if (hapd->conf->ap_pin == NULL)
+ return NULL;
+ wpas_wps_ap_pin_enable(wpa_s, timeout);
+
+ return hapd->conf->ap_pin;
+}
+
+
+const char * wpas_wps_ap_pin_get(struct wpa_supplicant *wpa_s)
+{
+ struct hostapd_data *hapd;
+ if (wpa_s->ap_iface == NULL)
+ return NULL;
+ hapd = wpa_s->ap_iface->bss[0];
+ return hapd->conf->ap_pin;
+}
+
+
+int wpas_wps_ap_pin_set(struct wpa_supplicant *wpa_s, const char *pin,
+ int timeout)
+{
+ struct hostapd_data *hapd;
+ char pin_txt[9];
+ int ret;
+
+ if (wpa_s->ap_iface == NULL)
+ return -1;
+ hapd = wpa_s->ap_iface->bss[0];
+ ret = os_snprintf(pin_txt, sizeof(pin_txt), "%s", pin);
+ if (ret < 0 || ret >= (int) sizeof(pin_txt))
+ return -1;
+ os_free(hapd->conf->ap_pin);
+ hapd->conf->ap_pin = os_strdup(pin_txt);
+ if (hapd->conf->ap_pin == NULL)
+ return -1;
+ wpas_wps_ap_pin_enable(wpa_s, timeout);
+
+ return 0;
+}
+
+
+void wpa_supplicant_ap_pwd_auth_fail(struct wpa_supplicant *wpa_s)
+{
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface == NULL)
+ return;
+ hapd = wpa_s->ap_iface->bss[0];
+
+ /*
+ * Registrar failed to prove its knowledge of the AP PIN. Disable AP
+ * PIN if this happens multiple times to slow down brute force attacks.
+ */
+ hapd->ap_pin_failures++;
+ wpa_printf(MSG_DEBUG, "WPS: AP PIN authentication failure number %u",
+ hapd->ap_pin_failures);
+ if (hapd->ap_pin_failures < 3)
+ return;
+
+ wpa_printf(MSG_DEBUG, "WPS: Disable AP PIN");
+ hapd->ap_pin_failures = 0;
+ os_free(hapd->conf->ap_pin);
+ hapd->conf->ap_pin = NULL;
+}
+
#endif /* CONFIG_WPS */
diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h
index 30eeca9..d3bab24 100644
--- a/wpa_supplicant/ap.h
+++ b/wpa_supplicant/ap.h
@@ -25,6 +25,11 @@ 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);
+void wpas_wps_ap_pin_disable(struct wpa_supplicant *wpa_s);
+const char * wpas_wps_ap_pin_random(struct wpa_supplicant *wpa_s, int timeout);
+const char * wpas_wps_ap_pin_get(struct wpa_supplicant *wpa_s);
+int wpas_wps_ap_pin_set(struct wpa_supplicant *wpa_s, const char *pin,
+ int timeout);
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,
@@ -41,5 +46,6 @@ void ap_mgmt_tx_cb(void *ctx, const u8 *buf, size_t len, u16 stype, int ok);
int wpa_supplicant_ap_update_beacon(struct wpa_supplicant *wpa_s);
int wpa_supplicant_ap_mac_addr_filter(struct wpa_supplicant *wpa_s,
const u8 *addr);
+void wpa_supplicant_ap_pwd_auth_fail(struct wpa_supplicant *wpa_s);
#endif /* AP_H */
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 197d9a1..c28f6a8 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -401,6 +401,65 @@ static int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s,
}
+#ifdef CONFIG_AP
+static int wpa_supplicant_ctrl_iface_wps_ap_pin(struct wpa_supplicant *wpa_s,
+ char *cmd, char *buf,
+ size_t buflen)
+{
+ int timeout = 300;
+ char *pos;
+ const char *pin_txt;
+
+ if (!wpa_s->ap_iface)
+ return -1;
+
+ pos = os_strchr(cmd, ' ');
+ if (pos)
+ *pos++ = '\0';
+
+ if (os_strcmp(cmd, "disable") == 0) {
+ wpas_wps_ap_pin_disable(wpa_s);
+ return os_snprintf(buf, buflen, "OK\n");
+ }
+
+ if (os_strcmp(cmd, "random") == 0) {
+ if (pos)
+ timeout = atoi(pos);
+ pin_txt = wpas_wps_ap_pin_random(wpa_s, timeout);
+ if (pin_txt == NULL)
+ return -1;
+ return os_snprintf(buf, buflen, "%s", pin_txt);
+ }
+
+ if (os_strcmp(cmd, "get") == 0) {
+ pin_txt = wpas_wps_ap_pin_get(wpa_s);
+ if (pin_txt == NULL)
+ return -1;
+ return os_snprintf(buf, buflen, "%s", pin_txt);
+ }
+
+ if (os_strcmp(cmd, "set") == 0) {
+ char *pin;
+ if (pos == NULL)
+ return -1;
+ pin = pos;
+ pos = os_strchr(pos, ' ');
+ if (pos) {
+ *pos++ = '\0';
+ timeout = atoi(pos);
+ }
+ if (os_strlen(pin) > buflen)
+ return -1;
+ if (wpas_wps_ap_pin_set(wpa_s, pin, timeout) < 0)
+ return -1;
+ return os_snprintf(buf, buflen, "%s", pin);
+ }
+
+ return -1;
+}
+#endif /* CONFIG_AP */
+
+
#ifdef CONFIG_WPS_ER
static int wpa_supplicant_ctrl_iface_wps_er_pin(struct wpa_supplicant *wpa_s,
char *cmd)
@@ -2813,6 +2872,11 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "WPS_REG ", 8) == 0) {
if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8))
reply_len = -1;
+#ifdef CONFIG_AP
+ } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
+ reply_len = wpa_supplicant_ctrl_iface_wps_ap_pin(
+ wpa_s, buf + 11, reply, reply_size);
+#endif /* CONFIG_AP */
#ifdef CONFIG_WPS_ER
} else if (os_strcmp(buf, "WPS_ER_START") == 0) {
if (wpas_wps_er_start(wpa_s, NULL))
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 0c00acf..4bea0ec 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -667,6 +667,35 @@ static int wpa_cli_cmd_wps_reg(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
+static int wpa_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char cmd[256];
+ int res;
+
+ if (argc < 1) {
+ printf("Invalid WPS_AP_PIN command: needs at least one "
+ "argument\n");
+ return -1;
+ }
+
+ if (argc > 2)
+ res = os_snprintf(cmd, sizeof(cmd), "WPS_AP_PIN %s %s %s",
+ argv[0], argv[1], argv[2]);
+ else if (argc > 1)
+ res = os_snprintf(cmd, sizeof(cmd), "WPS_AP_PIN %s %s",
+ argv[0], argv[1]);
+ else
+ res = os_snprintf(cmd, sizeof(cmd), "WPS_AP_PIN %s",
+ argv[0]);
+ if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+ printf("Too long WPS_AP_PIN command.\n");
+ return -1;
+ }
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
static int wpa_cli_cmd_wps_er_start(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -2273,6 +2302,9 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
{ "wps_reg", wpa_cli_cmd_wps_reg,
cli_cmd_flag_sensitive,
"<BSSID> <AP PIN> = start WPS Registrar to configure an AP" },
+ { "wps_ap_pin", wpa_cli_cmd_wps_ap_pin,
+ cli_cmd_flag_sensitive,
+ "[params..] = enable/disable AP PIN" },
{ "wps_er_start", wpa_cli_cmd_wps_er_start,
cli_cmd_flag_none,
"[IP address] = start Wi-Fi Protected Setup External Registrar" },
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index e2adb60..7b5c9be 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -551,6 +551,10 @@ static void wpa_supplicant_wps_event(void *ctx, enum wps_event event,
wpa_supplicant_wps_event_success(wpa_s);
break;
case WPS_EV_PWD_AUTH_FAIL:
+#ifdef CONFIG_AP
+ if (wpa_s->ap_iface && data->pwd_auth_fail.enrollee)
+ wpa_supplicant_ap_pwd_auth_fail(wpa_s);
+#endif /* CONFIG_AP */
break;
case WPS_EV_PBC_OVERLAP:
break;