WPS: Added wpa_supplicant ctrl_iface commands to start WPS processing

New control interface commands WPS_PBC, WPS_PIN, and WPS_REG can be used
to start WPS processing. These add and select the WPS network block into
the configuration temporarily, i.e., there is no need to add the WPS
network block manually anymore.
This commit is contained in:
Jouni Malinen 2008-11-29 20:59:45 +02:00
parent e237a6b0d7
commit fcc60db4eb
4 changed files with 356 additions and 0 deletions

View file

@ -27,6 +27,7 @@
#include "wpa_ctrl.h"
#include "eap_peer/eap.h"
#include "ieee802_11_defs.h"
#include "wps_supplicant.h"
static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
@ -139,6 +140,91 @@ static int wpa_supplicant_ctrl_iface_ft_ds(
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_WPS
static int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s,
char *cmd)
{
u8 bssid[ETH_ALEN];
if (cmd == NULL || os_strcmp(cmd, "any") == 0)
return wpas_wps_start_pbc(wpa_s, NULL);
if (hwaddr_aton(cmd, bssid)) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid BSSID '%s'",
cmd);
return -1;
}
return wpas_wps_start_pbc(wpa_s, bssid);
}
static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s,
char *cmd, char *buf,
size_t buflen)
{
u8 bssid[ETH_ALEN], *_bssid = bssid;
char *pin;
int ret;
pin = os_strchr(cmd, ' ');
if (pin)
*pin++ = '\0';
if (os_strcmp(cmd, "any") == 0)
_bssid = NULL;
else if (hwaddr_aton(cmd, bssid)) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_REG: invalid BSSID '%s'",
cmd);
return -1;
}
if (pin) {
ret = wpas_wps_start_pin(wpa_s, _bssid, pin);
if (ret < 0)
return -1;
ret = os_snprintf(buf, buflen, "%s", pin);
if (ret < 0 || (size_t) ret >= buflen)
return -1;
return ret;
}
ret = wpas_wps_start_pin(wpa_s, _bssid, NULL);
if (ret < 0)
return -1;
/* Return the generated PIN */
ret = os_snprintf(buf, buflen, "%08d", ret);
if (ret < 0 || (size_t) ret >= buflen)
return -1;
return ret;
}
static int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s,
char *cmd)
{
u8 bssid[ETH_ALEN], *_bssid = bssid;
char *pin;
pin = os_strchr(cmd, ' ');
if (pin == NULL)
return -1;
*pin++ = '\0';
if (os_strcmp(cmd, "any") == 0)
_bssid = NULL;
else if (hwaddr_aton(cmd, bssid)) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_REG: invalid BSSID '%s'",
cmd);
return -1;
}
return wpas_wps_start_reg(wpa_s, _bssid, pin);
}
#endif /* CONFIG_WPS */
static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s,
char *rsp)
{
@ -1432,6 +1518,21 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
if (wpa_supplicant_ctrl_iface_ft_ds(wpa_s, buf + 6))
reply_len = -1;
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_WPS
} else if (os_strcmp(buf, "WPS_PBC") == 0) {
if (wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, NULL))
reply_len = -1;
} else if (os_strncmp(buf, "WPS_PBC ", 8) == 0) {
if (wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, buf + 8))
reply_len = -1;
} else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
reply_len = wpa_supplicant_ctrl_iface_wps_pin(wpa_s, buf + 8,
reply,
reply_size);
} else if (os_strncmp(buf, "WPS_REG ", 8) == 0) {
if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8))
reply_len = -1;
#endif /* CONFIG_WPS */
} else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0)
{
if (wpa_supplicant_ctrl_iface_ctrl_rsp(

View file

@ -132,6 +132,10 @@ static const char *commands_help =
" ap_scan <value> = set ap_scan parameter\n"
" stkstart <addr> = request STK negotiation with <addr>\n"
" ft_ds <addr> = request over-the-DS FT with <addr>\n"
" wps_pbc [BSSID] = start Wi-Fi Protected Setup: Push Button Configuration\n"
" wps_pin <BSSID> [PIN] = start WPS PIN method (returns PIN, if not "
"hardcoded)\n"
" wps_reg <BSSID> <AP PIN> = start WPS Registrar to configure an AP\n"
" terminate = terminate wpa_supplicant\n"
" quit = exit wpa_cli\n";
@ -438,6 +442,80 @@ static int wpa_cli_cmd_ft_ds(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
static int wpa_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
char cmd[256];
int res;
if (argc == 0) {
/* Any BSSID */
return wpa_ctrl_command(ctrl, "WPS_PBC");
}
/* Specific BSSID */
res = os_snprintf(cmd, sizeof(cmd), "WPS_PBC %s", argv[0]);
if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
printf("Too long WPS_PBC command.\n");
return -1;
}
return wpa_ctrl_command(ctrl, cmd);
}
static int wpa_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
char cmd[256];
int res;
if (argc == 0) {
printf("Invalid WPS_PIN command: need one or two arguments:\n"
"- BSSID: use 'any' to select any\n"
"- PIN: optional, used only with devices that have no "
"display\n");
return -1;
}
if (argc == 1) {
/* Use dynamically generated PIN (returned as reply) */
res = os_snprintf(cmd, sizeof(cmd), "WPS_PIN %s", argv[0]);
if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
printf("Too long WPS_PIN command.\n");
return -1;
}
return wpa_ctrl_command(ctrl, cmd);
}
/* Use hardcoded PIN from a label */
res = os_snprintf(cmd, sizeof(cmd), "WPS_PIN %s %s", argv[0], argv[1]);
if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
printf("Too long WPS_PIN command.\n");
return -1;
}
return wpa_ctrl_command(ctrl, cmd);
}
static int wpa_cli_cmd_wps_reg(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
char cmd[256];
int res;
if (argc != 2) {
printf("Invalid WPS_REG command: need two arguments:\n"
"- BSSID: use 'any' to select any\n"
"- AP PIN\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;
}
return wpa_ctrl_command(ctrl, cmd);
}
static int wpa_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
char cmd[256];
@ -1091,6 +1169,9 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
{ "ap_scan", wpa_cli_cmd_ap_scan },
{ "stkstart", wpa_cli_cmd_stkstart },
{ "ft_ds", wpa_cli_cmd_ft_ds },
{ "wps_pbc", wpa_cli_cmd_wps_pbc },
{ "wps_pin", wpa_cli_cmd_wps_pin },
{ "wps_reg", wpa_cli_cmd_wps_reg },
{ NULL, NULL }
};

View file

@ -20,13 +20,20 @@
#include "config.h"
#include "eap_peer/eap.h"
#include "wpa_supplicant_i.h"
#include "eloop.h"
#include "eap_common/eap_wsc_common.h"
#include "wps/wps.h"
#include "wps/wps_defs.h"
#include "wps_supplicant.h"
static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx);
int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
{
eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && wpa_s->current_ssid &&
!(wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
wpa_printf(MSG_DEBUG, "WPS: Network configuration replaced - "
@ -182,6 +189,166 @@ u8 wpas_wps_get_req_type(struct wpa_ssid *ssid)
}
static void wpas_clear_wps(struct wpa_supplicant *wpa_s)
{
int id;
struct wpa_ssid *ssid;
eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
/* Remove any existing WPS network from configuration */
ssid = wpa_s->conf->ssid;
while (ssid) {
if (ssid->key_mgmt & WPA_KEY_MGMT_WPS)
id = ssid->id;
else
id = -1;
ssid = ssid->next;
if (id >= 0)
wpa_config_remove_network(wpa_s->conf, id);
}
}
static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
wpa_printf(MSG_DEBUG, "WPS: Requested operation timed out");
wpas_clear_wps(wpa_s);
}
static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s,
int registrar, const u8 *bssid)
{
struct wpa_ssid *ssid;
ssid = wpa_config_add_network(wpa_s->conf);
if (ssid == NULL)
return NULL;
wpa_config_set_network_defaults(ssid);
if (wpa_config_set(ssid, "key_mgmt", "WPS", 0) < 0 ||
wpa_config_set(ssid, "eap", "WSC", 0) < 0 ||
wpa_config_set(ssid, "identity", registrar ?
"\"" WSC_ID_REGISTRAR "\"" :
"\"" WSC_ID_ENROLLEE "\"", 0) < 0) {
wpa_config_remove_network(wpa_s->conf, ssid->id);
return NULL;
}
if (bssid) {
size_t i;
struct wpa_scan_res *res;
os_memcpy(ssid->bssid, bssid, ETH_ALEN);
/* Try to get SSID from scan results */
if (wpa_s->scan_res == NULL &&
wpa_supplicant_get_scan_results(wpa_s) < 0)
return ssid; /* Could not find any scan results */
for (i = 0; i < wpa_s->scan_res->num; i++) {
const u8 *ie;
res = wpa_s->scan_res->res[i];
if (os_memcmp(bssid, res->bssid, ETH_ALEN) != 0)
continue;
ie = wpa_scan_get_ie(res, WLAN_EID_SSID);
if (ie == NULL)
break;
os_free(ssid->ssid);
ssid->ssid = os_malloc(ie[1]);
if (ssid->ssid == NULL)
break;
os_memcpy(ssid->ssid, ie + 2, ie[1]);
ssid->ssid_len = ie[1];
break;
}
}
return ssid;
}
static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s,
struct wpa_ssid *selected)
{
struct wpa_ssid *ssid;
/* Mark all other networks disabled and trigger reassociation */
ssid = wpa_s->conf->ssid;
while (ssid) {
ssid->disabled = ssid != selected;
ssid = ssid->next;
}
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
wpa_supplicant_req_scan(wpa_s, 0, 0);
}
int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid)
{
struct wpa_ssid *ssid;
wpas_clear_wps(wpa_s);
ssid = wpas_wps_add_network(wpa_s, 0, bssid);
if (ssid == NULL)
return -1;
wpa_config_set(ssid, "phase1", "\"pbc=1\"", 0);
eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
wpa_s, NULL);
wpas_wps_reassoc(wpa_s, ssid);
return 0;
}
int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
const char *pin)
{
struct wpa_ssid *ssid;
char val[30];
unsigned int rpin = 0;
wpas_clear_wps(wpa_s);
ssid = wpas_wps_add_network(wpa_s, 0, bssid);
if (ssid == NULL)
return -1;
if (pin)
os_snprintf(val, sizeof(val), "\"pin=%s\"", pin);
else {
rpin = wps_generate_pin();
os_snprintf(val, sizeof(val), "\"pin=%08d\"", rpin);
}
wpa_config_set(ssid, "phase1", val, 0);
eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
wpa_s, NULL);
wpas_wps_reassoc(wpa_s, ssid);
return rpin;
}
int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid,
const char *pin)
{
struct wpa_ssid *ssid;
char val[30];
if (!pin)
return -1;
wpas_clear_wps(wpa_s);
ssid = wpas_wps_add_network(wpa_s, 1, bssid);
if (ssid == NULL)
return -1;
os_snprintf(val, sizeof(val), "\"pin=%s\"", pin);
wpa_config_set(ssid, "phase1", val, 0);
eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
wpa_s, NULL);
wpas_wps_reassoc(wpa_s, ssid);
return 0;
}
int wpas_wps_init(struct wpa_supplicant *wpa_s)
{
struct wps_context *wps;
@ -215,6 +382,8 @@ int wpas_wps_init(struct wpa_supplicant *wpa_s)
void wpas_wps_deinit(struct wpa_supplicant *wpa_s)
{
eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
if (wpa_s->wps == NULL)
return;

View file

@ -21,6 +21,11 @@ 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);
u8 wpas_wps_get_req_type(struct wpa_ssid *ssid);
int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid);
int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
const char *pin);
int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid,
const char *pin);
#else /* CONFIG_WPS */