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.
This commit is contained in:
Jouni Malinen 2010-11-17 16:46:55 +02:00 committed by Jouni Malinen
parent bb79dc720b
commit 70d84f11fe
5 changed files with 229 additions and 0 deletions

View file

@ -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 */

View file

@ -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 */

View file

@ -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))

View file

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

View file

@ -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;