aboutsummaryrefslogtreecommitdiffstats
path: root/wpa_supplicant
diff options
context:
space:
mode:
authorJouni Malinen <j@w1.fi>2008-11-23 17:34:26 (GMT)
committerJouni Malinen <j@w1.fi>2008-11-23 17:34:26 (GMT)
commitad08c3633cc2858d28b30a3545341e1e4dda4a90 (patch)
tree90b8f0ed5762d876df61013e851acc539f29f320 /wpa_supplicant
parent6e89cc438e1af4b9b23341faee40bbe271b3de8d (diff)
downloadhostap-06-ad08c3633cc2858d28b30a3545341e1e4dda4a90.zip
hostap-06-ad08c3633cc2858d28b30a3545341e1e4dda4a90.tar.gz
hostap-06-ad08c3633cc2858d28b30a3545341e1e4dda4a90.tar.bz2
Added preliminary Wi-Fi Protected Setup (WPS) implementation
This adds WPS support for both hostapd and wpa_supplicant. Both programs can be configured to act as WPS Enrollee and Registrar. Both PBC and PIN methods are supported. Currently, hostapd has more complete configuration option for WPS parameters and wpa_supplicant configuration style will likely change in the future. External Registrars are not yet supported in hostapd or wpa_supplicant. While wpa_supplicant has initial support for acting as an Registrar to configure an AP, this is still using number of hardcoded parameters which will need to be made configurable for proper operation.
Diffstat (limited to 'wpa_supplicant')
-rw-r--r--wpa_supplicant/Makefile24
-rw-r--r--wpa_supplicant/config.c4
-rw-r--r--wpa_supplicant/config_file.c2
-rw-r--r--wpa_supplicant/config_winreg.c2
-rw-r--r--wpa_supplicant/ctrl_iface_dbus_handlers.c8
-rw-r--r--wpa_supplicant/defconfig3
-rw-r--r--wpa_supplicant/eapol_test.c1
-rw-r--r--wpa_supplicant/events.c172
-rw-r--r--wpa_supplicant/scan.c51
-rw-r--r--wpa_supplicant/wpa_supplicant.c22
-rw-r--r--wpa_supplicant/wpa_supplicant.conf2
-rw-r--r--wpa_supplicant/wpas_glue.c150
12 files changed, 435 insertions, 6 deletions
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index a835008..2a068d7 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -493,6 +493,26 @@ endif
NEED_SHA256=y
endif
+ifdef CONFIG_WPS
+# EAP-WSC
+ifeq ($(CONFIG_EAP_WSC), dyn)
+CFLAGS += -DCONFIG_WPS -DEAP_WSC_DYNAMIC
+EAPDYN += ../src/eap_peer/eap_wsc.so
+else
+CFLAGS += -DCONFIG_WPS -DEAP_WSC
+OBJS += ../src/utils/uuid.o
+OBJS += ../src/eap_peer/eap_wsc.o ../src/eap_common/eap_wsc_common.o
+OBJS += ../src/wps/wps.o
+OBJS += ../src/wps/wps_common.o
+OBJS += ../src/wps/wps_dev_attr.o
+OBJS += ../src/wps/wps_enrollee.o
+OBJS += ../src/wps/wps_registrar.o
+OBJS_h += ../src/eap_server/eap_wsc.o
+endif
+CONFIG_IEEE8021X_EAPOL=y
+NEED_DH_GROUPS=y
+endif
+
ifdef CONFIG_EAP_IKEV2
# EAP-IKEv2
ifeq ($(CONFIG_EAP_IKEV2), dyn)
@@ -1080,6 +1100,10 @@ eap_sake.so: ../src/eap_peer/eap_sake.c ../src/eap_common/eap_sake_common.c
$(CC) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
-Deap_peer_sake_register=eap_peer_method_dynamic_init
+eap_wsc.so: ../src/eap_peer/eap_wsc.c ../src/eap_common/eap_wsc_common.c ../src/wps/wps.c
+ $(CC) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
+ -Deap_peer_wsc_register=eap_peer_method_dynamic_init
+
eap_ikev2.so: ../src/eap_peer/eap_ikev2.c ../src/eap_peer/ikev2.c ../src/eap_common/eap_ikev2_common.o ../src/eap_common/ikev2_common.c
$(CC) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
-Deap_peer_ikev2_register=eap_peer_method_dynamic_init
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index c95e7a0..c5e300e 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -515,6 +515,10 @@ static int wpa_config_parse_key_mgmt(const struct parse_data *data,
else if (os_strcmp(start, "WPA-EAP-SHA256") == 0)
val |= WPA_KEY_MGMT_IEEE8021X_SHA256;
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_WPS
+ else if (os_strcmp(start, "WPS") == 0)
+ val |= WPA_KEY_MGMT_WPS;
+#endif /* CONFIG_WPS */
else {
wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
line, start);
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 359c5f1..3153214 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -871,6 +871,8 @@ int wpa_config_write(const char *name, struct wpa_config *config)
wpa_config_write_global(f, config);
for (ssid = config->ssid; ssid; ssid = ssid->next) {
+ if (ssid->key_mgmt == WPA_KEY_MGMT_WPS)
+ continue; /* do not save temporary WPS networks */
fprintf(f, "\nnetwork={\n");
wpa_config_write_network(f, ssid);
fprintf(f, "}\n");
diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c
index 4ec50f6..48e5c80 100644
--- a/wpa_supplicant/config_winreg.c
+++ b/wpa_supplicant/config_winreg.c
@@ -874,6 +874,8 @@ int wpa_config_write(const char *name, struct wpa_config *config)
wpa_config_delete_subkeys(hk, TEXT("networks"));
for (ssid = config->ssid, id = 0; ssid; ssid = ssid->next, id++) {
+ if (ssid->key_mgmt == WPA_KEY_MGMT_WPS)
+ continue; /* do not save temporary WPS networks */
if (wpa_config_write_network(hk, ssid, id))
errors++;
}
diff --git a/wpa_supplicant/ctrl_iface_dbus_handlers.c b/wpa_supplicant/ctrl_iface_dbus_handlers.c
index 62751ad..015eb54 100644
--- a/wpa_supplicant/ctrl_iface_dbus_handlers.c
+++ b/wpa_supplicant/ctrl_iface_dbus_handlers.c
@@ -420,6 +420,14 @@ DBusMessage * wpas_dbus_bssid_properties(DBusMessage *message,
goto error;
}
+ ie = wpa_scan_get_vendor_ie(res, WPS_IE_VENDOR_TYPE);
+ if (ie) {
+ if (!wpa_dbus_dict_append_byte_array(&iter_dict, "wpsie",
+ (const char *) ie,
+ ie[1] + 2))
+ goto error;
+ }
+
if (res->freq) {
if (!wpa_dbus_dict_append_int32(&iter_dict, "frequency",
res->freq))
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index abf2408..e62b9b3 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -170,6 +170,9 @@ CONFIG_EAP_LEAP=y
# EAP-TNC and related Trusted Network Connect support (experimental)
#CONFIG_EAP_TNC=y
+# Wi-Fi Protected Setup (WPS)
+#CONFIG_WPS=y
+
# EAP-IKEv2
#CONFIG_EAP_IKEV2=y
diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c
index 4d96785..f650c85 100644
--- a/wpa_supplicant/eapol_test.c
+++ b/wpa_supplicant/eapol_test.c
@@ -336,6 +336,7 @@ static int test_eapol(struct eapol_test_data *e, struct wpa_supplicant *wpa_s,
ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
#endif /* EAP_TLS_OPENSSL */
+ ctx->mac_addr = wpa_s->own_addr;
wpa_s->eapol = eapol_sm_init(ctx);
if (wpa_s->eapol == NULL) {
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 27dfd55..34b06e3 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -31,6 +31,7 @@
#include "ieee802_11_defs.h"
#include "blacklist.h"
#include "wpas_glue.h"
+#include "wps/wps.h"
static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
@@ -276,6 +277,53 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_ssid *ssid,
int proto_match = 0;
const u8 *rsn_ie, *wpa_ie;
+#ifdef CONFIG_WPS
+ if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
+ const u8 *wps_ie;
+ wps_ie = wpa_scan_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE);
+ if (eap_is_wps_pbc_enrollee(&ssid->eap)) {
+ if (!wps_ie) {
+ wpa_printf(MSG_DEBUG, " skip - non-WPS AP");
+ return 0;
+ }
+
+ if (!wps_is_selected_pbc_registrar(wps_ie + 6,
+ wps_ie[1] - 4)) {
+ wpa_printf(MSG_DEBUG, " skip - WPS AP "
+ "without active PBC Registrar");
+ return 0;
+ }
+
+ /* TODO: overlap detection */
+ wpa_printf(MSG_DEBUG, " selected based on WPS IE "
+ "(Active PBC)");
+ return 1;
+ }
+
+ if (eap_is_wps_pin_enrollee(&ssid->eap)) {
+ if (!wps_ie) {
+ wpa_printf(MSG_DEBUG, " skip - non-WPS AP");
+ return 0;
+ }
+
+ if (!wps_is_selected_pin_registrar(wps_ie + 6,
+ wps_ie[1] - 4)) {
+ wpa_printf(MSG_DEBUG, " skip - WPS AP "
+ "without active PIN Registrar");
+ return 0;
+ }
+ wpa_printf(MSG_DEBUG, " selected based on WPS IE "
+ "(Active PIN)");
+ return 1;
+ }
+
+ if (wps_ie) {
+ wpa_printf(MSG_DEBUG, " selected based on WPS IE");
+ return 1;
+ }
+ }
+#endif /* CONFIG_WPS */
+
rsn_ie = wpa_scan_get_ie(bss, WLAN_EID_RSN);
while ((ssid->proto & WPA_PROTO_RSN) && rsn_ie) {
proto_match++;
@@ -364,6 +412,34 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_ssid *ssid,
}
+#ifdef CONFIG_WPS
+static int wps_ssid_wildcard_ok(struct wpa_ssid *ssid,
+ struct wpa_scan_res *bss)
+{
+ const u8 *wps_ie;
+
+ if (eap_is_wps_pbc_enrollee(&ssid->eap)) {
+ wps_ie = wpa_scan_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE);
+ if (wps_ie &&
+ wps_is_selected_pbc_registrar(wps_ie + 6, wps_ie[1] - 4)) {
+ /* allow wildcard SSID for WPS PBC */
+ return 1;
+ }
+ }
+
+ if (eap_is_wps_pin_enrollee(&ssid->eap)) {
+ wps_ie = wpa_scan_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE);
+ if (wps_ie &&
+ wps_is_selected_pin_registrar(wps_ie + 6, wps_ie[1] - 4)) {
+ /* allow wildcard SSID for WPS PIN */
+ return 1;
+ }
+ }
+
+ return 0;
+}
+#endif /* CONFIG_WPS */
+
static struct wpa_scan_res *
wpa_supplicant_select_bss_wpa(struct wpa_supplicant *wpa_s,
struct wpa_ssid *group,
@@ -409,13 +485,22 @@ wpa_supplicant_select_bss_wpa(struct wpa_supplicant *wpa_s,
}
for (ssid = group; ssid; ssid = ssid->pnext) {
+ int check_ssid = 1;
+
if (ssid->disabled) {
wpa_printf(MSG_DEBUG, " skip - disabled");
continue;
}
- if (ssid_len != ssid->ssid_len ||
- os_memcmp(ssid_, ssid->ssid, ssid_len) != 0) {
+#ifdef CONFIG_WPS
+ if (ssid->ssid_len == 0 &&
+ wps_ssid_wildcard_ok(ssid, bss))
+ check_ssid = 0;
+#endif /* CONFIG_WPS */
+
+ if (check_ssid &&
+ (ssid_len != ssid->ssid_len ||
+ os_memcmp(ssid_, ssid->ssid, ssid_len) != 0)) {
wpa_printf(MSG_DEBUG, " skip - "
"SSID mismatch");
continue;
@@ -485,12 +570,26 @@ wpa_supplicant_select_bss_non_wpa(struct wpa_supplicant *wpa_s,
}
for (ssid = group; ssid; ssid = ssid->pnext) {
+ int check_ssid = ssid->ssid_len != 0;
+
if (ssid->disabled) {
wpa_printf(MSG_DEBUG, " skip - disabled");
continue;
}
- if (ssid->ssid_len != 0 &&
+#ifdef CONFIG_WPS
+ if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
+ /* Only allow wildcard SSID match if an AP
+ * advertises active WPS operation that matches
+ * with our mode. */
+ check_ssid = 1;
+ if (ssid->ssid_len == 0 &&
+ wps_ssid_wildcard_ok(ssid, bss))
+ check_ssid = 0;
+ }
+#endif /* CONFIG_WPS */
+
+ if (check_ssid &&
(ssid_len != ssid->ssid_len ||
os_memcmp(ssid_, ssid->ssid, ssid_len) != 0)) {
wpa_printf(MSG_DEBUG, " skip - "
@@ -507,6 +606,7 @@ wpa_supplicant_select_bss_non_wpa(struct wpa_supplicant *wpa_s,
}
if (!(ssid->key_mgmt & WPA_KEY_MGMT_NONE) &&
+ !(ssid->key_mgmt & WPA_KEY_MGMT_WPS) &&
!(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA))
{
wpa_printf(MSG_DEBUG, " skip - "
@@ -570,6 +670,65 @@ wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s, struct wpa_ssid *group,
}
+#ifdef CONFIG_WPS
+
+static int wpa_scan_pbc_overlap(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_res *selected,
+ struct wpa_ssid *ssid)
+{
+ const u8 *sel_uuid, *uuid;
+ size_t i;
+ const u8 *wps_ie;
+
+ if (!eap_is_wps_pbc_enrollee(&ssid->eap))
+ return 0;
+
+ /* Make sure that only one AP is in active PBC mode */
+ wps_ie = wpa_scan_get_vendor_ie(selected, WPS_IE_VENDOR_TYPE);
+ if (wps_ie)
+ sel_uuid = wps_get_uuid_e(wps_ie + 6, wps_ie[1] - 4);
+ else
+ sel_uuid = NULL;
+ if (!sel_uuid) {
+ wpa_printf(MSG_DEBUG, "WPS: UUID-E not "
+ "available for PBC overlap "
+ "detection");
+ return 1;
+ }
+
+ for (i = 0; i < wpa_s->scan_res->num; i++) {
+ struct wpa_scan_res *bss = wpa_s->scan_res->res[i];
+ if (bss == selected)
+ continue;
+ wps_ie = wpa_scan_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE);
+ if (!wps_ie)
+ continue;
+ if (!wps_is_selected_pbc_registrar(wps_ie + 6,
+ wps_ie[1] - 4))
+ continue;
+ uuid = wps_get_uuid_e(wps_ie + 6, wps_ie[1] - 4);
+ if (uuid == NULL) {
+ wpa_printf(MSG_DEBUG, "WPS: UUID-E not "
+ "available for PBC overlap "
+ "detection (other BSS)");
+ return 1;
+ }
+ if (os_memcmp(sel_uuid, uuid, 16) != 0)
+ return 1; /* PBC overlap */
+
+ /* TODO: verify that this is reasonable dual-band situation */
+ }
+
+ return 0;
+}
+
+#else /* CONFIG_WPS */
+
+#define wpa_scan_pbc_overlap(w, s, i) 0
+
+#endif /* CONFIG_WPS */
+
+
static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s)
{
int prio, timeout;
@@ -619,6 +778,13 @@ static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s)
}
if (selected) {
+ if (wpa_scan_pbc_overlap(wpa_s, selected, ssid)) {
+ wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_OVERLAP
+ "PBC session overlap");
+ timeout = 10;
+ goto req_scan;
+ }
+
/* Do not trigger new association unless the BSSID has changed
* or if reassociation is requested. If we are in process of
* associating with the selected BSSID, do not trigger new
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 3c5bad9..04b6d44 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -20,6 +20,7 @@
#include "wpa_supplicant_i.h"
#include "mlme.h"
#include "uuid.h"
+#include "wps/wps.h"
static void wpa_supplicant_gen_assoc_event(struct wpa_supplicant *wpa_s)
@@ -41,13 +42,45 @@ static void wpa_supplicant_gen_assoc_event(struct wpa_supplicant *wpa_s)
}
+#ifdef CONFIG_WPS
+static int wpas_wps_in_use(struct wpa_config *conf, u8 *uuid)
+{
+ struct wpa_ssid *ssid;
+ int wps = 0;
+ const char *pos;
+
+ for (ssid = conf->ssid; ssid; ssid = ssid->next) {
+ if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS))
+ continue;
+
+ wps = 1;
+ if (!ssid->eap.phase1)
+ continue;
+
+ pos = os_strstr(ssid->eap.phase1, "uuid=");
+ if (pos)
+ uuid_str2bin(pos + 5, uuid);
+
+ if (os_strstr(ssid->eap.phase1, "pbc=1"))
+ return 2;
+ }
+
+ return wps;
+}
+#endif /* CONFIG_WPS */
+
static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
struct wpa_ssid *ssid;
int enabled, scan_req = 0, ret;
+ struct wpabuf *wps_ie = NULL;
const u8 *extra_ie = NULL;
size_t extra_ie_len = 0;
+ int wps = 0;
+#ifdef CONFIG_WPS
+ u8 uuid[UUID_LEN];
+#endif /* CONFIG_WPS */
if (wpa_s->disconnected && !wpa_s->scan_req)
return;
@@ -134,8 +167,12 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
} else
wpa_s->prev_scan_ssid = BROADCAST_SSID_SCAN;
+#ifdef CONFIG_WPS
+ wps = wpas_wps_in_use(wpa_s->conf, uuid);
+#endif /* CONFIG_WPS */
+
if (wpa_s->scan_res_tried == 0 && wpa_s->conf->ap_scan == 1 &&
- !wpa_s->use_client_mlme) {
+ !wpa_s->use_client_mlme && wps != 2) {
wpa_s->scan_res_tried++;
wpa_s->scan_req = scan_req;
wpa_printf(MSG_DEBUG, "Trying to get current scan results "
@@ -145,6 +182,16 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
return;
}
+#ifdef CONFIG_WPS
+ if (wps) {
+ wps_ie = wps_enrollee_build_probe_req_ie(wps == 2, uuid);
+ if (wps_ie) {
+ extra_ie = wpabuf_head(wps_ie);
+ extra_ie_len = wpabuf_len(wps_ie);
+ }
+ }
+#endif /* CONFIG_WPS */
+
if (wpa_s->use_client_mlme) {
ieee80211_sta_set_probe_req_ie(wpa_s, extra_ie, extra_ie_len);
ret = ieee80211_sta_req_scan(wpa_s, ssid ? ssid->ssid : NULL,
@@ -155,6 +202,8 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
ssid ? ssid->ssid_len : 0);
}
+ wpabuf_free(wps_ie);
+
if (ret) {
wpa_printf(MSG_WARNING, "Failed to initiate AP scan.");
wpa_supplicant_req_scan(wpa_s, 10, 0);
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index dba3f13..e9c9228 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -38,6 +38,7 @@
#include "ieee802_11_defs.h"
#include "blacklist.h"
#include "wpas_glue.h"
+#include "wps/wps.h"
const char *wpa_supplicant_version =
"wpa_supplicant v" VERSION_STR "\n"
@@ -282,7 +283,8 @@ void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
eapol_conf.workaround = ssid->eap_workaround;
eapol_conf.eap_disabled =
!wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) &&
- wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA;
+ wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
+ wpa_s->key_mgmt != WPA_KEY_MGMT_WPS;
eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
#endif /* IEEE8021X_EAPOL */
}
@@ -302,7 +304,9 @@ void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
{
int i;
- if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)
+ if (ssid->key_mgmt & WPA_KEY_MGMT_WPS)
+ wpa_s->key_mgmt = WPA_KEY_MGMT_WPS;
+ else if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)
wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_NO_WPA;
else
wpa_s->key_mgmt = WPA_KEY_MGMT_NONE;
@@ -635,6 +639,8 @@ static wpa_key_mgmt key_mgmt2driver(int key_mgmt)
return KEY_MGMT_802_1X_SHA256;
case WPA_KEY_MGMT_PSK_SHA256:
return KEY_MGMT_PSK_SHA256;
+ case WPA_KEY_MGMT_WPS:
+ return KEY_MGMT_WPS;
case WPA_KEY_MGMT_PSK:
default:
return KEY_MGMT_PSK;
@@ -1001,6 +1007,16 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
"results)");
return;
}
+#ifdef CONFIG_WPS
+ } else if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
+ struct wpabuf *wps_ie = wps_enrollee_build_assoc_req_ie();
+ if (wps_ie && wpabuf_len(wps_ie) <= sizeof(wpa_ie)) {
+ wpa_ie_len = wpabuf_len(wps_ie);
+ os_memcpy(wpa_ie, wpabuf_head(wps_ie), wpa_ie_len);
+ }
+ wpabuf_free(wps_ie);
+ wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
+#endif /* CONFIG_WPS */
} else {
wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
wpa_ie_len = 0;
@@ -1019,6 +1035,8 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
wep_keys_set = 1;
}
}
+ if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS)
+ use_crypt = 0;
#ifdef IEEE8021X_EAPOL
if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index dd4f579..a4c1ca7 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -397,6 +397,8 @@ fast_reauth=1
# * 0 = do not use cryptobinding (default)
# * 1 = use cryptobinding if server supports it
# * 2 = require cryptobinding
+# EAP-WSC (WPS) uses following options: pin=<Device Password> and
+# uuid=<Device UUID>.
# phase2: Phase2 (inner authentication with TLS tunnel) parameters
# (string with field-value pairs, e.g., "auth=MSCHAPV2" for EAP-PEAP or
# "autheap=MSCHAPV2 autheap=MD5" for EAP-TTLS)
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index e1e2cd6..41159bb 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -25,6 +25,8 @@
#include "pmksa_cache.h"
#include "mlme.h"
#include "ieee802_11_defs.h"
+#include "wps/wps.h"
+#include "wps/wps_defs.h"
#include "wpa_ctrl.h"
#include "wpas_glue.h"
@@ -228,6 +230,19 @@ static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol, int success,
wpa_printf(MSG_DEBUG, "EAPOL authentication completed %ssuccessfully",
success ? "" : "un");
+#ifdef CONFIG_WPS
+ 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 - "
+ "try to associate with the received credential");
+ wpa_supplicant_deauthenticate(wpa_s,
+ WLAN_REASON_DEAUTH_LEAVING);
+ wpa_s->reassociate = 1;
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+ return;
+ }
+#endif /* CONFIG_WPS */
+
if (!success) {
/*
* Make sure we do not get stuck here waiting for long EAPOL
@@ -491,6 +506,139 @@ static int wpa_supplicant_send_ft_action(void *ctx, u8 action,
#endif /* CONFIG_NO_WPA */
+#ifdef CONFIG_WPS
+static int wpa_supplicant_wps_cred(void *ctx, struct wps_credential *cred)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+ wpa_msg(wpa_s, MSG_INFO, "WPS: New credential received");
+
+ if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
+ wpa_printf(MSG_DEBUG, "WPS: Replace WPS network block based "
+ "on the received credential");
+ os_free(ssid->eap.identity);
+ ssid->eap.identity = NULL;
+ ssid->eap.identity_len = 0;
+ os_free(ssid->eap.phase1);
+ ssid->eap.phase1 = NULL;
+ os_free(ssid->eap.eap_methods);
+ ssid->eap.eap_methods = NULL;
+ } else {
+ wpa_printf(MSG_DEBUG, "WPS: Create a new network based on the "
+ "received credential");
+ ssid = wpa_config_add_network(wpa_s->conf);
+ if (ssid == NULL)
+ return -1;
+ }
+
+ wpa_config_set_network_defaults(ssid);
+
+ os_free(ssid->ssid);
+ ssid->ssid = os_malloc(cred->ssid_len);
+ if (ssid->ssid) {
+ os_memcpy(ssid->ssid, cred->ssid, cred->ssid_len);
+ ssid->ssid_len = cred->ssid_len;
+ }
+
+ switch (cred->encr_type) {
+ case WPS_ENCR_NONE:
+ ssid->pairwise_cipher = ssid->group_cipher = WPA_CIPHER_NONE;
+ break;
+ case WPS_ENCR_WEP:
+ ssid->pairwise_cipher = ssid->group_cipher =
+ WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104;
+ if (cred->key_len > 0 && cred->key_len <= MAX_WEP_KEY_LEN &&
+ cred->key_idx < NUM_WEP_KEYS) {
+ os_memcpy(ssid->wep_key[cred->key_idx], cred->key,
+ cred->key_len);
+ ssid->wep_key_len[cred->key_idx] = cred->key_len;
+ ssid->wep_tx_keyidx = cred->key_idx;
+ }
+ break;
+ case WPS_ENCR_TKIP:
+ ssid->pairwise_cipher = WPA_CIPHER_TKIP;
+ ssid->group_cipher = WPA_CIPHER_TKIP;
+ break;
+ case WPS_ENCR_AES:
+ ssid->pairwise_cipher = WPA_CIPHER_CCMP;
+ ssid->group_cipher = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP;
+ break;
+ }
+
+ switch (cred->auth_type) {
+ case WPS_AUTH_OPEN:
+ ssid->auth_alg = WPA_AUTH_ALG_OPEN;
+ ssid->key_mgmt = WPA_KEY_MGMT_NONE;
+ ssid->proto = 0;
+ break;
+ case WPS_AUTH_SHARED:
+ ssid->auth_alg = WPA_AUTH_ALG_SHARED;
+ ssid->key_mgmt = WPA_KEY_MGMT_NONE;
+ ssid->proto = 0;
+ break;
+ case WPS_AUTH_WPAPSK:
+ ssid->auth_alg = WPA_AUTH_ALG_OPEN;
+ ssid->key_mgmt = WPA_KEY_MGMT_PSK;
+ ssid->proto = WPA_PROTO_WPA;
+ break;
+ case WPS_AUTH_WPA:
+ ssid->auth_alg = WPA_AUTH_ALG_OPEN;
+ ssid->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
+ ssid->proto = WPA_PROTO_WPA;
+ break;
+ case WPS_AUTH_WPA2:
+ ssid->auth_alg = WPA_AUTH_ALG_OPEN;
+ ssid->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
+ ssid->proto = WPA_PROTO_RSN;
+ break;
+ case WPS_AUTH_WPA2PSK:
+ ssid->auth_alg = WPA_AUTH_ALG_OPEN;
+ ssid->key_mgmt = WPA_KEY_MGMT_PSK;
+ ssid->proto = WPA_PROTO_RSN;
+ break;
+ }
+
+ if (ssid->key_mgmt == WPA_KEY_MGMT_PSK) {
+ if (cred->key_len == 2 * PMK_LEN) {
+ if (hexstr2bin((const char *) cred->key, ssid->psk,
+ PMK_LEN)) {
+ wpa_printf(MSG_ERROR, "WPS: Invalid Network "
+ "Key");
+ return -1;
+ }
+ ssid->psk_set = 1;
+ } else if (cred->key_len >= 8 && cred->key_len < 2 * PMK_LEN) {
+ os_free(ssid->passphrase);
+ ssid->passphrase = os_malloc(cred->key_len + 1);
+ if (ssid->passphrase == NULL)
+ return -1;
+ os_memcpy(ssid->passphrase, cred->key, cred->key_len);
+ ssid->passphrase[cred->key_len] = '\0';
+ wpa_config_update_psk(ssid);
+ } else {
+ wpa_printf(MSG_ERROR, "WPS: Invalid Network Key "
+ "length %lu",
+ (unsigned long) cred->key_len);
+ return -1;
+ }
+ }
+
+#ifndef CONFIG_NO_CONFIG_WRITE
+ if (wpa_s->conf->update_config &&
+ wpa_config_write(wpa_s->confname, wpa_s->conf)) {
+ wpa_printf(MSG_DEBUG, "WPS: Failed to update configuration");
+ return -1;
+ }
+#endif /* CONFIG_NO_CONFIG_WRITE */
+
+ return 0;
+}
+#else /* CONFIG_WPS */
+#define wpa_supplicant_wps_cred NULL
+#endif /* CONFIG_WPS */
+
+
#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
static void wpa_supplicant_eap_param_needed(void *ctx, const char *field,
const char *txt)
@@ -554,6 +702,8 @@ int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s)
ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
#endif /* EAP_TLS_OPENSSL */
+ ctx->mac_addr = wpa_s->own_addr;
+ ctx->wps_cred = wpa_supplicant_wps_cred;
ctx->eap_param_needed = wpa_supplicant_eap_param_needed;
ctx->cb = wpa_supplicant_eapol_cb;
ctx->cb_ctx = wpa_s;