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:
parent
bb79dc720b
commit
70d84f11fe
5 changed files with 229 additions and 0 deletions
|
@ -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 */
|
||||
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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" },
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue