WPS: Add support for AP reconfiguration with wps_reg
wpa_supplicant can now reconfigure the AP by acting as an External Registrar with the wps_reg command. Previously, this was only used to fetch the current AP settings, but now the wps_reg command has optional arguments which can be used to provide the new AP configuration. When the new parameters are set, the WPS protocol run is allowed to continue through M8 to reconfigure the AP instead of stopping at M7.
This commit is contained in:
parent
e6965d4e5d
commit
52eb293dd2
11 changed files with 252 additions and 37 deletions
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* EAP-WSC peer for Wi-Fi Protected Setup
|
||||
* Copyright (c) 2007-2008, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
|
@ -65,6 +65,72 @@ static void eap_wsc_state(struct eap_wsc_data *data, int state)
|
|||
}
|
||||
|
||||
|
||||
static int eap_wsc_new_ap_settings(struct wps_credential *cred,
|
||||
const char *params)
|
||||
{
|
||||
const char *pos, *end;
|
||||
size_t len;
|
||||
|
||||
os_memset(cred, 0, sizeof(*cred));
|
||||
|
||||
pos = os_strstr(params, "new_ssid=");
|
||||
if (pos == NULL)
|
||||
return 0;
|
||||
pos += 9;
|
||||
end = os_strchr(pos, ' ');
|
||||
if (end == NULL)
|
||||
len = os_strlen(pos);
|
||||
else
|
||||
len = end - pos;
|
||||
if ((len & 1) || len > 2 * sizeof(cred->ssid) ||
|
||||
hexstr2bin(pos, cred->ssid, len / 2))
|
||||
return -1;
|
||||
cred->ssid_len = len / 2;
|
||||
|
||||
pos = os_strstr(params, "new_auth=");
|
||||
if (pos == NULL)
|
||||
return -1;
|
||||
if (os_strncmp(pos + 9, "OPEN", 4) == 0)
|
||||
cred->auth_type = WPS_AUTH_OPEN;
|
||||
else if (os_strncmp(pos + 9, "WPAPSK", 6) == 0)
|
||||
cred->auth_type = WPS_AUTH_WPAPSK;
|
||||
else if (os_strncmp(pos + 9, "WPA2PSK", 7) == 0)
|
||||
cred->auth_type = WPS_AUTH_WPA2PSK;
|
||||
else
|
||||
return -1;
|
||||
|
||||
pos = os_strstr(params, "new_encr=");
|
||||
if (pos == NULL)
|
||||
return -1;
|
||||
if (os_strncmp(pos + 9, "NONE", 4) == 0)
|
||||
cred->encr_type = WPS_ENCR_NONE;
|
||||
else if (os_strncmp(pos + 9, "WEP", 3) == 0)
|
||||
cred->encr_type = WPS_ENCR_WEP;
|
||||
else if (os_strncmp(pos + 9, "TKIP", 4) == 0)
|
||||
cred->encr_type = WPS_ENCR_TKIP;
|
||||
else if (os_strncmp(pos + 9, "CCMP", 4) == 0)
|
||||
cred->encr_type = WPS_ENCR_AES;
|
||||
else
|
||||
return -1;
|
||||
|
||||
pos = os_strstr(params, "new_key=");
|
||||
if (pos == NULL)
|
||||
return 0;
|
||||
pos += 8;
|
||||
end = os_strchr(pos, ' ');
|
||||
if (end == NULL)
|
||||
len = os_strlen(pos);
|
||||
else
|
||||
len = end - pos;
|
||||
if ((len & 1) || len > 2 * sizeof(cred->key) ||
|
||||
hexstr2bin(pos, cred->key, len / 2))
|
||||
return -1;
|
||||
cred->key_len = len / 2;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void * eap_wsc_init(struct eap_sm *sm)
|
||||
{
|
||||
struct eap_wsc_data *data;
|
||||
|
@ -75,6 +141,8 @@ static void * eap_wsc_init(struct eap_sm *sm)
|
|||
const char *pos;
|
||||
const char *phase1;
|
||||
struct wps_context *wps;
|
||||
struct wps_credential new_ap_settings;
|
||||
int res;
|
||||
|
||||
wps = sm->wps;
|
||||
if (wps == NULL) {
|
||||
|
@ -135,6 +203,17 @@ static void * eap_wsc_init(struct eap_sm *sm)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
res = eap_wsc_new_ap_settings(&new_ap_settings, phase1);
|
||||
if (res < 0) {
|
||||
os_free(data);
|
||||
return NULL;
|
||||
}
|
||||
if (res == 1) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-WSC: Provide new AP settings for "
|
||||
"WPS");
|
||||
cfg.new_ap_settings = &new_ap_settings;
|
||||
}
|
||||
|
||||
data->wps = wps_init(&cfg);
|
||||
if (data->wps == NULL) {
|
||||
os_free(data);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Wi-Fi Protected Setup
|
||||
* Copyright (c) 2007-2008, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
|
@ -89,6 +89,17 @@ struct wps_data * wps_init(const struct wps_config *cfg)
|
|||
}
|
||||
}
|
||||
|
||||
if (cfg->new_ap_settings) {
|
||||
data->new_ap_settings =
|
||||
os_malloc(sizeof(*data->new_ap_settings));
|
||||
if (data->new_ap_settings == NULL) {
|
||||
os_free(data);
|
||||
return NULL;
|
||||
}
|
||||
os_memcpy(data->new_ap_settings, cfg->new_ap_settings,
|
||||
sizeof(*data->new_ap_settings));
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
@ -115,6 +126,7 @@ void wps_deinit(struct wps_data *data)
|
|||
os_free(data->dev_password);
|
||||
os_free(data->new_psk);
|
||||
wps_device_data_free(&data->peer_dev);
|
||||
os_free(data->new_ap_settings);
|
||||
os_free(data);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Wi-Fi Protected Setup
|
||||
* Copyright (c) 2007-2008, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
|
@ -132,6 +132,16 @@ struct wps_config {
|
|||
* assoc_wps_ie: (Re)AssocReq WPS IE (in AP; %NULL if not AP)
|
||||
*/
|
||||
const struct wpabuf *assoc_wps_ie;
|
||||
|
||||
/**
|
||||
* new_ap_settings - New AP settings (%NULL if not used)
|
||||
*
|
||||
* This parameter provides new AP settings when using a wireless
|
||||
* stations as a Registrar to configure the AP. %NULL means that AP
|
||||
* will not be reconfigured, i.e., the station will only learn the
|
||||
* current AP settings by using AP PIN.
|
||||
*/
|
||||
const struct wps_credential *new_ap_settings;
|
||||
};
|
||||
|
||||
struct wps_data * wps_init(const struct wps_config *cfg);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Wi-Fi Protected Setup - internal definitions
|
||||
* Copyright (c) 2008, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
|
@ -103,6 +103,8 @@ struct wps_data {
|
|||
u16 config_error;
|
||||
|
||||
int ext_reg;
|
||||
|
||||
struct wps_credential *new_ap_settings;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Wi-Fi Protected Setup - Registrar
|
||||
* Copyright (c) 2008, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
|
@ -2041,6 +2041,19 @@ static void wps_sta_cred_cb(struct wps_data *wps)
|
|||
}
|
||||
|
||||
|
||||
static void wps_cred_update(struct wps_credential *dst,
|
||||
struct wps_credential *src)
|
||||
{
|
||||
os_memcpy(dst->ssid, src->ssid, sizeof(dst->ssid));
|
||||
dst->ssid_len = src->ssid_len;
|
||||
dst->auth_type = src->auth_type;
|
||||
dst->encr_type = src->encr_type;
|
||||
dst->key_idx = src->key_idx;
|
||||
os_memcpy(dst->key, src->key, sizeof(dst->key));
|
||||
dst->key_len = src->key_len;
|
||||
}
|
||||
|
||||
|
||||
static int wps_process_ap_settings_r(struct wps_data *wps,
|
||||
struct wps_parse_attr *attr)
|
||||
{
|
||||
|
@ -2053,21 +2066,19 @@ static int wps_process_ap_settings_r(struct wps_data *wps,
|
|||
|
||||
wpa_printf(MSG_INFO, "WPS: Received old AP configuration from AP");
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* TODO: Provide access to AP settings and allow changes before sending
|
||||
* out M8. For now, just copy the settings unchanged into M8.
|
||||
*/
|
||||
|
||||
return 0;
|
||||
#else
|
||||
/*
|
||||
* For now, use the AP PIN only to receive the current AP settings,
|
||||
* not to reconfigure the AP.
|
||||
*/
|
||||
wps_sta_cred_cb(wps);
|
||||
return 1;
|
||||
#endif
|
||||
if (wps->new_ap_settings) {
|
||||
wpa_printf(MSG_INFO, "WPS: Update AP configuration based on "
|
||||
"new settings");
|
||||
wps_cred_update(&wps->cred, wps->new_ap_settings);
|
||||
return 0;
|
||||
} else {
|
||||
/*
|
||||
* Use the AP PIN only to receive the current AP settings, not
|
||||
* to reconfigure the AP.
|
||||
*/
|
||||
wps_sta_cred_cb(wps);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -131,17 +131,29 @@ negotiation which will generate a new WPA PSK in the same way as the
|
|||
PIN method described above.
|
||||
|
||||
|
||||
If the client wants to operate in the Registrar role to configure an
|
||||
AP, wpa_supplicant is notified over the control interface, e.g., with
|
||||
If the client wants to operate in the Registrar role to learn the
|
||||
current AP configuration and optionally, to configure an AP,
|
||||
wpa_supplicant is notified over the control interface, e.g., with
|
||||
wpa_cli:
|
||||
|
||||
wpa_cli wps_reg <AP BSSID> <AP PIN>
|
||||
(example: wpa_cli wps_reg 02:34:56:78:9a:bc 12345670)
|
||||
|
||||
This is currently only used to fetch the current AP settings instead
|
||||
of actually changing them. The main difference with the wps_pin
|
||||
command is that wps_reg uses the AP PIN (e.g., from a label on the AP)
|
||||
instead of a PIN generated at the client.
|
||||
This is used to fetch the current AP settings instead of actually
|
||||
changing them. The main difference with the wps_pin command is that
|
||||
wps_reg uses the AP PIN (e.g., from a label on the AP) instead of a
|
||||
PIN generated at the client.
|
||||
|
||||
In order to change the AP configuration, the new configuration
|
||||
parameters are given to the wps_reg command:
|
||||
|
||||
wpa_cli wps_reg <AP BSSID> <AP PIN> <new SSID> <auth> <encr> <new key>
|
||||
examples:
|
||||
wpa_cli wps_reg 02:34:56:78:9a:bc 12345670 testing WPA2PSK CCMP 12345678
|
||||
wpa_cli wps_reg 02:34:56:78:9a:bc 12345670 clear OPEN NONE ""
|
||||
|
||||
<auth> must be one of the following: OPEN WPAPSK WPA2PSK
|
||||
<encr> must be one of the following: NONE WEP TKIP CCMP
|
||||
|
||||
|
||||
Scanning
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* WPA Supplicant / Control interface (shared code for all backends)
|
||||
* Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
|
@ -248,6 +248,11 @@ static int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s,
|
|||
{
|
||||
u8 bssid[ETH_ALEN], *_bssid = bssid;
|
||||
char *pin;
|
||||
char *new_ssid;
|
||||
char *new_auth;
|
||||
char *new_encr;
|
||||
char *new_key;
|
||||
struct wps_new_ap_settings ap;
|
||||
|
||||
pin = os_strchr(cmd, ' ');
|
||||
if (pin == NULL)
|
||||
|
@ -262,7 +267,32 @@ static int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s,
|
|||
return -1;
|
||||
}
|
||||
|
||||
return wpas_wps_start_reg(wpa_s, _bssid, pin);
|
||||
new_ssid = os_strchr(pin, ' ');
|
||||
if (new_ssid == NULL)
|
||||
return wpas_wps_start_reg(wpa_s, _bssid, pin, NULL);
|
||||
*new_ssid++ = '\0';
|
||||
|
||||
new_auth = os_strchr(new_ssid, ' ');
|
||||
if (new_auth == NULL)
|
||||
return -1;
|
||||
*new_auth++ = '\0';
|
||||
|
||||
new_encr = os_strchr(new_auth, ' ');
|
||||
if (new_encr == NULL)
|
||||
return -1;
|
||||
*new_encr++ = '\0';
|
||||
|
||||
new_key = os_strchr(new_encr, ' ');
|
||||
if (new_key == NULL)
|
||||
return -1;
|
||||
*new_key++ = '\0';
|
||||
|
||||
os_memset(&ap, 0, sizeof(ap));
|
||||
ap.ssid_hex = new_ssid;
|
||||
ap.auth = new_auth;
|
||||
ap.encr = new_encr;
|
||||
ap.key_hex = new_key;
|
||||
return wpas_wps_start_reg(wpa_s, _bssid, pin, &ap);
|
||||
}
|
||||
#endif /* CONFIG_WPS */
|
||||
|
||||
|
|
|
@ -1615,9 +1615,9 @@ DBusMessage * wpas_dbus_iface_wps_reg(DBusMessage *message,
|
|||
return wpas_dbus_new_invalid_opts_error(message, NULL);
|
||||
|
||||
if (!os_strcmp(arg_bssid, "any"))
|
||||
ret = wpas_wps_start_reg(wpa_s, NULL, pin);
|
||||
ret = wpas_wps_start_reg(wpa_s, NULL, pin, NULL);
|
||||
else if (!hwaddr_aton(arg_bssid, bssid))
|
||||
ret = wpas_wps_start_reg(wpa_s, bssid, pin);
|
||||
ret = wpas_wps_start_reg(wpa_s, bssid, pin, NULL);
|
||||
else {
|
||||
return wpas_dbus_new_invalid_opts_error(message,
|
||||
"Invalid BSSID");
|
||||
|
|
|
@ -484,14 +484,47 @@ static int wpa_cli_cmd_wps_reg(struct wpa_ctrl *ctrl, int argc, char *argv[])
|
|||
char cmd[256];
|
||||
int res;
|
||||
|
||||
if (argc != 2) {
|
||||
if (argc == 2)
|
||||
res = os_snprintf(cmd, sizeof(cmd), "WPS_REG %s %s",
|
||||
argv[0], argv[1]);
|
||||
else if (argc == 6) {
|
||||
char ssid_hex[2 * 32 + 1];
|
||||
char key_hex[2 * 64 + 1];
|
||||
int i;
|
||||
|
||||
ssid_hex[0] = '\0';
|
||||
for (i = 0; i < 32; i++) {
|
||||
if (argv[2][i] == '\0')
|
||||
break;
|
||||
os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[2][i]);
|
||||
}
|
||||
|
||||
key_hex[0] = '\0';
|
||||
for (i = 0; i < 64; i++) {
|
||||
if (argv[5][i] == '\0')
|
||||
break;
|
||||
os_snprintf(&key_hex[i * 2], 3, "%02x", argv[5][i]);
|
||||
}
|
||||
|
||||
res = os_snprintf(cmd, sizeof(cmd),
|
||||
"WPS_REG %s %s %s %s %s %s",
|
||||
argv[0], argv[1], ssid_hex, argv[3], argv[4],
|
||||
key_hex);
|
||||
} else {
|
||||
printf("Invalid WPS_REG command: need two arguments:\n"
|
||||
"- BSSID: use 'any' to select any\n"
|
||||
"- AP PIN\n");
|
||||
printf("Alternatively, six arguments can be used to "
|
||||
"reconfigure the AP:\n"
|
||||
"- BSSID: use 'any' to select any\n"
|
||||
"- AP PIN\n"
|
||||
"- new SSID\n"
|
||||
"- new auth (OPEN, WPAPSK, WPA2PSK)\n"
|
||||
"- new encr (NONE, WEP, TKIP, CCMP)\n"
|
||||
"- new key\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = os_snprintf(cmd, sizeof(cmd), "WPS_REG %s %s", argv[0], argv[1]);
|
||||
if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
|
||||
printf("Too long WPS_REG command.\n");
|
||||
return -1;
|
||||
|
|
|
@ -630,10 +630,12 @@ int wpas_wps_start_oob(struct wpa_supplicant *wpa_s, char *device_type,
|
|||
|
||||
|
||||
int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid,
|
||||
const char *pin)
|
||||
const char *pin, struct wps_new_ap_settings *settings)
|
||||
{
|
||||
struct wpa_ssid *ssid;
|
||||
char val[30];
|
||||
char val[200];
|
||||
char *pos, *end;
|
||||
int res;
|
||||
|
||||
if (!pin)
|
||||
return -1;
|
||||
|
@ -641,7 +643,24 @@ int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid,
|
|||
ssid = wpas_wps_add_network(wpa_s, 1, bssid);
|
||||
if (ssid == NULL)
|
||||
return -1;
|
||||
os_snprintf(val, sizeof(val), "\"pin=%s\"", pin);
|
||||
pos = val;
|
||||
end = pos + sizeof(val);
|
||||
res = os_snprintf(pos, end - pos, "\"pin=%s", pin);
|
||||
if (res < 0 || res >= end - pos)
|
||||
return -1;
|
||||
pos += res;
|
||||
if (settings) {
|
||||
res = os_snprintf(pos, end - pos, " new_ssid=%s new_auth=%s "
|
||||
"new_encr=%s new_key=%s",
|
||||
settings->ssid_hex, settings->auth,
|
||||
settings->encr, settings->key_hex);
|
||||
if (res < 0 || res >= end - pos)
|
||||
return -1;
|
||||
pos += res;
|
||||
}
|
||||
res = os_snprintf(pos, end - pos, "\"");
|
||||
if (res < 0 || res >= end - pos)
|
||||
return -1;
|
||||
wpa_config_set(ssid, "phase1", val, 0);
|
||||
eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
|
||||
wpa_s, NULL);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* wpa_supplicant / WPS integration
|
||||
* Copyright (c) 2008, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
|
@ -20,6 +20,13 @@
|
|||
#include "wps/wps.h"
|
||||
#include "wps/wps_defs.h"
|
||||
|
||||
struct wps_new_ap_settings {
|
||||
const char *ssid_hex;
|
||||
const char *auth;
|
||||
const char *encr;
|
||||
const char *key_hex;
|
||||
};
|
||||
|
||||
int wpas_wps_init(struct wpa_supplicant *wpa_s);
|
||||
void wpas_wps_deinit(struct wpa_supplicant *wpa_s);
|
||||
int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s);
|
||||
|
@ -30,7 +37,7 @@ int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
|
|||
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,
|
||||
const char *pin);
|
||||
const char *pin, struct wps_new_ap_settings *settings);
|
||||
int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s,
|
||||
struct wpa_ssid *ssid, struct wpa_scan_res *bss);
|
||||
int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s,
|
||||
|
|
Loading…
Reference in a new issue