aboutsummaryrefslogtreecommitdiffstats
path: root/wpa_supplicant
diff options
context:
space:
mode:
authorJouni Malinen <j@w1.fi>2008-11-29 18:59:45 (GMT)
committerJouni Malinen <j@w1.fi>2008-11-29 18:59:45 (GMT)
commitfcc60db4eb5a8ea4e482b1785fd069b8553fd760 (patch)
tree17fd73b230e7215e1c75b5293c918be9b6c4239b /wpa_supplicant
parente237a6b0d78db62c6b222dca07a008fe21c17f1f (diff)
downloadhostap-fcc60db4eb5a8ea4e482b1785fd069b8553fd760.zip
hostap-fcc60db4eb5a8ea4e482b1785fd069b8553fd760.tar.gz
hostap-fcc60db4eb5a8ea4e482b1785fd069b8553fd760.tar.bz2
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.
Diffstat (limited to 'wpa_supplicant')
-rw-r--r--wpa_supplicant/ctrl_iface.c101
-rw-r--r--wpa_supplicant/wpa_cli.c81
-rw-r--r--wpa_supplicant/wps_supplicant.c169
-rw-r--r--wpa_supplicant/wps_supplicant.h5
4 files changed, 356 insertions, 0 deletions
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index da207d1..3615dd8 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -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(
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 46ec736..51892f6 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -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 }
};
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 5b81d1d..49869f9 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -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;
diff --git a/wpa_supplicant/wps_supplicant.h b/wpa_supplicant/wps_supplicant.h
index 73e7258..1e393e3 100644
--- a/wpa_supplicant/wps_supplicant.h
+++ b/wpa_supplicant/wps_supplicant.h
@@ -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 */