wps_hostapd.c revision 7f65602d49069f96a7bb44da8bd79ffe8d4c6a98
18e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener/*
28e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener * hostapd / WPS integration
38e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
48e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener *
58e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener * This software may be distributed under the terms of the BSD license.
68e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener * See README for more details.
78e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener */
88e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
98e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener#include "utils/includes.h"
108e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
118e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener#include "utils/common.h"
128e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener#include "utils/eloop.h"
138e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener#include "utils/uuid.h"
148e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener#include "common/wpa_ctrl.h"
158e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener#include "common/ieee802_11_defs.h"
168e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener#include "common/ieee802_11_common.h"
178e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener#include "eapol_auth/eapol_auth_sm.h"
188e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener#include "eapol_auth/eapol_auth_sm_i.h"
198e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener#include "wps/wps.h"
208e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener#include "wps/wps_defs.h"
218e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener#include "wps/wps_dev_attr.h"
228e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener#include "wps/wps_attr_parse.h"
238e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener#include "hostapd.h"
248e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener#include "ap_config.h"
258e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener#include "ap_drv_ops.h"
268e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener#include "beacon.h"
278e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener#include "sta_info.h"
288e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener#include "wps_hostapd.h"
298e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
308e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
318e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener#ifdef CONFIG_WPS_UPNP
328e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener#include "wps/wps_upnp.h"
338e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstatic int hostapd_wps_upnp_init(struct hostapd_data *hapd,
348e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener				 struct wps_context *wps);
358e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstatic void hostapd_wps_upnp_deinit(struct hostapd_data *hapd);
368e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener#endif /* CONFIG_WPS_UPNP */
378e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
388e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstatic int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, const u8 *da,
398e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener				    const u8 *bssid,
408e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener				    const u8 *ie, size_t ie_len,
418e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener				    int ssi_signal);
428e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstatic void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx);
438e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstatic void hostapd_wps_nfc_clear(struct wps_context *wps);
448e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
458e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
468e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstruct wps_for_each_data {
478e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	int (*func)(struct hostapd_data *h, void *ctx);
488e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	void *ctx;
498e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	struct hostapd_data *calling_hapd;
508e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener};
518e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
528e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
538e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstatic int wps_for_each(struct hostapd_iface *iface, void *ctx)
548e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener{
558e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	struct wps_for_each_data *data = ctx;
568e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	size_t j;
578e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
588e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (iface == NULL)
598e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		return 0;
608e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	for (j = 0; j < iface->num_bss; j++) {
618e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		struct hostapd_data *hapd = iface->bss[j];
628e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		int ret;
638e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
648e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		if (hapd != data->calling_hapd &&
658e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		    (hapd->conf->wps_independent ||
668e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		     data->calling_hapd->conf->wps_independent))
678e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			continue;
688e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
698e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		ret = data->func(hapd, data->ctx);
708e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		if (ret)
718e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			return ret;
728e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	}
738e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
748e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	return 0;
758e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener}
768e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
778e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
788e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstatic int hostapd_wps_for_each(struct hostapd_data *hapd,
798e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener				int (*func)(struct hostapd_data *h, void *ctx),
808e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener				void *ctx)
818e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener{
828e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	struct hostapd_iface *iface = hapd->iface;
838e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	struct wps_for_each_data data;
848e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	data.func = func;
858e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	data.ctx = ctx;
868e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	data.calling_hapd = hapd;
878e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (iface->interfaces == NULL ||
888e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	    iface->interfaces->for_each_interface == NULL)
898e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		return wps_for_each(iface, &data);
908e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	return iface->interfaces->for_each_interface(iface->interfaces,
918e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener						     wps_for_each, &data);
928e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener}
938e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
948e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
958e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstatic int hostapd_wps_new_psk_cb(void *ctx, const u8 *mac_addr,
968e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener				  const u8 *p2p_dev_addr, const u8 *psk,
978e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener				  size_t psk_len)
988e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener{
998e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	struct hostapd_data *hapd = ctx;
1008e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	struct hostapd_wpa_psk *p;
1018e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	struct hostapd_ssid *ssid = &hapd->conf->ssid;
1028e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
1038e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (is_zero_ether_addr(p2p_dev_addr)) {
1048e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		wpa_printf(MSG_DEBUG,
1058e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			   "Received new WPA/WPA2-PSK from WPS for STA " MACSTR,
1068e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			   MAC2STR(mac_addr));
1078e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	} else {
1088e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		wpa_printf(MSG_DEBUG,
1098e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			   "Received new WPA/WPA2-PSK from WPS for STA " MACSTR
1108e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			   " P2P Device Addr " MACSTR,
1118e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			   MAC2STR(mac_addr), MAC2STR(p2p_dev_addr));
1128e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	}
1138e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	wpa_hexdump_key(MSG_DEBUG, "Per-device PSK", psk, psk_len);
1148e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
1158e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (psk_len != PMK_LEN) {
1168e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		wpa_printf(MSG_DEBUG, "Unexpected PSK length %lu",
1178e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			   (unsigned long) psk_len);
1188e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		return -1;
1198e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	}
1208e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
1218e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	/* Add the new PSK to runtime PSK list */
1228e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	p = os_zalloc(sizeof(*p));
1238e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (p == NULL)
1248e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		return -1;
1258e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	os_memcpy(p->addr, mac_addr, ETH_ALEN);
1268e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	os_memcpy(p->p2p_dev_addr, p2p_dev_addr, ETH_ALEN);
1278e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	os_memcpy(p->psk, psk, PMK_LEN);
1288e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
1298e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (hapd->new_psk_cb) {
1308e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		hapd->new_psk_cb(hapd->new_psk_cb_ctx, mac_addr, p2p_dev_addr,
1318e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener				 psk, psk_len);
1328e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	}
1338e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
1348e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	p->next = ssid->wpa_psk;
1358e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	ssid->wpa_psk = p;
1368e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
1378e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (ssid->wpa_psk_file) {
1388e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		FILE *f;
1398e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		char hex[PMK_LEN * 2 + 1];
1408e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		/* Add the new PSK to PSK list file */
1418e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		f = fopen(ssid->wpa_psk_file, "a");
1428e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		if (f == NULL) {
1438e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			wpa_printf(MSG_DEBUG, "Failed to add the PSK to "
1448e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener				   "'%s'", ssid->wpa_psk_file);
1458e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			return -1;
1468e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		}
1478e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
1488e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		wpa_snprintf_hex(hex, sizeof(hex), psk, psk_len);
1498e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		fprintf(f, MACSTR " %s\n", MAC2STR(mac_addr), hex);
1508e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		fclose(f);
1518e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	}
1528e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
1538e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	return 0;
1548e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener}
1558e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
1568e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
1578e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstatic int hostapd_wps_set_ie_cb(void *ctx, struct wpabuf *beacon_ie,
1588e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener				 struct wpabuf *probe_resp_ie)
1598e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener{
1608e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	struct hostapd_data *hapd = ctx;
1618e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	wpabuf_free(hapd->wps_beacon_ie);
1628e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	hapd->wps_beacon_ie = beacon_ie;
1638e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	wpabuf_free(hapd->wps_probe_resp_ie);
1648e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	hapd->wps_probe_resp_ie = probe_resp_ie;
1658e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (hapd->beacon_set_done)
1668e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		ieee802_11_set_beacon(hapd);
1678e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	return hostapd_set_ap_wps_ie(hapd);
1688e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener}
1698e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
1708e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
1718e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstatic void hostapd_wps_pin_needed_cb(void *ctx, const u8 *uuid_e,
1728e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener				      const struct wps_device_data *dev)
1738e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener{
1748e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	struct hostapd_data *hapd = ctx;
1758e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	char uuid[40], txt[400];
1768e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	int len;
1778e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	char devtype[WPS_DEV_TYPE_BUFSIZE];
1788e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
1798e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		return;
1808e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	wpa_printf(MSG_DEBUG, "WPS: PIN needed for E-UUID %s", uuid);
1818e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	len = os_snprintf(txt, sizeof(txt), WPS_EVENT_PIN_NEEDED
1828e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			  "%s " MACSTR " [%s|%s|%s|%s|%s|%s]",
1838e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			  uuid, MAC2STR(dev->mac_addr), dev->device_name,
1848e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			  dev->manufacturer, dev->model_name,
1858e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			  dev->model_number, dev->serial_number,
1868e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			  wps_dev_type_bin2str(dev->pri_dev_type, devtype,
1878e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener					       sizeof(devtype)));
1888e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (!os_snprintf_error(sizeof(txt), len))
1898e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		wpa_msg(hapd->msg_ctx, MSG_INFO, "%s", txt);
1908e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
1918e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (hapd->conf->wps_pin_requests) {
1928e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		FILE *f;
1938e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		struct os_time t;
1948e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		f = fopen(hapd->conf->wps_pin_requests, "a");
1958e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		if (f == NULL)
1968e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			return;
1978e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		os_get_time(&t);
1988e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		fprintf(f, "%ld\t%s\t" MACSTR "\t%s\t%s\t%s\t%s\t%s"
1998e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			"\t%s\n",
2008e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			t.sec, uuid, MAC2STR(dev->mac_addr), dev->device_name,
2018e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			dev->manufacturer, dev->model_name, dev->model_number,
2028e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			dev->serial_number,
2038e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			wps_dev_type_bin2str(dev->pri_dev_type, devtype,
2048e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener					     sizeof(devtype)));
2058e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		fclose(f);
2068e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	}
2078e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener}
2088e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
2098e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
2108e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstruct wps_stop_reg_data {
2118e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	struct hostapd_data *current_hapd;
2128e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	const u8 *uuid_e;
2138e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	const u8 *dev_pw;
2148e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	size_t dev_pw_len;
2158e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener};
2168e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
2178e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstatic int wps_stop_registrar(struct hostapd_data *hapd, void *ctx)
2188e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener{
2198e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	struct wps_stop_reg_data *data = ctx;
2208e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (hapd != data->current_hapd && hapd->wps != NULL)
2218e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		wps_registrar_complete(hapd->wps->registrar, data->uuid_e,
2228e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener				       data->dev_pw, data->dev_pw_len);
2238e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	return 0;
2248e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener}
2258e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
2268e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
2278e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstatic void hostapd_wps_reg_success_cb(void *ctx, const u8 *mac_addr,
2288e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener				       const u8 *uuid_e, const u8 *dev_pw,
2298e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener				       size_t dev_pw_len)
2308e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener{
2318e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	struct hostapd_data *hapd = ctx;
2328e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	char uuid[40];
2338e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	struct wps_stop_reg_data data;
2348e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
2358e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		return;
2368e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_REG_SUCCESS MACSTR " %s",
2378e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		MAC2STR(mac_addr), uuid);
2388e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (hapd->wps_reg_success_cb)
2398e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		hapd->wps_reg_success_cb(hapd->wps_reg_success_cb_ctx,
2408e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener					 mac_addr, uuid_e);
2418e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	data.current_hapd = hapd;
2428e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	data.uuid_e = uuid_e;
2438e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	data.dev_pw = dev_pw;
2448e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	data.dev_pw_len = dev_pw_len;
2458e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	hostapd_wps_for_each(hapd, wps_stop_registrar, &data);
2468e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener}
2478e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
2488e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
2498e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstatic void hostapd_wps_enrollee_seen_cb(void *ctx, const u8 *addr,
2508e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener					 const u8 *uuid_e,
2518e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener					 const u8 *pri_dev_type,
2528e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener					 u16 config_methods,
2538e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener					 u16 dev_password_id, u8 request_type,
2548e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener					 const char *dev_name)
2558e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener{
2568e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	struct hostapd_data *hapd = ctx;
2578e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	char uuid[40];
2588e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	char devtype[WPS_DEV_TYPE_BUFSIZE];
2598e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
2608e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		return;
2618e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (dev_name == NULL)
2628e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		dev_name = "";
2638e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO, WPS_EVENT_ENROLLEE_SEEN MACSTR
2648e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		     " %s %s 0x%x %u %u [%s]",
2658e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		     MAC2STR(addr), uuid,
2668e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		     wps_dev_type_bin2str(pri_dev_type, devtype,
2678e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener					  sizeof(devtype)),
2688e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		     config_methods, dev_password_id, request_type, dev_name);
2698e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener}
2708e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
2718e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
2728e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstatic int str_starts(const char *str, const char *start)
2738e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener{
2748e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	return os_strncmp(str, start, os_strlen(start)) == 0;
2758e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener}
2768e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
2778e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
2788e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstatic void wps_reload_config(void *eloop_data, void *user_ctx)
2798e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener{
2808e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	struct hostapd_iface *iface = eloop_data;
2818e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
2828e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	wpa_printf(MSG_DEBUG, "WPS: Reload configuration data");
2838e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (iface->interfaces == NULL ||
2848e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	    iface->interfaces->reload_config(iface) < 0) {
2858e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		wpa_printf(MSG_WARNING, "WPS: Failed to reload the updated "
2868e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			   "configuration");
2878e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	}
2888e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener}
2898e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
2908e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
2918e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienervoid hostapd_wps_eap_completed(struct hostapd_data *hapd)
2928e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener{
2938e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	/*
2948e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	 * Reduce race condition of the station trying to reconnect immediately
2958e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	 * after AP reconfiguration through WPS by rescheduling the reload
2968e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	 * timeout to happen after EAP completion rather than the originally
2978e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	 * scheduled 100 ms after new configuration became known.
2988e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	 */
2998e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (eloop_deplete_timeout(0, 0, wps_reload_config, hapd->iface, NULL) ==
3008e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	    1)
3018e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		wpa_printf(MSG_DEBUG, "WPS: Reschedule immediate configuration reload");
3028e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener}
3038e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
3048e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
3058e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstatic void hapd_new_ap_event(struct hostapd_data *hapd, const u8 *attr,
3068e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			      size_t attr_len)
3078e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener{
3088e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	size_t blen = attr_len * 2 + 1;
3098e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	char *buf = os_malloc(blen);
3108e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (buf) {
3118e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		wpa_snprintf_hex(buf, blen, attr, attr_len);
3128e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		wpa_msg(hapd->msg_ctx, MSG_INFO,
3138e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			WPS_EVENT_NEW_AP_SETTINGS "%s", buf);
3148e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		os_free(buf);
3158e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	}
3168e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener}
3178e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
3188e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
3198e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstatic int hapd_wps_reconfig_in_memory(struct hostapd_data *hapd,
3208e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener				       const struct wps_credential *cred)
3218e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener{
3228e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	struct hostapd_bss_config *bss = hapd->conf;
3238e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
3248e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	wpa_printf(MSG_DEBUG, "WPS: Updating in-memory configuration");
3258e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
3268e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	bss->wps_state = 2;
3278e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (cred->ssid_len <= HOSTAPD_MAX_SSID_LEN) {
3288e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		os_memcpy(bss->ssid.ssid, cred->ssid, cred->ssid_len);
3298e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		bss->ssid.ssid_len = cred->ssid_len;
3308e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		bss->ssid.ssid_set = 1;
3318e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	}
3328e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
3338e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if ((cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) &&
3348e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	    (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK)))
3358e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		bss->wpa = 3;
3368e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	else if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK))
3378e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		bss->wpa = 2;
3388e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	else if (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK))
3398e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		bss->wpa = 1;
3408e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	else
3418e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		bss->wpa = 0;
3428e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
3438e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (bss->wpa) {
3448e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA))
3458e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			bss->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X;
3468e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		if (cred->auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK))
3478e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
3488e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
3498e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		bss->wpa_pairwise = 0;
3508e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		if (cred->encr_type & WPS_ENCR_AES)
3518e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			bss->wpa_pairwise |= WPA_CIPHER_CCMP;
3528e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		if (cred->encr_type & WPS_ENCR_TKIP)
3538e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			bss->wpa_pairwise |= WPA_CIPHER_TKIP;
3548e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		bss->rsn_pairwise = bss->wpa_pairwise;
3558e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa,
3568e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener							    bss->wpa_pairwise,
3578e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener							    bss->rsn_pairwise);
3588e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
3598e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		if (cred->key_len >= 8 && cred->key_len < 64) {
3608e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			os_free(bss->ssid.wpa_passphrase);
3618e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			bss->ssid.wpa_passphrase = os_zalloc(cred->key_len + 1);
3628e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			if (bss->ssid.wpa_passphrase)
3638e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener				os_memcpy(bss->ssid.wpa_passphrase, cred->key,
3648e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener					  cred->key_len);
3658e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk);
3668e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		} else if (cred->key_len == 64) {
3678e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk);
3688e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			bss->ssid.wpa_psk =
3698e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener				os_zalloc(sizeof(struct hostapd_wpa_psk));
3708e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			if (bss->ssid.wpa_psk &&
3718e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			    hexstr2bin((const char *) cred->key,
3728e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener				       bss->ssid.wpa_psk->psk, PMK_LEN) == 0) {
3738e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener				bss->ssid.wpa_psk->group = 1;
3748e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener				os_free(bss->ssid.wpa_passphrase);
3758e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener				bss->ssid.wpa_passphrase = NULL;
3768e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			}
3778e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		}
3788e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		bss->auth_algs = 1;
3798e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	} else {
3808e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		/*
3818e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		 * WPS 2.0 does not allow WEP to be configured, so no need to
3828e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		 * process that option here either.
3838e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		 */
3848e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		bss->auth_algs = 1;
3858e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	}
3868e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
3878e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	/* Schedule configuration reload after short period of time to allow
3888e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	 * EAP-WSC to be finished.
3898e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	 */
3908e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	eloop_register_timeout(0, 100000, wps_reload_config, hapd->iface,
3918e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			       NULL);
3928e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
3938e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	return 0;
3948e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener}
3958e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
3968e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
3978e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstatic int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
3988e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener{
3998e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	const struct wps_credential *cred = ctx;
4008e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	FILE *oconf, *nconf;
4018e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	size_t len, i;
4028e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	char *tmp_fname;
4038e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	char buf[1024];
4048e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	int multi_bss;
4058e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	int wpa;
4068e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
4078e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (hapd->wps == NULL)
4088e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		return 0;
4098e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
4108e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	wpa_hexdump_key(MSG_DEBUG, "WPS: Received Credential attribute",
4118e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			cred->cred_attr, cred->cred_attr_len);
4128e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
4138e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	wpa_printf(MSG_DEBUG, "WPS: Received new AP Settings");
4148e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", cred->ssid, cred->ssid_len);
4158e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	wpa_printf(MSG_DEBUG, "WPS: Authentication Type 0x%x",
4168e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		   cred->auth_type);
4178e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	wpa_printf(MSG_DEBUG, "WPS: Encryption Type 0x%x", cred->encr_type);
4188e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	wpa_printf(MSG_DEBUG, "WPS: Network Key Index %d", cred->key_idx);
4198e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key",
4208e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			cred->key, cred->key_len);
4218e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	wpa_printf(MSG_DEBUG, "WPS: MAC Address " MACSTR,
4228e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		   MAC2STR(cred->mac_addr));
4238e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
4248e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if ((hapd->conf->wps_cred_processing == 1 ||
4258e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	     hapd->conf->wps_cred_processing == 2) && cred->cred_attr) {
4268e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		hapd_new_ap_event(hapd, cred->cred_attr, cred->cred_attr_len);
4278e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	} else if (hapd->conf->wps_cred_processing == 1 ||
4288e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		   hapd->conf->wps_cred_processing == 2) {
4298e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		struct wpabuf *attr;
4308e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		attr = wpabuf_alloc(200);
4318e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		if (attr && wps_build_credential_wrap(attr, cred) == 0)
4328e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			hapd_new_ap_event(hapd, wpabuf_head_u8(attr),
4338e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener					  wpabuf_len(attr));
4348e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		wpabuf_free(attr);
4358e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	} else
4368e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_NEW_AP_SETTINGS);
4378e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
4388e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (hapd->conf->wps_cred_processing == 1)
4398e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		return 0;
4408e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
4418e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	os_memcpy(hapd->wps->ssid, cred->ssid, cred->ssid_len);
4428e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	hapd->wps->ssid_len = cred->ssid_len;
4438e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	hapd->wps->encr_types = cred->encr_type;
4448e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	hapd->wps->auth_types = cred->auth_type;
4458e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	hapd->wps->ap_encr_type = cred->encr_type;
4468e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	hapd->wps->ap_auth_type = cred->auth_type;
4478e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (cred->key_len == 0) {
4488e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		os_free(hapd->wps->network_key);
4498e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		hapd->wps->network_key = NULL;
4508e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		hapd->wps->network_key_len = 0;
4518e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	} else {
4528e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		if (hapd->wps->network_key == NULL ||
4538e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		    hapd->wps->network_key_len < cred->key_len) {
4548e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			hapd->wps->network_key_len = 0;
4558e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			os_free(hapd->wps->network_key);
4568e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			hapd->wps->network_key = os_malloc(cred->key_len);
4578e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			if (hapd->wps->network_key == NULL)
4588e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener				return -1;
4598e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		}
4608e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		hapd->wps->network_key_len = cred->key_len;
4618e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		os_memcpy(hapd->wps->network_key, cred->key, cred->key_len);
4628e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	}
4638e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	hapd->wps->wps_state = WPS_STATE_CONFIGURED;
4648e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
4658e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (hapd->iface->config_fname == NULL)
4668e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		return hapd_wps_reconfig_in_memory(hapd, cred);
4678e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	len = os_strlen(hapd->iface->config_fname) + 5;
4688e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	tmp_fname = os_malloc(len);
4698e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (tmp_fname == NULL)
4708e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		return -1;
4718e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	os_snprintf(tmp_fname, len, "%s-new", hapd->iface->config_fname);
4728e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
4738e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	oconf = fopen(hapd->iface->config_fname, "r");
4748e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (oconf == NULL) {
4758e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		wpa_printf(MSG_WARNING, "WPS: Could not open current "
4768e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			   "configuration file");
4778e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		os_free(tmp_fname);
4788e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		return -1;
4798e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	}
4808e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
4818e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	nconf = fopen(tmp_fname, "w");
4828e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (nconf == NULL) {
4838e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		wpa_printf(MSG_WARNING, "WPS: Could not write updated "
4848e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			   "configuration file");
4858e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		os_free(tmp_fname);
4868e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		fclose(oconf);
4878e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		return -1;
4888e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	}
4898e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
4908e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	fprintf(nconf, "# WPS configuration - START\n");
4918e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
4928e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	fprintf(nconf, "wps_state=2\n");
4938e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
4948e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (is_hex(cred->ssid, cred->ssid_len)) {
4958e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		fprintf(nconf, "ssid2=");
4968e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		for (i = 0; i < cred->ssid_len; i++)
4978e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			fprintf(nconf, "%02x", cred->ssid[i]);
4988e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		fprintf(nconf, "\n");
4998e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	} else {
5008e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		fprintf(nconf, "ssid=");
5018e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		for (i = 0; i < cred->ssid_len; i++)
5028e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			fputc(cred->ssid[i], nconf);
5038e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		fprintf(nconf, "\n");
5048e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	}
5058e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
5068e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if ((cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) &&
5078e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	    (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK)))
5088e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		wpa = 3;
5098e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	else if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK))
5108e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		wpa = 2;
5118e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	else if (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK))
5128e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		wpa = 1;
5138e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	else
5148e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		wpa = 0;
5158e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
5168e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (wpa) {
5178e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		char *prefix;
5188e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		fprintf(nconf, "wpa=%d\n", wpa);
5198e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
5208e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		fprintf(nconf, "wpa_key_mgmt=");
5218e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		prefix = "";
5228e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA)) {
5238e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			fprintf(nconf, "WPA-EAP");
5248e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			prefix = " ";
5258e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		}
5268e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		if (cred->auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK))
5278e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			fprintf(nconf, "%sWPA-PSK", prefix);
5288e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		fprintf(nconf, "\n");
5298e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
5308e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		fprintf(nconf, "wpa_pairwise=");
5318e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		prefix = "";
5328e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		if (cred->encr_type & WPS_ENCR_AES) {
5338e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			fprintf(nconf, "CCMP");
5348e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			prefix = " ";
5358e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		}
5368e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		if (cred->encr_type & WPS_ENCR_TKIP) {
5378e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			fprintf(nconf, "%sTKIP", prefix);
5388e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		}
5398e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		fprintf(nconf, "\n");
5408e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
5418e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		if (cred->key_len >= 8 && cred->key_len < 64) {
5428e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			fprintf(nconf, "wpa_passphrase=");
5438e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			for (i = 0; i < cred->key_len; i++)
5448e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener				fputc(cred->key[i], nconf);
5458e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			fprintf(nconf, "\n");
5468e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		} else if (cred->key_len == 64) {
5478e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			fprintf(nconf, "wpa_psk=");
5488e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			for (i = 0; i < cred->key_len; i++)
5498e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener				fputc(cred->key[i], nconf);
5508e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			fprintf(nconf, "\n");
5518e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		} else {
5528e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			wpa_printf(MSG_WARNING, "WPS: Invalid key length %lu "
5538e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener				   "for WPA/WPA2",
5548e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener				   (unsigned long) cred->key_len);
5558e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		}
5568e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
5578e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		fprintf(nconf, "auth_algs=1\n");
5588e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	} else {
5598e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		/*
5608e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		 * WPS 2.0 does not allow WEP to be configured, so no need to
5618e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		 * process that option here either.
5628e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		 */
5638e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		fprintf(nconf, "auth_algs=1\n");
5648e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	}
5658e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
5668e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	fprintf(nconf, "# WPS configuration - END\n");
5678e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
5688e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	multi_bss = 0;
5698e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	while (fgets(buf, sizeof(buf), oconf)) {
5708e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		if (os_strncmp(buf, "bss=", 4) == 0)
5718e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			multi_bss = 1;
5728e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		if (!multi_bss &&
5738e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		    (str_starts(buf, "ssid=") ||
5748e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		     str_starts(buf, "ssid2=") ||
5758e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		     str_starts(buf, "auth_algs=") ||
5768e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		     str_starts(buf, "wep_default_key=") ||
5778e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		     str_starts(buf, "wep_key") ||
5788e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		     str_starts(buf, "wps_state=") ||
5798e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		     str_starts(buf, "wpa=") ||
5808e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		     str_starts(buf, "wpa_psk=") ||
5818e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		     str_starts(buf, "wpa_pairwise=") ||
5828e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		     str_starts(buf, "rsn_pairwise=") ||
5838e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		     str_starts(buf, "wpa_key_mgmt=") ||
5848e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		     str_starts(buf, "wpa_passphrase="))) {
5858e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			fprintf(nconf, "#WPS# %s", buf);
5868e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		} else
5878e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			fprintf(nconf, "%s", buf);
5888e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	}
5898e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
5908e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	fclose(nconf);
5918e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	fclose(oconf);
5928e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
5938e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (rename(tmp_fname, hapd->iface->config_fname) < 0) {
5948e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		wpa_printf(MSG_WARNING, "WPS: Failed to rename the updated "
5958e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			   "configuration file: %s", strerror(errno));
5968e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		os_free(tmp_fname);
5978e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		return -1;
5988e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	}
5998e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
6008e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	os_free(tmp_fname);
6018e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
6028e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	/* Schedule configuration reload after short period of time to allow
6038e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	 * EAP-WSC to be finished.
6048e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	 */
6058e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	eloop_register_timeout(0, 100000, wps_reload_config, hapd->iface,
6068e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			       NULL);
6078e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
6088e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	wpa_printf(MSG_DEBUG, "WPS: AP configuration updated");
6098e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
6108e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	return 0;
6118e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener}
6128e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
6138e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
6148e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstatic int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred)
6158e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener{
6168e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	struct hostapd_data *hapd = ctx;
6178e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	return hostapd_wps_for_each(hapd, hapd_wps_cred_cb, (void *) cred);
6188e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener}
6198e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
6208e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
6218e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstatic void hostapd_wps_reenable_ap_pin(void *eloop_data, void *user_ctx)
6228e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener{
6238e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	struct hostapd_data *hapd = eloop_data;
6248e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
6258e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (hapd->conf->ap_setup_locked)
6268e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		return;
6278e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (hapd->ap_pin_failures_consecutive >= 10)
6288e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		return;
6298e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
6308e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	wpa_printf(MSG_DEBUG, "WPS: Re-enable AP PIN");
6318e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_UNLOCKED);
6328e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	hapd->wps->ap_setup_locked = 0;
6338e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	wps_registrar_update_ie(hapd->wps->registrar);
6348e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener}
6358e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
6368e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
6378e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstatic int wps_pwd_auth_fail(struct hostapd_data *hapd, void *ctx)
6388e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener{
6398e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	struct wps_event_pwd_auth_fail *data = ctx;
6408e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
6418e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (!data->enrollee || hapd->conf->ap_pin == NULL || hapd->wps == NULL)
6428e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		return 0;
6438e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
6448e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	/*
6458e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	 * Registrar failed to prove its knowledge of the AP PIN. Lock AP setup
6468e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	 * for some time if this happens multiple times to slow down brute
6478e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	 * force attacks.
6488e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	 */
6498e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	hapd->ap_pin_failures++;
6508e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	hapd->ap_pin_failures_consecutive++;
6518e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	wpa_printf(MSG_DEBUG, "WPS: AP PIN authentication failure number %u "
6528e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		   "(%u consecutive)",
6538e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		   hapd->ap_pin_failures, hapd->ap_pin_failures_consecutive);
6548e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (hapd->ap_pin_failures < 3)
6558e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		return 0;
6568e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
6578e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_LOCKED);
6588e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	hapd->wps->ap_setup_locked = 1;
6598e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
6608e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	wps_registrar_update_ie(hapd->wps->registrar);
6618e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
6628e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (!hapd->conf->ap_setup_locked &&
6638e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	    hapd->ap_pin_failures_consecutive >= 10) {
6648e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		/*
6658e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		 * In indefinite lockdown - disable automatic AP PIN
6668e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		 * reenablement.
6678e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		 */
6688e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL);
6698e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		wpa_printf(MSG_DEBUG, "WPS: AP PIN disabled indefinitely");
6708e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	} else if (!hapd->conf->ap_setup_locked) {
6718e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		if (hapd->ap_pin_lockout_time == 0)
6728e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			hapd->ap_pin_lockout_time = 60;
6738e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		else if (hapd->ap_pin_lockout_time < 365 * 24 * 60 * 60 &&
6748e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			 (hapd->ap_pin_failures % 3) == 0)
6758e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			hapd->ap_pin_lockout_time *= 2;
6768e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
6778e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		wpa_printf(MSG_DEBUG, "WPS: Disable AP PIN for %u seconds",
6788e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			   hapd->ap_pin_lockout_time);
6798e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL);
6808e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		eloop_register_timeout(hapd->ap_pin_lockout_time, 0,
6818e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener				       hostapd_wps_reenable_ap_pin, hapd,
6828e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener				       NULL);
6838e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	}
6848e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
6858e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	return 0;
6868e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener}
6878e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
6888e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
6898e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstatic void hostapd_pwd_auth_fail(struct hostapd_data *hapd,
6908e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener				  struct wps_event_pwd_auth_fail *data)
6918e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener{
6928e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	/* Update WPS Status - Authentication Failure */
6938e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	wpa_printf(MSG_DEBUG, "WPS: Authentication failure update");
6948e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	hapd->wps_stats.status = WPS_STATUS_FAILURE;
6958e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	hapd->wps_stats.failure_reason = WPS_EI_AUTH_FAILURE;
6968e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	os_memcpy(hapd->wps_stats.peer_addr, data->peer_macaddr, ETH_ALEN);
6978e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
6988e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	hostapd_wps_for_each(hapd, wps_pwd_auth_fail, data);
6998e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener}
7008e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
7018e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
7028e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstatic int wps_ap_pin_success(struct hostapd_data *hapd, void *ctx)
7038e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener{
7048e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (hapd->conf->ap_pin == NULL || hapd->wps == NULL)
7058e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		return 0;
7068e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
7078e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (hapd->ap_pin_failures_consecutive == 0)
7088e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		return 0;
7098e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
7108e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	wpa_printf(MSG_DEBUG, "WPS: Clear consecutive AP PIN failure counter "
7118e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		   "- total validation failures %u (%u consecutive)",
7128e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		   hapd->ap_pin_failures, hapd->ap_pin_failures_consecutive);
7138e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	hapd->ap_pin_failures_consecutive = 0;
7148e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
7158e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	return 0;
7168e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener}
7178e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
7188e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
7198e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstatic void hostapd_wps_ap_pin_success(struct hostapd_data *hapd)
7208e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener{
7218e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	hostapd_wps_for_each(hapd, wps_ap_pin_success, NULL);
7228e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener}
7238e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
7248e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
7258e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstatic void hostapd_wps_event_pbc_overlap(struct hostapd_data *hapd)
7268e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener{
7278e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	/* Update WPS Status - PBC Overlap */
7288e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	hapd->wps_stats.pbc_status = WPS_PBC_STATUS_OVERLAP;
7298e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener}
7308e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
7318e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
7328e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstatic void hostapd_wps_event_pbc_timeout(struct hostapd_data *hapd)
7338e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener{
7348e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	/* Update WPS PBC Status:PBC Timeout */
7358e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	hapd->wps_stats.pbc_status = WPS_PBC_STATUS_TIMEOUT;
7368e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener}
7378e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
7388e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
7398e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstatic void hostapd_wps_event_pbc_active(struct hostapd_data *hapd)
7408e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener{
7418e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	/* Update WPS PBC status - Active */
7428e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	hapd->wps_stats.pbc_status = WPS_PBC_STATUS_ACTIVE;
7438e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener}
7448e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
7458e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
7468e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstatic void hostapd_wps_event_pbc_disable(struct hostapd_data *hapd)
7478e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener{
7488e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	/* Update WPS PBC status - Active */
7498e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	hapd->wps_stats.pbc_status = WPS_PBC_STATUS_DISABLE;
7508e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener}
7518e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
7528e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
7538e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstatic void hostapd_wps_event_success(struct hostapd_data *hapd,
7548e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener				      struct wps_event_success *success)
7558e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener{
7568e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	/* Update WPS status - Success */
7578e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	hapd->wps_stats.pbc_status = WPS_PBC_STATUS_DISABLE;
7588e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	hapd->wps_stats.status = WPS_STATUS_SUCCESS;
7598e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	os_memcpy(hapd->wps_stats.peer_addr, success->peer_macaddr, ETH_ALEN);
7608e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener}
7618e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
7628e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
7638e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstatic void hostapd_wps_event_fail(struct hostapd_data *hapd,
7648e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener				   struct wps_event_fail *fail)
7658e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener{
7668e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	/* Update WPS status - Failure */
7678e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	hapd->wps_stats.status = WPS_STATUS_FAILURE;
7688e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	os_memcpy(hapd->wps_stats.peer_addr, fail->peer_macaddr, ETH_ALEN);
7698e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
7708e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	hapd->wps_stats.failure_reason = fail->error_indication;
7718e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
7728e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (fail->error_indication > 0 &&
7738e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	    fail->error_indication < NUM_WPS_EI_VALUES) {
7748e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		wpa_msg(hapd->msg_ctx, MSG_INFO,
7758e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			WPS_EVENT_FAIL "msg=%d config_error=%d reason=%d (%s)",
7768e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			fail->msg, fail->config_error, fail->error_indication,
7778e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			wps_ei_str(fail->error_indication));
7788e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	} else {
7798e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		wpa_msg(hapd->msg_ctx, MSG_INFO,
7808e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			WPS_EVENT_FAIL "msg=%d config_error=%d",
7818e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			fail->msg, fail->config_error);
7828e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	}
7838e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener}
7848e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
7858e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
7868e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstatic void hostapd_wps_event_cb(void *ctx, enum wps_event event,
7878e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener				 union wps_event_data *data)
7888e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener{
7898e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	struct hostapd_data *hapd = ctx;
7908e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
7918e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	switch (event) {
7928e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	case WPS_EV_M2D:
7938e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_M2D);
7948e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		break;
7958e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	case WPS_EV_FAIL:
7968e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		hostapd_wps_event_fail(hapd, &data->fail);
7978e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		break;
7988e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	case WPS_EV_SUCCESS:
7998e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		hostapd_wps_event_success(hapd, &data->success);
8008e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_SUCCESS);
8018e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		break;
8028e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	case WPS_EV_PWD_AUTH_FAIL:
8038e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		hostapd_pwd_auth_fail(hapd, &data->pwd_auth_fail);
8048e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		break;
8058e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	case WPS_EV_PBC_OVERLAP:
8068e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		hostapd_wps_event_pbc_overlap(hapd);
8078e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_OVERLAP);
8088e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		break;
8098e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	case WPS_EV_PBC_TIMEOUT:
8108e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		hostapd_wps_event_pbc_timeout(hapd);
8118e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_TIMEOUT);
8128e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		break;
8138e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	case WPS_EV_PBC_ACTIVE:
8148e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		hostapd_wps_event_pbc_active(hapd);
8158e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_ACTIVE);
8168e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		break;
8178e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	case WPS_EV_PBC_DISABLE:
8188e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		hostapd_wps_event_pbc_disable(hapd);
8198e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_DISABLE);
8208e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		break;
8218e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	case WPS_EV_ER_AP_ADD:
8228e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		break;
8238e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	case WPS_EV_ER_AP_REMOVE:
8248e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		break;
8258e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	case WPS_EV_ER_ENROLLEE_ADD:
8268e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		break;
8278e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	case WPS_EV_ER_ENROLLEE_REMOVE:
8288e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		break;
8298e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	case WPS_EV_ER_AP_SETTINGS:
8308e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		break;
8318e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	case WPS_EV_ER_SET_SELECTED_REGISTRAR:
8328e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		break;
8338e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	case WPS_EV_AP_PIN_SUCCESS:
8348e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		hostapd_wps_ap_pin_success(hapd);
8358e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		break;
8368e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	}
8378e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (hapd->wps_event_cb)
8388e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		hapd->wps_event_cb(hapd->wps_event_cb_ctx, event, data);
8398e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener}
8408e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
8418e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
8428e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstatic int hostapd_wps_rf_band_cb(void *ctx)
8438e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener{
8448e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	struct hostapd_data *hapd = ctx;
8458e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
8468e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	return hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ?
8478e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		WPS_RF_50GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */
8488e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener}
8498e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
8508e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
8518e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstatic void hostapd_wps_clear_ies(struct hostapd_data *hapd, int deinit_only)
8528e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener{
8538e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	wpabuf_free(hapd->wps_beacon_ie);
8548e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	hapd->wps_beacon_ie = NULL;
8558e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
8568e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	wpabuf_free(hapd->wps_probe_resp_ie);
8578e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	hapd->wps_probe_resp_ie = NULL;
8588e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
8598e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (deinit_only)
8608e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		return;
8618e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
8628e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	hostapd_set_ap_wps_ie(hapd);
8638e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener}
8648e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
8658e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
8668e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstatic int get_uuid_cb(struct hostapd_iface *iface, void *ctx)
8678e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener{
8688e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	const u8 **uuid = ctx;
8698e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	size_t j;
8708e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
8718e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (iface == NULL)
8728e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		return 0;
8738e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	for (j = 0; j < iface->num_bss; j++) {
8748e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		struct hostapd_data *hapd = iface->bss[j];
8758e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		if (hapd->wps && !hapd->conf->wps_independent &&
8768e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		    !is_nil_uuid(hapd->wps->uuid)) {
8778e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			*uuid = hapd->wps->uuid;
8788e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			return 1;
8798e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		}
8808e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	}
8818e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
8828e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	return 0;
8838e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener}
8848e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
8858e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
8868e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstatic const u8 * get_own_uuid(struct hostapd_iface *iface)
8878e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener{
8888e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	const u8 *uuid;
8898e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (iface->interfaces == NULL ||
8908e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	    iface->interfaces->for_each_interface == NULL)
8918e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		return NULL;
8928e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	uuid = NULL;
8938e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	iface->interfaces->for_each_interface(iface->interfaces, get_uuid_cb,
8948e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener					      &uuid);
8958e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	return uuid;
8968e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener}
8978e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
8988e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
8998e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstatic int count_interface_cb(struct hostapd_iface *iface, void *ctx)
9008e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener{
9018e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	int *count= ctx;
9028e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	(*count)++;
9038e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	return 0;
9048e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener}
9058e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
9068e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
9078e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstatic int interface_count(struct hostapd_iface *iface)
9088e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener{
9098e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	int count = 0;
9108e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (iface->interfaces == NULL ||
9118e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	    iface->interfaces->for_each_interface == NULL)
9128e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		return 0;
9138e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	iface->interfaces->for_each_interface(iface->interfaces,
9148e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener					      count_interface_cb, &count);
9158e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	return count;
9168e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener}
9178e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
9188e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
9198e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstatic int hostapd_wps_set_vendor_ext(struct hostapd_data *hapd,
9208e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener				      struct wps_context *wps)
9218e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener{
9228e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	int i;
9238e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
9248e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
9258e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		wpabuf_free(wps->dev.vendor_ext[i]);
9268e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		wps->dev.vendor_ext[i] = NULL;
9278e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
9288e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		if (hapd->conf->wps_vendor_ext[i] == NULL)
9298e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			continue;
9308e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
9318e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		wps->dev.vendor_ext[i] =
9328e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			wpabuf_dup(hapd->conf->wps_vendor_ext[i]);
9338e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		if (wps->dev.vendor_ext[i] == NULL) {
9348e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			while (--i >= 0)
9358e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener				wpabuf_free(wps->dev.vendor_ext[i]);
9368e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener			return -1;
9378e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		}
9388e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	}
9398e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
9408e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	return 0;
9418e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener}
9428e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
9438e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
9448e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerstatic void hostapd_free_wps(struct wps_context *wps)
9458e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener{
9468e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	int i;
9478e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
9488e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++)
9498e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		wpabuf_free(wps->dev.vendor_ext[i]);
9508e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	wps_device_data_free(&wps->dev);
9518e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	os_free(wps->network_key);
9528e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	hostapd_wps_nfc_clear(wps);
9538e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	wpabuf_free(wps->dh_pubkey);
9548e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	wpabuf_free(wps->dh_privkey);
9558e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	os_free(wps);
9568e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener}
9578e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
9588e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
9598e8939fc10ad63576a2785ba1333a23726b7e164Florian Krienerint hostapd_init_wps(struct hostapd_data *hapd,
9608e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		     struct hostapd_bss_config *conf)
9618e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener{
9628e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	struct wps_context *wps;
9638e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	struct wps_registrar_config cfg;
9648e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
9658e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (conf->wps_state == 0) {
9668e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		hostapd_wps_clear_ies(hapd, 0);
9678e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		return 0;
9688e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	}
9698e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
9708e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	wps = os_zalloc(sizeof(*wps));
9718e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (wps == NULL)
9728e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		return -1;
9738e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
9748e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	wps->cred_cb = hostapd_wps_cred_cb;
9758e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	wps->event_cb = hostapd_wps_event_cb;
9768e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	wps->rf_band_cb = hostapd_wps_rf_band_cb;
9778e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	wps->cb_ctx = hapd;
9788e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener
9798e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	os_memset(&cfg, 0, sizeof(cfg));
9808e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	wps->wps_state = hapd->conf->wps_state;
9818e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	wps->ap_setup_locked = hapd->conf->ap_setup_locked;
9828e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener	if (is_nil_uuid(hapd->conf->uuid)) {
9838e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		const u8 *uuid;
9848e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		uuid = get_own_uuid(hapd->iface);
9858e8939fc10ad63576a2785ba1333a23726b7e164Florian Kriener		if (uuid && !conf->wps_independent) {
986			os_memcpy(wps->uuid, uuid, UUID_LEN);
987			wpa_hexdump(MSG_DEBUG, "WPS: Clone UUID from another "
988				    "interface", wps->uuid, UUID_LEN);
989		} else {
990			uuid_gen_mac_addr(hapd->own_addr, wps->uuid);
991			wpa_hexdump(MSG_DEBUG, "WPS: UUID based on MAC "
992				    "address", wps->uuid, UUID_LEN);
993		}
994	} else {
995		os_memcpy(wps->uuid, hapd->conf->uuid, UUID_LEN);
996		wpa_hexdump(MSG_DEBUG, "WPS: Use configured UUID",
997			    wps->uuid, UUID_LEN);
998	}
999	wps->ssid_len = hapd->conf->ssid.ssid_len;
1000	os_memcpy(wps->ssid, hapd->conf->ssid.ssid, wps->ssid_len);
1001	wps->ap = 1;
1002	os_memcpy(wps->dev.mac_addr, hapd->own_addr, ETH_ALEN);
1003	wps->dev.device_name = hapd->conf->device_name ?
1004		os_strdup(hapd->conf->device_name) : NULL;
1005	wps->dev.manufacturer = hapd->conf->manufacturer ?
1006		os_strdup(hapd->conf->manufacturer) : NULL;
1007	wps->dev.model_name = hapd->conf->model_name ?
1008		os_strdup(hapd->conf->model_name) : NULL;
1009	wps->dev.model_number = hapd->conf->model_number ?
1010		os_strdup(hapd->conf->model_number) : NULL;
1011	wps->dev.serial_number = hapd->conf->serial_number ?
1012		os_strdup(hapd->conf->serial_number) : NULL;
1013	wps->config_methods =
1014		wps_config_methods_str2bin(hapd->conf->config_methods);
1015	if ((wps->config_methods &
1016	     (WPS_CONFIG_DISPLAY | WPS_CONFIG_VIRT_DISPLAY |
1017	      WPS_CONFIG_PHY_DISPLAY)) == WPS_CONFIG_DISPLAY) {
1018		wpa_printf(MSG_INFO, "WPS: Converting display to "
1019			   "virtual_display for WPS 2.0 compliance");
1020		wps->config_methods |= WPS_CONFIG_VIRT_DISPLAY;
1021	}
1022	if ((wps->config_methods &
1023	     (WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_VIRT_PUSHBUTTON |
1024	      WPS_CONFIG_PHY_PUSHBUTTON)) == WPS_CONFIG_PUSHBUTTON) {
1025		wpa_printf(MSG_INFO, "WPS: Converting push_button to "
1026			   "virtual_push_button for WPS 2.0 compliance");
1027		wps->config_methods |= WPS_CONFIG_VIRT_PUSHBUTTON;
1028	}
1029	os_memcpy(wps->dev.pri_dev_type, hapd->conf->device_type,
1030		  WPS_DEV_TYPE_LEN);
1031
1032	if (hostapd_wps_set_vendor_ext(hapd, wps) < 0)
1033		goto fail;
1034
1035	wps->dev.os_version = WPA_GET_BE32(hapd->conf->os_version);
1036
1037	if (conf->wps_rf_bands) {
1038		wps->dev.rf_bands = conf->wps_rf_bands;
1039	} else {
1040		wps->dev.rf_bands =
1041			hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ?
1042			WPS_RF_50GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */
1043	}
1044
1045	if (conf->wpa & WPA_PROTO_RSN) {
1046		if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK)
1047			wps->auth_types |= WPS_AUTH_WPA2PSK;
1048		if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X)
1049			wps->auth_types |= WPS_AUTH_WPA2;
1050
1051		if (conf->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP))
1052			wps->encr_types |= WPS_ENCR_AES;
1053		if (conf->rsn_pairwise & WPA_CIPHER_TKIP)
1054			wps->encr_types |= WPS_ENCR_TKIP;
1055	}
1056
1057	if (conf->wpa & WPA_PROTO_WPA) {
1058		if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK)
1059			wps->auth_types |= WPS_AUTH_WPAPSK;
1060		if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X)
1061			wps->auth_types |= WPS_AUTH_WPA;
1062
1063		if (conf->wpa_pairwise & WPA_CIPHER_CCMP)
1064			wps->encr_types |= WPS_ENCR_AES;
1065		if (conf->wpa_pairwise & WPA_CIPHER_TKIP)
1066			wps->encr_types |= WPS_ENCR_TKIP;
1067	}
1068
1069	if (conf->ssid.security_policy == SECURITY_PLAINTEXT) {
1070		wps->encr_types |= WPS_ENCR_NONE;
1071		wps->auth_types |= WPS_AUTH_OPEN;
1072	}
1073
1074	if (conf->ssid.wpa_psk_file) {
1075		/* Use per-device PSKs */
1076	} else if (conf->ssid.wpa_passphrase) {
1077		wps->network_key = (u8 *) os_strdup(conf->ssid.wpa_passphrase);
1078		wps->network_key_len = os_strlen(conf->ssid.wpa_passphrase);
1079	} else if (conf->ssid.wpa_psk) {
1080		wps->network_key = os_malloc(2 * PMK_LEN + 1);
1081		if (wps->network_key == NULL)
1082			goto fail;
1083		wpa_snprintf_hex((char *) wps->network_key, 2 * PMK_LEN + 1,
1084				 conf->ssid.wpa_psk->psk, PMK_LEN);
1085		wps->network_key_len = 2 * PMK_LEN;
1086	} else if (conf->ssid.wep.keys_set && conf->ssid.wep.key[0]) {
1087		wps->network_key = os_malloc(conf->ssid.wep.len[0]);
1088		if (wps->network_key == NULL)
1089			goto fail;
1090		os_memcpy(wps->network_key, conf->ssid.wep.key[0],
1091			  conf->ssid.wep.len[0]);
1092		wps->network_key_len = conf->ssid.wep.len[0];
1093	}
1094
1095	if (conf->ssid.wpa_psk) {
1096		os_memcpy(wps->psk, conf->ssid.wpa_psk->psk, PMK_LEN);
1097		wps->psk_set = 1;
1098	}
1099
1100	wps->ap_auth_type = wps->auth_types;
1101	wps->ap_encr_type = wps->encr_types;
1102	if (conf->wps_state == WPS_STATE_NOT_CONFIGURED) {
1103		/* Override parameters to enable security by default */
1104		wps->auth_types = WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK;
1105		wps->encr_types = WPS_ENCR_AES | WPS_ENCR_TKIP;
1106	}
1107
1108	wps->ap_settings = conf->ap_settings;
1109	wps->ap_settings_len = conf->ap_settings_len;
1110
1111	cfg.new_psk_cb = hostapd_wps_new_psk_cb;
1112	cfg.set_ie_cb = hostapd_wps_set_ie_cb;
1113	cfg.pin_needed_cb = hostapd_wps_pin_needed_cb;
1114	cfg.reg_success_cb = hostapd_wps_reg_success_cb;
1115	cfg.enrollee_seen_cb = hostapd_wps_enrollee_seen_cb;
1116	cfg.cb_ctx = hapd;
1117	cfg.skip_cred_build = conf->skip_cred_build;
1118	cfg.extra_cred = conf->extra_cred;
1119	cfg.extra_cred_len = conf->extra_cred_len;
1120	cfg.disable_auto_conf = (hapd->conf->wps_cred_processing == 1) &&
1121		conf->skip_cred_build;
1122	if (conf->ssid.security_policy == SECURITY_STATIC_WEP)
1123		cfg.static_wep_only = 1;
1124	cfg.dualband = interface_count(hapd->iface) > 1;
1125	if ((wps->dev.rf_bands & (WPS_RF_50GHZ | WPS_RF_24GHZ)) ==
1126	    (WPS_RF_50GHZ | WPS_RF_24GHZ))
1127		cfg.dualband = 1;
1128	if (cfg.dualband)
1129		wpa_printf(MSG_DEBUG, "WPS: Dualband AP");
1130	cfg.force_per_enrollee_psk = conf->force_per_enrollee_psk;
1131
1132	wps->registrar = wps_registrar_init(wps, &cfg);
1133	if (wps->registrar == NULL) {
1134		wpa_printf(MSG_ERROR, "Failed to initialize WPS Registrar");
1135		goto fail;
1136	}
1137
1138#ifdef CONFIG_WPS_UPNP
1139	wps->friendly_name = hapd->conf->friendly_name;
1140	wps->manufacturer_url = hapd->conf->manufacturer_url;
1141	wps->model_description = hapd->conf->model_description;
1142	wps->model_url = hapd->conf->model_url;
1143	wps->upc = hapd->conf->upc;
1144#endif /* CONFIG_WPS_UPNP */
1145
1146	hostapd_register_probereq_cb(hapd, hostapd_wps_probe_req_rx, hapd);
1147
1148	hapd->wps = wps;
1149
1150	return 0;
1151
1152fail:
1153	hostapd_free_wps(wps);
1154	return -1;
1155}
1156
1157
1158int hostapd_init_wps_complete(struct hostapd_data *hapd)
1159{
1160	struct wps_context *wps = hapd->wps;
1161
1162	if (wps == NULL)
1163		return 0;
1164
1165#ifdef CONFIG_WPS_UPNP
1166	if (hostapd_wps_upnp_init(hapd, wps) < 0) {
1167		wpa_printf(MSG_ERROR, "Failed to initialize WPS UPnP");
1168		wps_registrar_deinit(wps->registrar);
1169		hostapd_free_wps(wps);
1170		hapd->wps = NULL;
1171		return -1;
1172	}
1173#endif /* CONFIG_WPS_UPNP */
1174
1175	return 0;
1176}
1177
1178
1179static void hostapd_wps_nfc_clear(struct wps_context *wps)
1180{
1181#ifdef CONFIG_WPS_NFC
1182	wpa_printf(MSG_DEBUG, "WPS: Clear NFC Tag context %p", wps);
1183	wps->ap_nfc_dev_pw_id = 0;
1184	wpabuf_free(wps->ap_nfc_dh_pubkey);
1185	wps->ap_nfc_dh_pubkey = NULL;
1186	wpabuf_free(wps->ap_nfc_dh_privkey);
1187	wps->ap_nfc_dh_privkey = NULL;
1188	wpabuf_free(wps->ap_nfc_dev_pw);
1189	wps->ap_nfc_dev_pw = NULL;
1190#endif /* CONFIG_WPS_NFC */
1191}
1192
1193
1194void hostapd_deinit_wps(struct hostapd_data *hapd)
1195{
1196	eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL);
1197	eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL);
1198	eloop_cancel_timeout(wps_reload_config, hapd->iface, NULL);
1199	if (hapd->wps == NULL) {
1200		hostapd_wps_clear_ies(hapd, 1);
1201		return;
1202	}
1203#ifdef CONFIG_WPS_UPNP
1204	hostapd_wps_upnp_deinit(hapd);
1205#endif /* CONFIG_WPS_UPNP */
1206	wps_registrar_deinit(hapd->wps->registrar);
1207	wps_free_pending_msgs(hapd->wps->upnp_msgs);
1208	hostapd_free_wps(hapd->wps);
1209	hapd->wps = NULL;
1210	hostapd_wps_clear_ies(hapd, 1);
1211}
1212
1213
1214void hostapd_update_wps(struct hostapd_data *hapd)
1215{
1216	if (hapd->wps == NULL)
1217		return;
1218
1219#ifdef CONFIG_WPS_UPNP
1220	hapd->wps->friendly_name = hapd->conf->friendly_name;
1221	hapd->wps->manufacturer_url = hapd->conf->manufacturer_url;
1222	hapd->wps->model_description = hapd->conf->model_description;
1223	hapd->wps->model_url = hapd->conf->model_url;
1224	hapd->wps->upc = hapd->conf->upc;
1225#endif /* CONFIG_WPS_UPNP */
1226
1227	hostapd_wps_set_vendor_ext(hapd, hapd->wps);
1228
1229	if (hapd->conf->wps_state)
1230		wps_registrar_update_ie(hapd->wps->registrar);
1231	else
1232		hostapd_deinit_wps(hapd);
1233}
1234
1235
1236struct wps_add_pin_data {
1237	const u8 *addr;
1238	const u8 *uuid;
1239	const u8 *pin;
1240	size_t pin_len;
1241	int timeout;
1242	int added;
1243};
1244
1245
1246static int wps_add_pin(struct hostapd_data *hapd, void *ctx)
1247{
1248	struct wps_add_pin_data *data = ctx;
1249	int ret;
1250
1251	if (hapd->wps == NULL)
1252		return 0;
1253	ret = wps_registrar_add_pin(hapd->wps->registrar, data->addr,
1254				    data->uuid, data->pin, data->pin_len,
1255				    data->timeout);
1256	if (ret == 0)
1257		data->added++;
1258	return ret;
1259}
1260
1261
1262int hostapd_wps_add_pin(struct hostapd_data *hapd, const u8 *addr,
1263			const char *uuid, const char *pin, int timeout)
1264{
1265	u8 u[UUID_LEN];
1266	struct wps_add_pin_data data;
1267
1268	data.addr = addr;
1269	data.uuid = u;
1270	data.pin = (const u8 *) pin;
1271	data.pin_len = os_strlen(pin);
1272	data.timeout = timeout;
1273	data.added = 0;
1274
1275	if (os_strcmp(uuid, "any") == 0)
1276		data.uuid = NULL;
1277	else {
1278		if (uuid_str2bin(uuid, u))
1279			return -1;
1280		data.uuid = u;
1281	}
1282	if (hostapd_wps_for_each(hapd, wps_add_pin, &data) < 0)
1283		return -1;
1284	return data.added ? 0 : -1;
1285}
1286
1287
1288static int wps_button_pushed(struct hostapd_data *hapd, void *ctx)
1289{
1290	const u8 *p2p_dev_addr = ctx;
1291	if (hapd->wps == NULL)
1292		return -1;
1293	return wps_registrar_button_pushed(hapd->wps->registrar, p2p_dev_addr);
1294}
1295
1296
1297int hostapd_wps_button_pushed(struct hostapd_data *hapd,
1298			      const u8 *p2p_dev_addr)
1299{
1300	return hostapd_wps_for_each(hapd, wps_button_pushed,
1301				    (void *) p2p_dev_addr);
1302}
1303
1304
1305static int wps_cancel(struct hostapd_data *hapd, void *ctx)
1306{
1307	if (hapd->wps == NULL)
1308		return -1;
1309
1310	wps_registrar_wps_cancel(hapd->wps->registrar);
1311	ap_for_each_sta(hapd, ap_sta_wps_cancel, NULL);
1312
1313	return 0;
1314}
1315
1316
1317int hostapd_wps_cancel(struct hostapd_data *hapd)
1318{
1319	return hostapd_wps_for_each(hapd, wps_cancel, NULL);
1320}
1321
1322
1323static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, const u8 *da,
1324				    const u8 *bssid,
1325				    const u8 *ie, size_t ie_len,
1326				    int ssi_signal)
1327{
1328	struct hostapd_data *hapd = ctx;
1329	struct wpabuf *wps_ie;
1330	struct ieee802_11_elems elems;
1331
1332	if (hapd->wps == NULL)
1333		return 0;
1334
1335	if (ieee802_11_parse_elems(ie, ie_len, &elems, 0) == ParseFailed) {
1336		wpa_printf(MSG_DEBUG, "WPS: Could not parse ProbeReq from "
1337			   MACSTR, MAC2STR(addr));
1338		return 0;
1339	}
1340
1341	if (elems.ssid && elems.ssid_len > 0 &&
1342	    (elems.ssid_len != hapd->conf->ssid.ssid_len ||
1343	     os_memcmp(elems.ssid, hapd->conf->ssid.ssid, elems.ssid_len) !=
1344	     0))
1345		return 0; /* Not for us */
1346
1347	wps_ie = ieee802_11_vendor_ie_concat(ie, ie_len, WPS_DEV_OUI_WFA);
1348	if (wps_ie == NULL)
1349		return 0;
1350	if (wps_validate_probe_req(wps_ie, addr) < 0) {
1351		wpabuf_free(wps_ie);
1352		return 0;
1353	}
1354
1355	if (wpabuf_len(wps_ie) > 0) {
1356		int p2p_wildcard = 0;
1357#ifdef CONFIG_P2P
1358		if (elems.ssid && elems.ssid_len == P2P_WILDCARD_SSID_LEN &&
1359		    os_memcmp(elems.ssid, P2P_WILDCARD_SSID,
1360			      P2P_WILDCARD_SSID_LEN) == 0)
1361			p2p_wildcard = 1;
1362#endif /* CONFIG_P2P */
1363		wps_registrar_probe_req_rx(hapd->wps->registrar, addr, wps_ie,
1364					   p2p_wildcard);
1365#ifdef CONFIG_WPS_UPNP
1366		/* FIX: what exactly should be included in the WLANEvent?
1367		 * WPS attributes? Full ProbeReq frame? */
1368		if (!p2p_wildcard)
1369			upnp_wps_device_send_wlan_event(
1370				hapd->wps_upnp, addr,
1371				UPNP_WPS_WLANEVENT_TYPE_PROBE, wps_ie);
1372#endif /* CONFIG_WPS_UPNP */
1373	}
1374
1375	wpabuf_free(wps_ie);
1376
1377	return 0;
1378}
1379
1380
1381#ifdef CONFIG_WPS_UPNP
1382
1383static int hostapd_rx_req_put_wlan_response(
1384	void *priv, enum upnp_wps_wlanevent_type ev_type,
1385	const u8 *mac_addr, const struct wpabuf *msg,
1386	enum wps_msg_type msg_type)
1387{
1388	struct hostapd_data *hapd = priv;
1389	struct sta_info *sta;
1390	struct upnp_pending_message *p;
1391
1392	wpa_printf(MSG_DEBUG, "WPS UPnP: PutWLANResponse ev_type=%d mac_addr="
1393		   MACSTR, ev_type, MAC2STR(mac_addr));
1394	wpa_hexdump(MSG_MSGDUMP, "WPS UPnP: PutWLANResponse NewMessage",
1395		    wpabuf_head(msg), wpabuf_len(msg));
1396	if (ev_type != UPNP_WPS_WLANEVENT_TYPE_EAP) {
1397		wpa_printf(MSG_DEBUG, "WPS UPnP: Ignored unexpected "
1398			   "PutWLANResponse WLANEventType %d", ev_type);
1399		return -1;
1400	}
1401
1402	/*
1403	 * EAP response to ongoing to WPS Registration. Send it to EAP-WSC
1404	 * server implementation for delivery to the peer.
1405	 */
1406
1407	sta = ap_get_sta(hapd, mac_addr);
1408#ifndef CONFIG_WPS_STRICT
1409	if (!sta) {
1410		/*
1411		 * Workaround - Intel wsccmd uses bogus NewWLANEventMAC:
1412		 * Pick STA that is in an ongoing WPS registration without
1413		 * checking the MAC address.
1414		 */
1415		wpa_printf(MSG_DEBUG, "WPS UPnP: No matching STA found based "
1416			   "on NewWLANEventMAC; try wildcard match");
1417		for (sta = hapd->sta_list; sta; sta = sta->next) {
1418			if (sta->eapol_sm && (sta->flags & WLAN_STA_WPS))
1419				break;
1420		}
1421	}
1422#endif /* CONFIG_WPS_STRICT */
1423
1424	if (!sta || !(sta->flags & WLAN_STA_WPS)) {
1425		wpa_printf(MSG_DEBUG, "WPS UPnP: No matching STA found");
1426		return 0;
1427	}
1428
1429	if (!sta->eapol_sm) {
1430		/*
1431		 * This can happen, e.g., if an ER sends an extra message after
1432		 * the station has disassociated (but not fully
1433		 * deauthenticated).
1434		 */
1435		wpa_printf(MSG_DEBUG, "WPS UPnP: Matching STA did not have EAPOL state machine initialized");
1436		return 0;
1437	}
1438
1439	p = os_zalloc(sizeof(*p));
1440	if (p == NULL)
1441		return -1;
1442	os_memcpy(p->addr, sta->addr, ETH_ALEN);
1443	p->msg = wpabuf_dup(msg);
1444	p->type = msg_type;
1445	p->next = hapd->wps->upnp_msgs;
1446	hapd->wps->upnp_msgs = p;
1447
1448	return eapol_auth_eap_pending_cb(sta->eapol_sm, sta->eapol_sm->eap);
1449}
1450
1451
1452static int hostapd_wps_upnp_init(struct hostapd_data *hapd,
1453				 struct wps_context *wps)
1454{
1455	struct upnp_wps_device_ctx *ctx;
1456
1457	if (!hapd->conf->upnp_iface)
1458		return 0;
1459	ctx = os_zalloc(sizeof(*ctx));
1460	if (ctx == NULL)
1461		return -1;
1462
1463	ctx->rx_req_put_wlan_response = hostapd_rx_req_put_wlan_response;
1464	if (hapd->conf->ap_pin)
1465		ctx->ap_pin = os_strdup(hapd->conf->ap_pin);
1466
1467	hapd->wps_upnp = upnp_wps_device_init(ctx, wps, hapd,
1468					      hapd->conf->upnp_iface);
1469	if (hapd->wps_upnp == NULL)
1470		return -1;
1471	wps->wps_upnp = hapd->wps_upnp;
1472
1473	return 0;
1474}
1475
1476
1477static void hostapd_wps_upnp_deinit(struct hostapd_data *hapd)
1478{
1479	upnp_wps_device_deinit(hapd->wps_upnp, hapd);
1480}
1481
1482#endif /* CONFIG_WPS_UPNP */
1483
1484
1485int hostapd_wps_get_mib_sta(struct hostapd_data *hapd, const u8 *addr,
1486			    char *buf, size_t buflen)
1487{
1488	if (hapd->wps == NULL)
1489		return 0;
1490	return wps_registrar_get_info(hapd->wps->registrar, addr, buf, buflen);
1491}
1492
1493
1494static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx)
1495{
1496	struct hostapd_data *hapd = eloop_data;
1497	wpa_printf(MSG_DEBUG, "WPS: AP PIN timed out");
1498	hostapd_wps_ap_pin_disable(hapd);
1499	wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_PIN_DISABLED);
1500}
1501
1502
1503static void hostapd_wps_ap_pin_enable(struct hostapd_data *hapd, int timeout)
1504{
1505	wpa_printf(MSG_DEBUG, "WPS: Enabling AP PIN (timeout=%d)", timeout);
1506	hapd->ap_pin_failures = 0;
1507	hapd->ap_pin_failures_consecutive = 0;
1508	hapd->conf->ap_setup_locked = 0;
1509	if (hapd->wps->ap_setup_locked) {
1510		wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_UNLOCKED);
1511		hapd->wps->ap_setup_locked = 0;
1512		wps_registrar_update_ie(hapd->wps->registrar);
1513	}
1514	eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL);
1515	if (timeout > 0)
1516		eloop_register_timeout(timeout, 0,
1517				       hostapd_wps_ap_pin_timeout, hapd, NULL);
1518}
1519
1520
1521static int wps_ap_pin_disable(struct hostapd_data *hapd, void *ctx)
1522{
1523	os_free(hapd->conf->ap_pin);
1524	hapd->conf->ap_pin = NULL;
1525#ifdef CONFIG_WPS_UPNP
1526	upnp_wps_set_ap_pin(hapd->wps_upnp, NULL);
1527#endif /* CONFIG_WPS_UPNP */
1528	eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL);
1529	return 0;
1530}
1531
1532
1533void hostapd_wps_ap_pin_disable(struct hostapd_data *hapd)
1534{
1535	wpa_printf(MSG_DEBUG, "WPS: Disabling AP PIN");
1536	hostapd_wps_for_each(hapd, wps_ap_pin_disable, NULL);
1537}
1538
1539
1540struct wps_ap_pin_data {
1541	char pin_txt[9];
1542	int timeout;
1543};
1544
1545
1546static int wps_ap_pin_set(struct hostapd_data *hapd, void *ctx)
1547{
1548	struct wps_ap_pin_data *data = ctx;
1549	os_free(hapd->conf->ap_pin);
1550	hapd->conf->ap_pin = os_strdup(data->pin_txt);
1551#ifdef CONFIG_WPS_UPNP
1552	upnp_wps_set_ap_pin(hapd->wps_upnp, data->pin_txt);
1553#endif /* CONFIG_WPS_UPNP */
1554	hostapd_wps_ap_pin_enable(hapd, data->timeout);
1555	return 0;
1556}
1557
1558
1559const char * hostapd_wps_ap_pin_random(struct hostapd_data *hapd, int timeout)
1560{
1561	unsigned int pin;
1562	struct wps_ap_pin_data data;
1563
1564	pin = wps_generate_pin();
1565	os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%08u", pin);
1566	data.timeout = timeout;
1567	hostapd_wps_for_each(hapd, wps_ap_pin_set, &data);
1568	return hapd->conf->ap_pin;
1569}
1570
1571
1572const char * hostapd_wps_ap_pin_get(struct hostapd_data *hapd)
1573{
1574	return hapd->conf->ap_pin;
1575}
1576
1577
1578int hostapd_wps_ap_pin_set(struct hostapd_data *hapd, const char *pin,
1579			   int timeout)
1580{
1581	struct wps_ap_pin_data data;
1582	int ret;
1583
1584	ret = os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%s", pin);
1585	if (os_snprintf_error(sizeof(data.pin_txt), ret))
1586		return -1;
1587	data.timeout = timeout;
1588	return hostapd_wps_for_each(hapd, wps_ap_pin_set, &data);
1589}
1590
1591
1592static int wps_update_ie(struct hostapd_data *hapd, void *ctx)
1593{
1594	if (hapd->wps)
1595		wps_registrar_update_ie(hapd->wps->registrar);
1596	return 0;
1597}
1598
1599
1600void hostapd_wps_update_ie(struct hostapd_data *hapd)
1601{
1602	hostapd_wps_for_each(hapd, wps_update_ie, NULL);
1603}
1604
1605
1606int hostapd_wps_config_ap(struct hostapd_data *hapd, const char *ssid,
1607			  const char *auth, const char *encr, const char *key)
1608{
1609	struct wps_credential cred;
1610	size_t len;
1611
1612	os_memset(&cred, 0, sizeof(cred));
1613
1614	len = os_strlen(ssid);
1615	if ((len & 1) || len > 2 * sizeof(cred.ssid) ||
1616	    hexstr2bin(ssid, cred.ssid, len / 2))
1617		return -1;
1618	cred.ssid_len = len / 2;
1619
1620	if (os_strncmp(auth, "OPEN", 4) == 0)
1621		cred.auth_type = WPS_AUTH_OPEN;
1622	else if (os_strncmp(auth, "WPAPSK", 6) == 0)
1623		cred.auth_type = WPS_AUTH_WPAPSK;
1624	else if (os_strncmp(auth, "WPA2PSK", 7) == 0)
1625		cred.auth_type = WPS_AUTH_WPA2PSK;
1626	else
1627		return -1;
1628
1629	if (encr) {
1630		if (os_strncmp(encr, "NONE", 4) == 0)
1631			cred.encr_type = WPS_ENCR_NONE;
1632		else if (os_strncmp(encr, "TKIP", 4) == 0)
1633			cred.encr_type = WPS_ENCR_TKIP;
1634		else if (os_strncmp(encr, "CCMP", 4) == 0)
1635			cred.encr_type = WPS_ENCR_AES;
1636		else
1637			return -1;
1638	} else
1639		cred.encr_type = WPS_ENCR_NONE;
1640
1641	if (key) {
1642		len = os_strlen(key);
1643		if ((len & 1) || len > 2 * sizeof(cred.key) ||
1644		    hexstr2bin(key, cred.key, len / 2))
1645			return -1;
1646		cred.key_len = len / 2;
1647	}
1648
1649	return wps_registrar_config_ap(hapd->wps->registrar, &cred);
1650}
1651
1652
1653#ifdef CONFIG_WPS_NFC
1654
1655struct wps_nfc_password_token_data {
1656	const u8 *oob_dev_pw;
1657	size_t oob_dev_pw_len;
1658	int added;
1659};
1660
1661
1662static int wps_add_nfc_password_token(struct hostapd_data *hapd, void *ctx)
1663{
1664	struct wps_nfc_password_token_data *data = ctx;
1665	int ret;
1666
1667	if (hapd->wps == NULL)
1668		return 0;
1669	ret = wps_registrar_add_nfc_password_token(hapd->wps->registrar,
1670						   data->oob_dev_pw,
1671						   data->oob_dev_pw_len);
1672	if (ret == 0)
1673		data->added++;
1674	return ret;
1675}
1676
1677
1678static int hostapd_wps_add_nfc_password_token(struct hostapd_data *hapd,
1679					      struct wps_parse_attr *attr)
1680{
1681	struct wps_nfc_password_token_data data;
1682
1683	data.oob_dev_pw = attr->oob_dev_password;
1684	data.oob_dev_pw_len = attr->oob_dev_password_len;
1685	data.added = 0;
1686	if (hostapd_wps_for_each(hapd, wps_add_nfc_password_token, &data) < 0)
1687		return -1;
1688	return data.added ? 0 : -1;
1689}
1690
1691
1692static int hostapd_wps_nfc_tag_process(struct hostapd_data *hapd,
1693				       const struct wpabuf *wps)
1694{
1695	struct wps_parse_attr attr;
1696
1697	wpa_hexdump_buf(MSG_DEBUG, "WPS: Received NFC tag payload", wps);
1698
1699	if (wps_parse_msg(wps, &attr)) {
1700		wpa_printf(MSG_DEBUG, "WPS: Ignore invalid data from NFC tag");
1701		return -1;
1702	}
1703
1704	if (attr.oob_dev_password)
1705		return hostapd_wps_add_nfc_password_token(hapd, &attr);
1706
1707	wpa_printf(MSG_DEBUG, "WPS: Ignore unrecognized NFC tag");
1708	return -1;
1709}
1710
1711
1712int hostapd_wps_nfc_tag_read(struct hostapd_data *hapd,
1713			     const struct wpabuf *data)
1714{
1715	const struct wpabuf *wps = data;
1716	struct wpabuf *tmp = NULL;
1717	int ret;
1718
1719	if (wpabuf_len(data) < 4)
1720		return -1;
1721
1722	if (*wpabuf_head_u8(data) != 0x10) {
1723		/* Assume this contains full NDEF record */
1724		tmp = ndef_parse_wifi(data);
1725		if (tmp == NULL) {
1726			wpa_printf(MSG_DEBUG, "WPS: Could not parse NDEF");
1727			return -1;
1728		}
1729		wps = tmp;
1730	}
1731
1732	ret = hostapd_wps_nfc_tag_process(hapd, wps);
1733	wpabuf_free(tmp);
1734	return ret;
1735}
1736
1737
1738struct wpabuf * hostapd_wps_nfc_config_token(struct hostapd_data *hapd,
1739					     int ndef)
1740{
1741	struct wpabuf *ret;
1742
1743	if (hapd->wps == NULL)
1744		return NULL;
1745
1746	ret = wps_get_oob_cred(hapd->wps, hostapd_wps_rf_band_cb(hapd),
1747			       hapd->iconf->channel);
1748	if (ndef && ret) {
1749		struct wpabuf *tmp;
1750		tmp = ndef_build_wifi(ret);
1751		wpabuf_free(ret);
1752		if (tmp == NULL)
1753			return NULL;
1754		ret = tmp;
1755	}
1756
1757	return ret;
1758}
1759
1760
1761struct wpabuf * hostapd_wps_nfc_hs_cr(struct hostapd_data *hapd, int ndef)
1762{
1763	struct wpabuf *ret;
1764
1765	if (hapd->wps == NULL)
1766		return NULL;
1767
1768	if (hapd->conf->wps_nfc_dh_pubkey == NULL) {
1769		struct wps_context *wps = hapd->wps;
1770		if (wps_nfc_gen_dh(&hapd->conf->wps_nfc_dh_pubkey,
1771				   &hapd->conf->wps_nfc_dh_privkey) < 0)
1772			return NULL;
1773		hostapd_wps_nfc_clear(wps);
1774		wps->ap_nfc_dev_pw_id = DEV_PW_NFC_CONNECTION_HANDOVER;
1775		wps->ap_nfc_dh_pubkey =
1776			wpabuf_dup(hapd->conf->wps_nfc_dh_pubkey);
1777		wps->ap_nfc_dh_privkey =
1778			wpabuf_dup(hapd->conf->wps_nfc_dh_privkey);
1779		if (!wps->ap_nfc_dh_pubkey || !wps->ap_nfc_dh_privkey) {
1780			hostapd_wps_nfc_clear(wps);
1781			return NULL;
1782		}
1783	}
1784
1785	ret = wps_build_nfc_handover_sel(hapd->wps,
1786					 hapd->conf->wps_nfc_dh_pubkey,
1787					 hapd->own_addr, hapd->iface->freq);
1788
1789	if (ndef && ret) {
1790		struct wpabuf *tmp;
1791		tmp = ndef_build_wifi(ret);
1792		wpabuf_free(ret);
1793		if (tmp == NULL)
1794			return NULL;
1795		ret = tmp;
1796	}
1797
1798	return ret;
1799}
1800
1801
1802int hostapd_wps_nfc_report_handover(struct hostapd_data *hapd,
1803				    const struct wpabuf *req,
1804				    const struct wpabuf *sel)
1805{
1806	struct wpabuf *wps;
1807	int ret = -1;
1808	u16 wsc_len;
1809	const u8 *pos;
1810	struct wpabuf msg;
1811	struct wps_parse_attr attr;
1812	u16 dev_pw_id;
1813
1814	/*
1815	 * Enrollee/station is always initiator of the NFC connection handover,
1816	 * so use the request message here to find Enrollee public key hash.
1817	 */
1818	wps = ndef_parse_wifi(req);
1819	if (wps == NULL)
1820		return -1;
1821	wpa_printf(MSG_DEBUG, "WPS: Received application/vnd.wfa.wsc "
1822		   "payload from NFC connection handover");
1823	wpa_hexdump_buf(MSG_DEBUG, "WPS: NFC payload", wps);
1824	if (wpabuf_len(wps) < 2) {
1825		wpa_printf(MSG_DEBUG, "WPS: Too short Wi-Fi Handover Request "
1826			   "Message");
1827		goto out;
1828	}
1829	pos = wpabuf_head(wps);
1830	wsc_len = WPA_GET_BE16(pos);
1831	if (wsc_len > wpabuf_len(wps) - 2) {
1832		wpa_printf(MSG_DEBUG, "WPS: Invalid WSC attribute length (%u) "
1833			   "in rt Wi-Fi Handover Request Message", wsc_len);
1834		goto out;
1835	}
1836	pos += 2;
1837
1838	wpa_hexdump(MSG_DEBUG,
1839		    "WPS: WSC attributes in Wi-Fi Handover Request Message",
1840		    pos, wsc_len);
1841	if (wsc_len < wpabuf_len(wps) - 2) {
1842		wpa_hexdump(MSG_DEBUG,
1843			    "WPS: Ignore extra data after WSC attributes",
1844			    pos + wsc_len, wpabuf_len(wps) - 2 - wsc_len);
1845	}
1846
1847	wpabuf_set(&msg, pos, wsc_len);
1848	ret = wps_parse_msg(&msg, &attr);
1849	if (ret < 0) {
1850		wpa_printf(MSG_DEBUG, "WPS: Could not parse WSC attributes in "
1851			   "Wi-Fi Handover Request Message");
1852		goto out;
1853	}
1854
1855	if (attr.oob_dev_password == NULL ||
1856	    attr.oob_dev_password_len < WPS_OOB_PUBKEY_HASH_LEN + 2) {
1857		wpa_printf(MSG_DEBUG, "WPS: No Out-of-Band Device Password "
1858			   "included in Wi-Fi Handover Request Message");
1859		ret = -1;
1860		goto out;
1861	}
1862
1863	if (attr.uuid_e == NULL) {
1864		wpa_printf(MSG_DEBUG, "WPS: No UUID-E included in Wi-Fi "
1865			   "Handover Request Message");
1866		ret = -1;
1867		goto out;
1868	}
1869
1870	wpa_hexdump(MSG_DEBUG, "WPS: UUID-E", attr.uuid_e, WPS_UUID_LEN);
1871
1872	wpa_hexdump(MSG_DEBUG, "WPS: Out-of-Band Device Password",
1873		    attr.oob_dev_password, attr.oob_dev_password_len);
1874	dev_pw_id = WPA_GET_BE16(attr.oob_dev_password +
1875				 WPS_OOB_PUBKEY_HASH_LEN);
1876	if (dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER) {
1877		wpa_printf(MSG_DEBUG, "WPS: Unexpected OOB Device Password ID "
1878			   "%u in Wi-Fi Handover Request Message", dev_pw_id);
1879		ret = -1;
1880		goto out;
1881	}
1882	wpa_hexdump(MSG_DEBUG, "WPS: Enrollee Public Key hash",
1883		    attr.oob_dev_password, WPS_OOB_PUBKEY_HASH_LEN);
1884
1885	ret = wps_registrar_add_nfc_pw_token(hapd->wps->registrar,
1886					     attr.oob_dev_password,
1887					     DEV_PW_NFC_CONNECTION_HANDOVER,
1888					     NULL, 0, 1);
1889
1890out:
1891	wpabuf_free(wps);
1892	return ret;
1893}
1894
1895
1896struct wpabuf * hostapd_wps_nfc_token_gen(struct hostapd_data *hapd, int ndef)
1897{
1898	if (hapd->conf->wps_nfc_pw_from_config) {
1899		return wps_nfc_token_build(ndef,
1900					   hapd->conf->wps_nfc_dev_pw_id,
1901					   hapd->conf->wps_nfc_dh_pubkey,
1902					   hapd->conf->wps_nfc_dev_pw);
1903	}
1904
1905	return wps_nfc_token_gen(ndef, &hapd->conf->wps_nfc_dev_pw_id,
1906				 &hapd->conf->wps_nfc_dh_pubkey,
1907				 &hapd->conf->wps_nfc_dh_privkey,
1908				 &hapd->conf->wps_nfc_dev_pw);
1909}
1910
1911
1912int hostapd_wps_nfc_token_enable(struct hostapd_data *hapd)
1913{
1914	struct wps_context *wps = hapd->wps;
1915	struct wpabuf *pw;
1916
1917	if (wps == NULL)
1918		return -1;
1919
1920	if (!hapd->conf->wps_nfc_dh_pubkey ||
1921	    !hapd->conf->wps_nfc_dh_privkey ||
1922	    !hapd->conf->wps_nfc_dev_pw ||
1923	    !hapd->conf->wps_nfc_dev_pw_id)
1924		return -1;
1925
1926	hostapd_wps_nfc_clear(wps);
1927	wpa_printf(MSG_DEBUG,
1928		   "WPS: Enable NFC Tag (Dev Pw Id %u) for AP interface %s (context %p)",
1929		   hapd->conf->wps_nfc_dev_pw_id, hapd->conf->iface, wps);
1930	wps->ap_nfc_dev_pw_id = hapd->conf->wps_nfc_dev_pw_id;
1931	wps->ap_nfc_dh_pubkey = wpabuf_dup(hapd->conf->wps_nfc_dh_pubkey);
1932	wps->ap_nfc_dh_privkey = wpabuf_dup(hapd->conf->wps_nfc_dh_privkey);
1933	pw = hapd->conf->wps_nfc_dev_pw;
1934	wps->ap_nfc_dev_pw = wpabuf_alloc(
1935		wpabuf_len(pw) * 2 + 1);
1936	if (wps->ap_nfc_dev_pw) {
1937		wpa_snprintf_hex_uppercase(
1938			(char *) wpabuf_put(wps->ap_nfc_dev_pw,
1939					    wpabuf_len(pw) * 2),
1940			wpabuf_len(pw) * 2 + 1,
1941			wpabuf_head(pw), wpabuf_len(pw));
1942	}
1943
1944	if (!wps->ap_nfc_dh_pubkey || !wps->ap_nfc_dh_privkey ||
1945	    !wps->ap_nfc_dev_pw) {
1946		hostapd_wps_nfc_clear(wps);
1947		return -1;
1948	}
1949
1950	return 0;
1951}
1952
1953
1954void hostapd_wps_nfc_token_disable(struct hostapd_data *hapd)
1955{
1956	wpa_printf(MSG_DEBUG, "WPS: Disable NFC token for AP interface %s",
1957		   hapd->conf->iface);
1958	hostapd_wps_nfc_clear(hapd->wps);
1959}
1960
1961#endif /* CONFIG_WPS_NFC */
1962