wps_registrar.c revision 98f9e76624da6bb96edc1982c423e4a119c5170a
18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Wi-Fi Protected Setup - Registrar
38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi>
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details.
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/includes.h"
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/common.h"
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/base64.h"
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/eloop.h"
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/uuid.h"
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/list.h"
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/crypto.h"
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/sha256.h"
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/random.h"
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common/ieee802_11_defs.h"
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "wps_i.h"
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "wps_dev_attr.h"
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "wps_upnp.h"
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "wps_upnp_i.h"
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef CONFIG_WPS_STRICT
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define WPS_WORKAROUNDS
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS_STRICT */
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wps_uuid_pin {
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct dl_list list;
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 uuid[WPS_UUID_LEN];
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int wildcard_uuid;
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *pin;
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t pin_len;
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define PIN_LOCKED BIT(0)
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define PIN_EXPIRES BIT(1)
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int flags;
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct os_time expiration;
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 enrollee_addr[ETH_ALEN];
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_free_pin(struct wps_uuid_pin *pin)
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(pin->pin);
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(pin);
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_remove_pin(struct wps_uuid_pin *pin)
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_del(&pin->list);
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_free_pin(pin);
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_free_pins(struct dl_list *pins)
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_uuid_pin *pin, *prev;
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_for_each_safe(pin, prev, pins, struct wps_uuid_pin, list)
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_remove_pin(pin);
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wps_pbc_session {
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_pbc_session *next;
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 addr[ETH_ALEN];
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 uuid_e[WPS_UUID_LEN];
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct os_time timestamp;
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_free_pbc_sessions(struct wps_pbc_session *pbc)
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_pbc_session *prev;
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (pbc) {
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		prev = pbc;
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pbc = pbc->next;
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(prev);
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wps_registrar_device {
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_registrar_device *next;
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_device_data dev;
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 uuid[WPS_UUID_LEN];
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wps_registrar {
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_context *wps;
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int pbc;
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int selected_registrar;
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int (*new_psk_cb)(void *ctx, const u8 *mac_addr, const u8 *psk,
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  size_t psk_len);
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int (*set_ie_cb)(void *ctx, struct wpabuf *beacon_ie,
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 struct wpabuf *probe_resp_ie);
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void (*pin_needed_cb)(void *ctx, const u8 *uuid_e,
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      const struct wps_device_data *dev);
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void (*reg_success_cb)(void *ctx, const u8 *mac_addr,
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       const u8 *uuid_e);
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void (*set_sel_reg_cb)(void *ctx, int sel_reg, u16 dev_passwd_id,
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       u16 sel_reg_config_methods);
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void (*enrollee_seen_cb)(void *ctx, const u8 *addr, const u8 *uuid_e,
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 const u8 *pri_dev_type, u16 config_methods,
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 u16 dev_password_id, u8 request_type,
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 const char *dev_name);
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void *cb_ctx;
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct dl_list pins;
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_pbc_session *pbc_sessions;
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int skip_cred_build;
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *extra_cred;
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int disable_auto_conf;
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int sel_reg_union;
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int sel_reg_dev_password_id_override;
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int sel_reg_config_methods_override;
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int static_wep_only;
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int dualband;
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_registrar_device *devices;
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int force_pbc_overlap;
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 authorized_macs[WPS_MAX_AUTHORIZED_MACS][ETH_ALEN];
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 authorized_macs_union[WPS_MAX_AUTHORIZED_MACS][ETH_ALEN];
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 p2p_dev_addr[ETH_ALEN];
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_set_ie(struct wps_registrar *reg);
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_registrar_pbc_timeout(void *eloop_ctx, void *timeout_ctx);
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_registrar_set_selected_timeout(void *eloop_ctx,
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					       void *timeout_ctx);
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_registrar_add_authorized_mac(struct wps_registrar *reg,
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					     const u8 *addr)
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i;
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Add authorized MAC " MACSTR,
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   MAC2STR(addr));
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < WPS_MAX_AUTHORIZED_MACS; i++)
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_memcmp(reg->authorized_macs[i], addr, ETH_ALEN) == 0) {
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "WPS: Authorized MAC was "
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "already in the list");
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return; /* already in list */
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = WPS_MAX_AUTHORIZED_MACS - 1; i > 0; i--)
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(reg->authorized_macs[i], reg->authorized_macs[i - 1],
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  ETH_ALEN);
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(reg->authorized_macs[0], addr, ETH_ALEN);
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "WPS: Authorized MACs",
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    (u8 *) reg->authorized_macs, sizeof(reg->authorized_macs));
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_registrar_remove_authorized_mac(struct wps_registrar *reg,
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						const u8 *addr)
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i;
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Remove authorized MAC " MACSTR,
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   MAC2STR(addr));
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < WPS_MAX_AUTHORIZED_MACS; i++) {
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_memcmp(reg->authorized_macs, addr, ETH_ALEN) == 0)
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (i == WPS_MAX_AUTHORIZED_MACS) {
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Authorized MAC was not in the "
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "list");
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return; /* not in the list */
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (; i + 1 < WPS_MAX_AUTHORIZED_MACS; i++)
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(reg->authorized_macs[i], reg->authorized_macs[i + 1],
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  ETH_ALEN);
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(reg->authorized_macs[WPS_MAX_AUTHORIZED_MACS - 1], 0,
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  ETH_ALEN);
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "WPS: Authorized MACs",
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    (u8 *) reg->authorized_macs, sizeof(reg->authorized_macs));
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_free_devices(struct wps_registrar_device *dev)
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_registrar_device *prev;
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (dev) {
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		prev = dev;
1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		dev = dev->next;
1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_device_data_free(&prev->dev);
1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(prev);
1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wps_registrar_device * wps_device_get(struct wps_registrar *reg,
2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						    const u8 *addr)
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_registrar_device *dev;
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (dev = reg->devices; dev; dev = dev->next) {
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_memcmp(dev->dev.mac_addr, addr, ETH_ALEN) == 0)
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return dev;
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_device_clone_data(struct wps_device_data *dst,
2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  struct wps_device_data *src)
2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(dst->mac_addr, src->mac_addr, ETH_ALEN);
2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(dst->pri_dev_type, src->pri_dev_type, WPS_DEV_TYPE_LEN);
2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define WPS_STRDUP(n) \
2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(dst->n); \
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dst->n = src->n ? os_strdup(src->n) : NULL
2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	WPS_STRDUP(device_name);
2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	WPS_STRDUP(manufacturer);
2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	WPS_STRDUP(model_name);
2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	WPS_STRDUP(model_number);
2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	WPS_STRDUP(serial_number);
2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#undef WPS_STRDUP
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wps_device_store(struct wps_registrar *reg,
2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		     struct wps_device_data *dev, const u8 *uuid)
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_registrar_device *d;
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	d = wps_device_get(reg, dev->mac_addr);
2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (d == NULL) {
2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		d = os_zalloc(sizeof(*d));
2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (d == NULL)
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		d->next = reg->devices;
2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		reg->devices = d;
2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_device_clone_data(&d->dev, dev);
2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(d->uuid, uuid, WPS_UUID_LEN);
2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_registrar_add_pbc_session(struct wps_registrar *reg,
2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  const u8 *addr, const u8 *uuid_e)
2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_pbc_session *pbc, *prev = NULL;
2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct os_time now;
2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_get_time(&now);
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pbc = reg->pbc_sessions;
2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (pbc) {
2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_memcmp(pbc->addr, addr, ETH_ALEN) == 0 &&
2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    os_memcmp(pbc->uuid_e, uuid_e, WPS_UUID_LEN) == 0) {
2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (prev)
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				prev->next = pbc->next;
2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			else
2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				reg->pbc_sessions = pbc->next;
2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		prev = pbc;
2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pbc = pbc->next;
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!pbc) {
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pbc = os_zalloc(sizeof(*pbc));
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (pbc == NULL)
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return;
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(pbc->addr, addr, ETH_ALEN);
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (uuid_e)
2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_memcpy(pbc->uuid_e, uuid_e, WPS_UUID_LEN);
2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pbc->next = reg->pbc_sessions;
2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	reg->pbc_sessions = pbc;
2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pbc->timestamp = now;
2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* remove entries that have timed out */
2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	prev = pbc;
2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pbc = pbc->next;
2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (pbc) {
2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (now.sec > pbc->timestamp.sec + WPS_PBC_WALK_TIME) {
2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			prev->next = NULL;
2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps_free_pbc_sessions(pbc);
2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		prev = pbc;
3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pbc = pbc->next;
3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_registrar_remove_pbc_session(struct wps_registrar *reg,
3071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					     const u8 *uuid_e,
3081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					     const u8 *p2p_dev_addr)
3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_pbc_session *pbc, *prev = NULL, *tmp;
3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pbc = reg->pbc_sessions;
3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (pbc) {
3141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (os_memcmp(pbc->uuid_e, uuid_e, WPS_UUID_LEN) == 0 ||
31598f9e76624da6bb96edc1982c423e4a119c5170aDmitry Shmidt#ifdef ANDROID_P2P
31698f9e76624da6bb96edc1982c423e4a119c5170aDmitry Shmidt		    (p2p_dev_addr && !is_zero_ether_addr(pbc->addr) &&
31798f9e76624da6bb96edc1982c423e4a119c5170aDmitry Shmidt		     os_memcmp(pbc->addr, p2p_dev_addr, ETH_ALEN) ==
31898f9e76624da6bb96edc1982c423e4a119c5170aDmitry Shmidt#else
3191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		    (p2p_dev_addr && !is_zero_ether_addr(reg->p2p_dev_addr) &&
3201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		     os_memcmp(reg->p2p_dev_addr, p2p_dev_addr, ETH_ALEN) ==
32198f9e76624da6bb96edc1982c423e4a119c5170aDmitry Shmidt#endif
3221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		     0)) {
3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (prev)
3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				prev->next = pbc->next;
3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			else
3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				reg->pbc_sessions = pbc->next;
3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			tmp = pbc;
3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			pbc = pbc->next;
3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "WPS: Removing PBC session for "
3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "addr=" MACSTR, MAC2STR(tmp->addr));
3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_hexdump(MSG_DEBUG, "WPS: Removed UUID-E",
3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    tmp->uuid_e, WPS_UUID_LEN);
3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_free(tmp);
3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		prev = pbc;
3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pbc = pbc->next;
3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wps_registrar_pbc_overlap(struct wps_registrar *reg,
3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      const u8 *addr, const u8 *uuid_e)
3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int count = 0;
3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_pbc_session *pbc;
3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_pbc_session *first = NULL;
3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct os_time now;
3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_get_time(&now);
3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Checking active PBC sessions for overlap");
3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (uuid_e) {
3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Add one for the requested UUID");
3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump(MSG_DEBUG, "WPS: Requested UUID",
3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    uuid_e, WPS_UUID_LEN);
3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		count++;
3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (pbc = reg->pbc_sessions; pbc; pbc = pbc->next) {
3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Consider PBC session with " MACSTR,
3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   MAC2STR(pbc->addr));
3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump(MSG_DEBUG, "WPS: UUID-E",
3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    pbc->uuid_e, WPS_UUID_LEN);
3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (now.sec > pbc->timestamp.sec + WPS_PBC_WALK_TIME) {
3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "WPS: PBC walk time has "
3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "expired");
3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (first &&
3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    os_memcmp(pbc->uuid_e, first->uuid_e, WPS_UUID_LEN) == 0) {
3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "WPS: Same Enrollee");
3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue; /* same Enrollee */
3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (uuid_e == NULL ||
3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    os_memcmp(uuid_e, pbc->uuid_e, WPS_UUID_LEN)) {
3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "WPS: New Enrollee");
3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			count++;
3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (first == NULL)
3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			first = pbc;
3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: %u active PBC session(s) found", count);
3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return count > 1 ? 1 : 0;
3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_build_wps_state(struct wps_context *wps, struct wpabuf *msg)
3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * Wi-Fi Protected Setup State (%d)",
3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   wps->wps_state);
3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_WPS_STATE);
3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, 1);
3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_u8(msg, wps->wps_state);
3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS_UPNP
4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_registrar_free_pending_m2(struct wps_context *wps)
4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct upnp_pending_message *p, *p2, *prev = NULL;
4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	p = wps->upnp_msgs;
4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (p) {
4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (p->type == WPS_M2 || p->type == WPS_M2D) {
4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (prev == NULL)
4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wps->upnp_msgs = p->next;
4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			else
4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				prev->next = p->next;
4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "WPS UPnP: Drop pending M2/M2D");
4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			p2 = p;
4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			p = p->next;
4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpabuf_free(p2->msg);
4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_free(p2);
4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		prev = p;
4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		p = p->next;
4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS_UPNP */
4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_build_ap_setup_locked(struct wps_context *wps,
4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     struct wpabuf *msg)
4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->ap_setup_locked && wps->ap_setup_locked != 2) {
4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS:  * AP Setup Locked");
4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_put_be16(msg, ATTR_AP_SETUP_LOCKED);
4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_put_be16(msg, 1);
4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_put_u8(msg, 1);
4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_build_selected_registrar(struct wps_registrar *reg,
4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					struct wpabuf *msg)
4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!reg->sel_reg_union)
4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * Selected Registrar");
4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_SELECTED_REGISTRAR);
4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, 1);
4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_u8(msg, 1);
4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_build_sel_reg_dev_password_id(struct wps_registrar *reg,
4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					     struct wpabuf *msg)
4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 id = reg->pbc ? DEV_PW_PUSHBUTTON : DEV_PW_DEFAULT;
4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!reg->sel_reg_union)
4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (reg->sel_reg_dev_password_id_override >= 0)
4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		id = reg->sel_reg_dev_password_id_override;
4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * Device Password ID (%d)", id);
4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_DEV_PASSWORD_ID);
4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, 2);
4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, id);
4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_build_sel_pbc_reg_uuid_e(struct wps_registrar *reg,
4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					struct wpabuf *msg)
4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 id = reg->pbc ? DEV_PW_PUSHBUTTON : DEV_PW_DEFAULT;
4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!reg->sel_reg_union)
4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (reg->sel_reg_dev_password_id_override >= 0)
4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		id = reg->sel_reg_dev_password_id_override;
4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (id != DEV_PW_PUSHBUTTON || !reg->dualband)
4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return wps_build_uuid_e(msg, reg->wps->uuid);
4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_set_pushbutton(u16 *methods, u16 conf_methods)
4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*methods |= WPS_CONFIG_PUSHBUTTON;
4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS2
4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conf_methods & WPS_CONFIG_VIRT_PUSHBUTTON)
4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*methods |= WPS_CONFIG_VIRT_PUSHBUTTON;
4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conf_methods & WPS_CONFIG_PHY_PUSHBUTTON)
4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*methods |= WPS_CONFIG_PHY_PUSHBUTTON;
4911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!(*methods & (WPS_CONFIG_VIRT_PUSHBUTTON |
4921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			  WPS_CONFIG_PHY_PUSHBUTTON))) {
4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * Required to include virtual/physical flag, but we were not
4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * configured with push button type, so have to default to one
4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * of them.
4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*methods |= WPS_CONFIG_PHY_PUSHBUTTON;
4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS2 */
5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_build_sel_reg_config_methods(struct wps_registrar *reg,
5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					    struct wpabuf *msg)
5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 methods;
5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!reg->sel_reg_union)
5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	methods = reg->wps->config_methods;
5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	methods &= ~WPS_CONFIG_PUSHBUTTON;
5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS2
5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON |
5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		     WPS_CONFIG_PHY_PUSHBUTTON);
5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS2 */
5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (reg->pbc)
5178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_set_pushbutton(&methods, reg->wps->config_methods);
5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (reg->sel_reg_config_methods_override >= 0)
5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		methods = reg->sel_reg_config_methods_override;
5208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * Selected Registrar Config Methods (%x)",
5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   methods);
5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_SELECTED_REGISTRAR_CONFIG_METHODS);
5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, 2);
5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, methods);
5258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
5268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_build_probe_config_methods(struct wps_registrar *reg,
5308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  struct wpabuf *msg)
5318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 methods;
5338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * These are the methods that the AP supports as an Enrollee for adding
5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * external Registrars.
5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
5378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON;
5388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS2
5398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON |
5408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		     WPS_CONFIG_PHY_PUSHBUTTON);
5418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS2 */
5428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * Config Methods (%x)", methods);
5438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_CONFIG_METHODS);
5448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, 2);
5458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, methods);
5468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
5478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_build_config_methods_r(struct wps_registrar *reg,
5518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      struct wpabuf *msg)
5528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return wps_build_config_methods(msg, reg->wps->config_methods);
5548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtconst u8 * wps_authorized_macs(struct wps_registrar *reg, size_t *count)
5588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*count = 0;
5608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS2
5628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (*count < WPS_MAX_AUTHORIZED_MACS) {
5638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (is_zero_ether_addr(reg->authorized_macs_union[*count]))
5648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
5658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		(*count)++;
5668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS2 */
5688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return (const u8 *) reg->authorized_macs_union;
5708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
5748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wps_registrar_init - Initialize WPS Registrar data
5758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @wps: Pointer to longterm WPS context
5768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @cfg: Registrar configuration
5778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Pointer to allocated Registrar data or %NULL on failure
5788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
5798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This function is used to initialize WPS Registrar functionality. It can be
5808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * used for a single Registrar run (e.g., when run in a supplicant) or multiple
5818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * runs (e.g., when run as an internal Registrar in an AP). Caller is
5828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * responsible for freeing the returned data with wps_registrar_deinit() when
5838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Registrar functionality is not needed anymore.
5848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
5858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wps_registrar *
5868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtwps_registrar_init(struct wps_context *wps,
5878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   const struct wps_registrar_config *cfg)
5888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_registrar *reg = os_zalloc(sizeof(*reg));
5908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (reg == NULL)
5918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
5928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_init(&reg->pins);
5948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	reg->wps = wps;
5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	reg->new_psk_cb = cfg->new_psk_cb;
5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	reg->set_ie_cb = cfg->set_ie_cb;
5978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	reg->pin_needed_cb = cfg->pin_needed_cb;
5988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	reg->reg_success_cb = cfg->reg_success_cb;
5998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	reg->set_sel_reg_cb = cfg->set_sel_reg_cb;
6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	reg->enrollee_seen_cb = cfg->enrollee_seen_cb;
6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	reg->cb_ctx = cfg->cb_ctx;
6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	reg->skip_cred_build = cfg->skip_cred_build;
6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (cfg->extra_cred) {
6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		reg->extra_cred = wpabuf_alloc_copy(cfg->extra_cred,
6058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						    cfg->extra_cred_len);
6068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (reg->extra_cred == NULL) {
6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_free(reg);
6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return NULL;
6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	reg->disable_auto_conf = cfg->disable_auto_conf;
6128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	reg->sel_reg_dev_password_id_override = -1;
6138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	reg->sel_reg_config_methods_override = -1;
6148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	reg->static_wep_only = cfg->static_wep_only;
6158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	reg->dualband = cfg->dualband;
6168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_set_ie(reg)) {
6188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_registrar_deinit(reg);
6198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
6208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return reg;
6238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
6278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wps_registrar_deinit - Deinitialize WPS Registrar data
6288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @reg: Registrar data from wps_registrar_init()
6298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
6308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wps_registrar_deinit(struct wps_registrar *reg)
6318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (reg == NULL)
6338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
6348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL);
6358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
6368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_free_pins(&reg->pins);
6378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_free_pbc_sessions(reg->pbc_sessions);
6388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(reg->extra_cred);
6398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_free_devices(reg->devices);
6408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(reg);
6418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
6458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wps_registrar_add_pin - Configure a new PIN for Registrar
6468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @reg: Registrar data from wps_registrar_init()
6478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @addr: Enrollee MAC address or %NULL if not known
6488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @uuid: UUID-E or %NULL for wildcard (any UUID)
6498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @pin: PIN (Device Password)
6508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @pin_len: Length of pin in octets
6518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @timeout: Time (in seconds) when the PIN will be invalidated; 0 = no timeout
6528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure
6538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
6548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wps_registrar_add_pin(struct wps_registrar *reg, const u8 *addr,
6558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  const u8 *uuid, const u8 *pin, size_t pin_len,
6568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  int timeout)
6578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_uuid_pin *p;
6598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	p = os_zalloc(sizeof(*p));
6618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (p == NULL)
6628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
6638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (addr)
6648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(p->enrollee_addr, addr, ETH_ALEN);
6658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (uuid == NULL)
6668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		p->wildcard_uuid = 1;
6678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
6688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(p->uuid, uuid, WPS_UUID_LEN);
6698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	p->pin = os_malloc(pin_len);
6708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (p->pin == NULL) {
6718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(p);
6728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
6738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(p->pin, pin, pin_len);
6758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	p->pin_len = pin_len;
6768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (timeout) {
6788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		p->flags |= PIN_EXPIRES;
6798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_get_time(&p->expiration);
6808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		p->expiration.sec += timeout;
6818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_add(&reg->pins, &p->list);
6848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: A new PIN configured (timeout=%d)",
6868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   timeout);
6878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "WPS: UUID", uuid, WPS_UUID_LEN);
6888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: PIN", pin, pin_len);
6898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	reg->selected_registrar = 1;
6908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	reg->pbc = 0;
6918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (addr)
6928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_registrar_add_authorized_mac(reg, addr);
6938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
6948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_registrar_add_authorized_mac(
6958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			reg, (u8 *) "\xff\xff\xff\xff\xff\xff");
6968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_registrar_selected_registrar_changed(reg);
6978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
6988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_register_timeout(WPS_PBC_WALK_TIME, 0,
6998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       wps_registrar_set_selected_timeout,
7008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       reg, NULL);
7018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
7038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_registrar_remove_pin(struct wps_registrar *reg,
7078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     struct wps_uuid_pin *pin)
7088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *addr;
7108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
7118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (is_zero_ether_addr(pin->enrollee_addr))
7138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		addr = bcast;
7148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
7158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		addr = pin->enrollee_addr;
7168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_registrar_remove_authorized_mac(reg, addr);
7178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_remove_pin(pin);
7188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_registrar_selected_registrar_changed(reg);
7198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_registrar_expire_pins(struct wps_registrar *reg)
7238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_uuid_pin *pin, *prev;
7258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct os_time now;
7268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_get_time(&now);
7288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_for_each_safe(pin, prev, &reg->pins, struct wps_uuid_pin, list)
7298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	{
7308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if ((pin->flags & PIN_EXPIRES) &&
7318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    os_time_before(&pin->expiration, &now)) {
7328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_hexdump(MSG_DEBUG, "WPS: Expired PIN for UUID",
7338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    pin->uuid, WPS_UUID_LEN);
7348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps_registrar_remove_pin(reg, pin);
7358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
7368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
7418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wps_registrar_invalidate_wildcard_pin - Invalidate a wildcard PIN
7428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @reg: Registrar data from wps_registrar_init()
7438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 if not wildcard PIN is enabled
7448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
7458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_registrar_invalidate_wildcard_pin(struct wps_registrar *reg)
7468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_uuid_pin *pin, *prev;
7488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_for_each_safe(pin, prev, &reg->pins, struct wps_uuid_pin, list)
7508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	{
7518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (pin->wildcard_uuid) {
7528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_hexdump(MSG_DEBUG, "WPS: Invalidated PIN for UUID",
7538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    pin->uuid, WPS_UUID_LEN);
7548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps_registrar_remove_pin(reg, pin);
7558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return 0;
7568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
7578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
7608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
7648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wps_registrar_invalidate_pin - Invalidate a PIN for a specific UUID-E
7658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @reg: Registrar data from wps_registrar_init()
7668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @uuid: UUID-E
7678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure (e.g., PIN not found)
7688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
7698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wps_registrar_invalidate_pin(struct wps_registrar *reg, const u8 *uuid)
7708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_uuid_pin *pin, *prev;
7728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_for_each_safe(pin, prev, &reg->pins, struct wps_uuid_pin, list)
7748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	{
7758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_memcmp(pin->uuid, uuid, WPS_UUID_LEN) == 0) {
7768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_hexdump(MSG_DEBUG, "WPS: Invalidated PIN for UUID",
7778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    pin->uuid, WPS_UUID_LEN);
7788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps_registrar_remove_pin(reg, pin);
7798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return 0;
7808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
7818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
7848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic const u8 * wps_registrar_get_pin(struct wps_registrar *reg,
7888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					const u8 *uuid, size_t *pin_len)
7898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_uuid_pin *pin, *found = NULL;
7918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_registrar_expire_pins(reg);
7938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_for_each(pin, &reg->pins, struct wps_uuid_pin, list) {
7958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!pin->wildcard_uuid &&
7968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    os_memcmp(pin->uuid, uuid, WPS_UUID_LEN) == 0) {
7978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			found = pin;
7988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
7998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
8008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!found) {
8038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Check for wildcard UUIDs since none of the UUID-specific
8048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * PINs matched */
8058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		dl_list_for_each(pin, &reg->pins, struct wps_uuid_pin, list) {
806c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			if (pin->wildcard_uuid == 1 ||
807c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			    pin->wildcard_uuid == 2) {
8088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpa_printf(MSG_DEBUG, "WPS: Found a wildcard "
8098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   "PIN. Assigned it for this UUID-E");
810c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				pin->wildcard_uuid++;
8118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				os_memcpy(pin->uuid, uuid, WPS_UUID_LEN);
8128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				found = pin;
8138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				break;
8148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
8158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
8168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!found)
8198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
8208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
8228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Lock the PIN to avoid attacks based on concurrent re-use of the PIN
8238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * that could otherwise avoid PIN invalidations.
8248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
8258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (found->flags & PIN_LOCKED) {
8268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Selected PIN locked - do not "
8278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "allow concurrent re-use");
8288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
8298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*pin_len = found->pin_len;
8318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	found->flags |= PIN_LOCKED;
8328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return found->pin;
8338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
8348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
8378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wps_registrar_unlock_pin - Unlock a PIN for a specific UUID-E
8388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @reg: Registrar data from wps_registrar_init()
8398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @uuid: UUID-E
8408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure
8418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
8428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * PINs are locked to enforce only one concurrent use. This function unlocks a
8438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * PIN to allow it to be used again. If the specified PIN was configured using
8448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * a wildcard UUID, it will be removed instead of allowing multiple uses.
8458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
8468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wps_registrar_unlock_pin(struct wps_registrar *reg, const u8 *uuid)
8478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
8488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_uuid_pin *pin;
8498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_for_each(pin, &reg->pins, struct wps_uuid_pin, list) {
8518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_memcmp(pin->uuid, uuid, WPS_UUID_LEN) == 0) {
852c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			if (pin->wildcard_uuid == 3) {
8538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpa_printf(MSG_DEBUG, "WPS: Invalidating used "
8548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   "wildcard PIN");
8558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				return wps_registrar_invalidate_pin(reg, uuid);
8568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
8578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			pin->flags &= ~PIN_LOCKED;
8588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return 0;
8598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
8608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
8638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
8648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_registrar_stop_pbc(struct wps_registrar *reg)
8678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
8688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	reg->selected_registrar = 0;
8698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	reg->pbc = 0;
8708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(reg->p2p_dev_addr, 0, ETH_ALEN);
8718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_registrar_remove_authorized_mac(reg,
8728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					    (u8 *) "\xff\xff\xff\xff\xff\xff");
8738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_registrar_selected_registrar_changed(reg);
8748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
8758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_registrar_pbc_timeout(void *eloop_ctx, void *timeout_ctx)
8788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
8798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_registrar *reg = eloop_ctx;
8808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: PBC timed out - disable PBC mode");
8828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_pbc_timeout_event(reg->wps);
8838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_registrar_stop_pbc(reg);
8848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
8858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
8888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wps_registrar_button_pushed - Notify Registrar that AP button was pushed
8898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @reg: Registrar data from wps_registrar_init()
8908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @p2p_dev_addr: Limit allowed PBC devices to the specified P2P device, %NULL
8918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *	indicates no such filtering
8928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure, -2 on session overlap
8938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
8948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This function is called on an AP when a push button is pushed to activate
8958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * PBC mode. The PBC mode will be stopped after walk time (2 minutes) timeout
8968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * or when a PBC registration is completed. If more than one Enrollee in active
8978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * PBC mode has been detected during the monitor time (previous 2 minutes), the
8981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * PBC mode is not activated and -2 is returned to indicate session overlap.
8991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * This is skipped if a specific Enrollee is selected.
9008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
9018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wps_registrar_button_pushed(struct wps_registrar *reg,
9028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				const u8 *p2p_dev_addr)
9038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
9048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (p2p_dev_addr == NULL &&
9058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_registrar_pbc_overlap(reg, NULL, NULL)) {
9068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: PBC overlap - do not start PBC "
9078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "mode");
9088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_pbc_overlap_event(reg->wps);
9098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -2;
9108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
9118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Button pushed - PBC mode started");
9128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	reg->force_pbc_overlap = 0;
9138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	reg->selected_registrar = 1;
9148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	reg->pbc = 1;
9158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (p2p_dev_addr)
9168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(reg->p2p_dev_addr, p2p_dev_addr, ETH_ALEN);
9178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
9188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memset(reg->p2p_dev_addr, 0, ETH_ALEN);
9198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_registrar_add_authorized_mac(reg,
9208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 (u8 *) "\xff\xff\xff\xff\xff\xff");
9218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_registrar_selected_registrar_changed(reg);
9228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
9248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL);
9258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wps_registrar_pbc_timeout,
9268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       reg, NULL);
9278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
9288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
9298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_registrar_pbc_completed(struct wps_registrar *reg)
9328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
9338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: PBC completed - stopping PBC mode");
9348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL);
9358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_registrar_stop_pbc(reg);
9368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
9378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_registrar_pin_completed(struct wps_registrar *reg)
9408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
9418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: PIN completed using internal Registrar");
9428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
9438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	reg->selected_registrar = 0;
9448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_registrar_selected_registrar_changed(reg);
9458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
9468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtvoid wps_registrar_complete(struct wps_registrar *registrar, const u8 *uuid_e)
9491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
9501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (registrar->pbc) {
9511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wps_registrar_remove_pbc_session(registrar,
9521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt						 uuid_e, NULL);
9531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wps_registrar_pbc_completed(registrar);
9541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	} else {
9551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wps_registrar_pin_completed(registrar);
9561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
9571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
9581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
9591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
9608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wps_registrar_wps_cancel(struct wps_registrar *reg)
9618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
9628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (reg->pbc) {
9638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: PBC is set - cancelling it");
9648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_registrar_pbc_timeout(reg, NULL);
965c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL);
9668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 1;
9678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (reg->selected_registrar) {
9688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* PIN Method */
9698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: PIN is set - cancelling it");
9708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_registrar_pin_completed(reg);
9718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_registrar_invalidate_wildcard_pin(reg);
9728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 1;
9738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
9748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
9758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
9768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
9798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wps_registrar_probe_req_rx - Notify Registrar of Probe Request
9808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @reg: Registrar data from wps_registrar_init()
9818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @addr: MAC address of the Probe Request sender
9828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @wps_data: WPS IE contents
9838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
9848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This function is called on an AP when a Probe Request with WPS IE is
9858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * received. This is used to track PBC mode use and to detect possible overlap
9868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * situation with other WPS APs.
9878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
9888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr,
9898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				const struct wpabuf *wps_data,
9908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				int p2p_wildcard)
9918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
9928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_parse_attr attr;
9938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_buf(MSG_MSGDUMP,
9958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			"WPS: Probe Request with WPS data received",
9968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps_data);
9978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_parse_msg(wps_data, &attr) < 0)
9998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
10008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (attr.config_methods == NULL) {
10028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No Config Methods attribute in "
10038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "Probe Request");
10048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
10058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (attr.dev_password_id == NULL) {
10088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No Device Password Id attribute "
10098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "in Probe Request");
10108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
10118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (reg->enrollee_seen_cb && attr.uuid_e &&
10148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    attr.primary_dev_type && attr.request_type && !p2p_wildcard) {
10158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		char *dev_name = NULL;
10168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (attr.dev_name) {
10178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			dev_name = os_zalloc(attr.dev_name_len + 1);
10188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (dev_name) {
10198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				os_memcpy(dev_name, attr.dev_name,
10208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  attr.dev_name_len);
10218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
10228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
10238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		reg->enrollee_seen_cb(reg->cb_ctx, addr, attr.uuid_e,
10248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      attr.primary_dev_type,
10258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      WPA_GET_BE16(attr.config_methods),
10268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      WPA_GET_BE16(attr.dev_password_id),
10278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      *attr.request_type, dev_name);
10288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(dev_name);
10298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (WPA_GET_BE16(attr.dev_password_id) != DEV_PW_PUSHBUTTON)
10328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return; /* Not PBC */
10338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Probe Request for PBC received from "
10358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   MACSTR, MAC2STR(addr));
10368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (attr.uuid_e == NULL) {
10378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Invalid Probe Request WPS IE: No "
10388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "UUID-E included");
10398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
10408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "WPS: UUID-E from Probe Request", attr.uuid_e,
10428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    WPS_UUID_LEN);
10438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_registrar_add_pbc_session(reg, addr, attr.uuid_e);
10458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_registrar_pbc_overlap(reg, addr, attr.uuid_e)) {
10468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: PBC session overlap detected");
10478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		reg->force_pbc_overlap = 1;
10488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_pbc_overlap_event(reg->wps);
10498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_cb_new_psk(struct wps_registrar *reg, const u8 *mac_addr,
10548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  const u8 *psk, size_t psk_len)
10558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
10568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (reg->new_psk_cb == NULL)
10578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
10588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return reg->new_psk_cb(reg->cb_ctx, mac_addr, psk, psk_len);
10608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_cb_pin_needed(struct wps_registrar *reg, const u8 *uuid_e,
10648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      const struct wps_device_data *dev)
10658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
10668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (reg->pin_needed_cb == NULL)
10678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
10688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	reg->pin_needed_cb(reg->cb_ctx, uuid_e, dev);
10708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_cb_reg_success(struct wps_registrar *reg, const u8 *mac_addr,
10748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       const u8 *uuid_e)
10758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
10768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (reg->reg_success_cb == NULL)
10778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
10788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	reg->reg_success_cb(reg->cb_ctx, mac_addr, uuid_e);
10808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_cb_set_ie(struct wps_registrar *reg, struct wpabuf *beacon_ie,
10848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 struct wpabuf *probe_resp_ie)
10858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
10868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return reg->set_ie_cb(reg->cb_ctx, beacon_ie, probe_resp_ie);
10878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_cb_set_sel_reg(struct wps_registrar *reg)
10918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
10928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 methods = 0;
10938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (reg->set_sel_reg_cb == NULL)
10948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
10958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (reg->selected_registrar) {
10978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON;
10988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS2
10998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON |
11008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     WPS_CONFIG_PHY_PUSHBUTTON);
11018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS2 */
11028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (reg->pbc)
11038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps_set_pushbutton(&methods, reg->wps->config_methods);
11048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
11058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: wps_cb_set_sel_reg: sel_reg=%d "
11078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "config_methods=0x%x pbc=%d methods=0x%x",
11088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   reg->selected_registrar, reg->wps->config_methods,
11098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   reg->pbc, methods);
11108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	reg->set_sel_reg_cb(reg->cb_ctx, reg->selected_registrar,
11128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    reg->pbc ? DEV_PW_PUSHBUTTON : DEV_PW_DEFAULT,
11138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    methods);
11148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
11158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_set_ie(struct wps_registrar *reg)
11188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
11198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *beacon;
11208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *probe;
11218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *auth_macs;
11228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t count;
11238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t vendor_len = 0;
11248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i;
11258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (reg->set_ie_cb == NULL)
11278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
11288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
11308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (reg->wps->dev.vendor_ext[i]) {
11318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			vendor_len += 2 + 2;
11328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			vendor_len += wpabuf_len(reg->wps->dev.vendor_ext[i]);
11338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
11348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
11358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	beacon = wpabuf_alloc(400 + vendor_len);
11378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (beacon == NULL)
11388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
11398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	probe = wpabuf_alloc(500 + vendor_len);
11408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (probe == NULL) {
11418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(beacon);
11428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
11438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
11448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	auth_macs = wps_authorized_macs(reg, &count);
11468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Build Beacon IEs");
11488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_build_version(beacon) ||
11508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_wps_state(reg->wps, beacon) ||
11518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_ap_setup_locked(reg->wps, beacon) ||
11528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_selected_registrar(reg, beacon) ||
11538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_sel_reg_dev_password_id(reg, beacon) ||
11548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_sel_reg_config_methods(reg, beacon) ||
11558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_sel_pbc_reg_uuid_e(reg, beacon) ||
11568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    (reg->dualband && wps_build_rf_bands(&reg->wps->dev, beacon)) ||
11578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_wfa_ext(beacon, 0, auth_macs, count) ||
11588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_vendor_ext(&reg->wps->dev, beacon)) {
11598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(beacon);
11608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(probe);
11618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
11628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
11638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_P2P
11658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_build_dev_name(&reg->wps->dev, beacon) ||
11668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_primary_dev_type(&reg->wps->dev, beacon)) {
11678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(beacon);
11688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(probe);
11698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
11708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
11718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_P2P */
11728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Build Probe Response IEs");
11748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_build_version(probe) ||
11768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_wps_state(reg->wps, probe) ||
11778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_ap_setup_locked(reg->wps, probe) ||
11788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_selected_registrar(reg, probe) ||
11798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_sel_reg_dev_password_id(reg, probe) ||
11808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_sel_reg_config_methods(reg, probe) ||
11818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_resp_type(probe, reg->wps->ap ? WPS_RESP_AP :
11828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				WPS_RESP_REGISTRAR) ||
11838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_uuid_e(probe, reg->wps->uuid) ||
11848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_device_attrs(&reg->wps->dev, probe) ||
11858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_probe_config_methods(reg, probe) ||
11868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_rf_bands(&reg->wps->dev, probe) ||
11878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_wfa_ext(probe, 0, auth_macs, count) ||
11888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_vendor_ext(&reg->wps->dev, probe)) {
11898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(beacon);
11908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(probe);
11918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
11928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
11938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	beacon = wps_ie_encapsulate(beacon);
11958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	probe = wps_ie_encapsulate(probe);
11968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!beacon || !probe) {
11988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(beacon);
11998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(probe);
12008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
12018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
12028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (reg->static_wep_only) {
12048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
12058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * Windows XP and Vista clients can get confused about
12068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * EAP-Identity/Request when they probe the network with
12078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * EAPOL-Start. In such a case, they may assume the network is
12088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * using IEEE 802.1X and prompt user for a certificate while
12098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * the correct (non-WPS) behavior would be to ask for the
12108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * static WEP key. As a workaround, use Microsoft Provisioning
12118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * IE to advertise that legacy 802.1X is not supported.
12128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
12138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		const u8 ms_wps[7] = {
12148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			WLAN_EID_VENDOR_SPECIFIC, 5,
12158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			/* Microsoft Provisioning IE (00:50:f2:5) */
12168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			0x00, 0x50, 0xf2, 5,
12178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			0x00 /* no legacy 802.1X or MS WPS */
12188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		};
12198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Add Microsoft Provisioning IE "
12208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "into Beacon/Probe Response frames");
12218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_put_data(beacon, ms_wps, sizeof(ms_wps));
12228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_put_data(probe, ms_wps, sizeof(ms_wps));
12238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
12248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return wps_cb_set_ie(reg, beacon, probe);
12268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
12278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_get_dev_password(struct wps_data *wps)
12308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
12318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *pin;
12328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t pin_len = 0;
12338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(wps->dev_password);
12358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->dev_password = NULL;
12368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->pbc) {
12388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Use default PIN for PBC");
12398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pin = (const u8 *) "00000000";
12408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pin_len = 8;
12418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
12428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pin = wps_registrar_get_pin(wps->wps->registrar, wps->uuid_e,
12438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					    &pin_len);
12448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
12458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pin == NULL) {
12468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No Device Password available for "
12478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "the Enrollee");
12488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_cb_pin_needed(wps->wps->registrar, wps->uuid_e,
12498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  &wps->peer_dev);
12508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
12518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
12528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->dev_password = os_malloc(pin_len);
12548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->dev_password == NULL)
12558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
12568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(wps->dev_password, pin, pin_len);
12578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->dev_password_len = pin_len;
12588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
12608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
12618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_build_uuid_r(struct wps_data *wps, struct wpabuf *msg)
12648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
12658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * UUID-R");
12668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_UUID_R);
12678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, WPS_UUID_LEN);
12688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_data(msg, wps->uuid_r, WPS_UUID_LEN);
12698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
12708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
12718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_build_r_hash(struct wps_data *wps, struct wpabuf *msg)
12748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
12758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *hash;
12768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *addr[4];
12778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t len[4];
12788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (random_get_bytes(wps->snonce, 2 * WPS_SECRET_NONCE_LEN) < 0)
12808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
12818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "WPS: R-S1", wps->snonce, WPS_SECRET_NONCE_LEN);
12828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "WPS: R-S2",
12838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    wps->snonce + WPS_SECRET_NONCE_LEN, WPS_SECRET_NONCE_LEN);
12848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->dh_pubkey_e == NULL || wps->dh_pubkey_r == NULL) {
12868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: DH public keys not available for "
12878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "R-Hash derivation");
12888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
12898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
12908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * R-Hash1");
12928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_R_HASH1);
12938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, SHA256_MAC_LEN);
12948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hash = wpabuf_put(msg, SHA256_MAC_LEN);
12958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* R-Hash1 = HMAC_AuthKey(R-S1 || PSK1 || PK_E || PK_R) */
12968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[0] = wps->snonce;
12978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[0] = WPS_SECRET_NONCE_LEN;
12988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[1] = wps->psk1;
12998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[1] = WPS_PSK_LEN;
13008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[2] = wpabuf_head(wps->dh_pubkey_e);
13018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[2] = wpabuf_len(wps->dh_pubkey_e);
13028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[3] = wpabuf_head(wps->dh_pubkey_r);
13038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[3] = wpabuf_len(wps->dh_pubkey_r);
13048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
13058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "WPS: R-Hash1", hash, SHA256_MAC_LEN);
13068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * R-Hash2");
13088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_R_HASH2);
13098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, SHA256_MAC_LEN);
13108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hash = wpabuf_put(msg, SHA256_MAC_LEN);
13118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* R-Hash2 = HMAC_AuthKey(R-S2 || PSK2 || PK_E || PK_R) */
13128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[0] = wps->snonce + WPS_SECRET_NONCE_LEN;
13138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[1] = wps->psk2;
13148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
13158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "WPS: R-Hash2", hash, SHA256_MAC_LEN);
13168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
13188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
13198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_build_r_snonce1(struct wps_data *wps, struct wpabuf *msg)
13228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
13238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * R-SNonce1");
13248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_R_SNONCE1);
13258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, WPS_SECRET_NONCE_LEN);
13268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_data(msg, wps->snonce, WPS_SECRET_NONCE_LEN);
13278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
13288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
13298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_build_r_snonce2(struct wps_data *wps, struct wpabuf *msg)
13328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
13338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * R-SNonce2");
13348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_R_SNONCE2);
13358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, WPS_SECRET_NONCE_LEN);
13368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_data(msg, wps->snonce + WPS_SECRET_NONCE_LEN,
13378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			WPS_SECRET_NONCE_LEN);
13388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
13398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
13408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_build_cred_network_idx(struct wpabuf *msg,
13438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      const struct wps_credential *cred)
13448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
13458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * Network Index (1)");
13468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_NETWORK_INDEX);
13478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, 1);
13488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_u8(msg, 1);
13498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
13508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
13518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_build_cred_ssid(struct wpabuf *msg,
13548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       const struct wps_credential *cred)
13558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
13568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * SSID");
13578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID for Credential",
13588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  cred->ssid, cred->ssid_len);
13598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_SSID);
13608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, cred->ssid_len);
13618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_data(msg, cred->ssid, cred->ssid_len);
13628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
13638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
13648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_build_cred_auth_type(struct wpabuf *msg,
13678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    const struct wps_credential *cred)
13688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
13698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * Authentication Type (0x%x)",
13708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   cred->auth_type);
13718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_AUTH_TYPE);
13728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, 2);
13738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, cred->auth_type);
13748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
13758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
13768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_build_cred_encr_type(struct wpabuf *msg,
13798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    const struct wps_credential *cred)
13808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
13818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * Encryption Type (0x%x)",
13828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   cred->encr_type);
13838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_ENCR_TYPE);
13848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, 2);
13858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, cred->encr_type);
13868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
13878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
13888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_build_cred_network_key(struct wpabuf *msg,
13918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      const struct wps_credential *cred)
13928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
13938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * Network Key (len=%d)",
13948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   (int) cred->key_len);
13958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key",
13968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			cred->key, cred->key_len);
13978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_NETWORK_KEY);
13988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, cred->key_len);
13998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_data(msg, cred->key, cred->key_len);
14008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
14018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
14028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_build_cred_mac_addr(struct wpabuf *msg,
14058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   const struct wps_credential *cred)
14068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
14078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * MAC Address (" MACSTR ")",
14088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   MAC2STR(cred->mac_addr));
14098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_MAC_ADDR);
14108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ETH_ALEN);
14118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_data(msg, cred->mac_addr, ETH_ALEN);
14128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
14138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
14148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_build_credential(struct wpabuf *msg,
14178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				const struct wps_credential *cred)
14188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
14198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_build_cred_network_idx(msg, cred) ||
14208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_cred_ssid(msg, cred) ||
14218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_cred_auth_type(msg, cred) ||
14228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_cred_encr_type(msg, cred) ||
14238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_cred_network_key(msg, cred) ||
14248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_cred_mac_addr(msg, cred))
14258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
14268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
14278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
14288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtint wps_build_credential_wrap(struct wpabuf *msg,
14311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			      const struct wps_credential *cred)
14321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
14331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpabuf *wbuf;
14341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wbuf = wpabuf_alloc(200);
14351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (wbuf == NULL)
14361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
14371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (wps_build_credential(wbuf, cred)) {
14381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpabuf_free(wbuf);
14391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
14401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
14411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpabuf_put_be16(msg, ATTR_CRED);
14421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpabuf_put_be16(msg, wpabuf_len(wbuf));
14431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpabuf_put_buf(msg, wbuf);
14441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpabuf_free(wbuf);
14451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return 0;
14461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
14471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
14481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
14498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wps_build_cred(struct wps_data *wps, struct wpabuf *msg)
14508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
14518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *cred;
14528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->wps->registrar->skip_cred_build)
14548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto skip_cred_build;
14558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * Credential");
14578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->use_cred) {
14588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(&wps->cred, wps->use_cred, sizeof(wps->cred));
14598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto use_provided;
14608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
14618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&wps->cred, 0, sizeof(wps->cred));
14628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(wps->cred.ssid, wps->wps->ssid, wps->wps->ssid_len);
14648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->cred.ssid_len = wps->wps->ssid_len;
14658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Select the best authentication and encryption type */
14678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->auth_type & WPS_AUTH_WPA2PSK)
14688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->auth_type = WPS_AUTH_WPA2PSK;
14698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else if (wps->auth_type & WPS_AUTH_WPAPSK)
14708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->auth_type = WPS_AUTH_WPAPSK;
14718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else if (wps->auth_type & WPS_AUTH_OPEN)
14728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->auth_type = WPS_AUTH_OPEN;
14738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else if (wps->auth_type & WPS_AUTH_SHARED)
14748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->auth_type = WPS_AUTH_SHARED;
14758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else {
14768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Unsupported auth_type 0x%x",
14778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   wps->auth_type);
14788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
14798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
14808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->cred.auth_type = wps->auth_type;
14818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->auth_type == WPS_AUTH_WPA2PSK ||
14838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps->auth_type == WPS_AUTH_WPAPSK) {
14848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (wps->encr_type & WPS_ENCR_AES)
14858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps->encr_type = WPS_ENCR_AES;
14868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		else if (wps->encr_type & WPS_ENCR_TKIP)
14878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps->encr_type = WPS_ENCR_TKIP;
14888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		else {
14898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "WPS: No suitable encryption "
14908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "type for WPA/WPA2");
14918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
14928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
14938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
14948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (wps->encr_type & WPS_ENCR_WEP)
14958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps->encr_type = WPS_ENCR_WEP;
14968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		else if (wps->encr_type & WPS_ENCR_NONE)
14978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps->encr_type = WPS_ENCR_NONE;
14988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		else {
14998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "WPS: No suitable encryption "
15008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "type for non-WPA/WPA2 mode");
15018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
15028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
15038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
15048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->cred.encr_type = wps->encr_type;
15058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
15068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Set MAC address in the Credential to be the Enrollee's MAC address
15078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
15088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(wps->cred.mac_addr, wps->mac_addr_e, ETH_ALEN);
15098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->wps->wps_state == WPS_STATE_NOT_CONFIGURED && wps->wps->ap &&
15118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    !wps->wps->registrar->disable_auto_conf) {
15128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		u8 r[16];
15138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Generate a random passphrase */
15148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (random_get_bytes(r, sizeof(r)) < 0)
15158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
15168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(wps->new_psk);
15178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->new_psk = base64_encode(r, sizeof(r), &wps->new_psk_len);
15188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (wps->new_psk == NULL)
15198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
15208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->new_psk_len--; /* remove newline */
15218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		while (wps->new_psk_len &&
15228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       wps->new_psk[wps->new_psk_len - 1] == '=')
15238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps->new_psk_len--;
15248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: Generated passphrase",
15258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      wps->new_psk, wps->new_psk_len);
15268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(wps->cred.key, wps->new_psk, wps->new_psk_len);
15278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->cred.key_len = wps->new_psk_len;
15288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (wps->use_psk_key && wps->wps->psk_set) {
15298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		char hex[65];
15308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Use PSK format for Network Key");
15318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_snprintf_hex(hex, sizeof(hex), wps->wps->psk, 32);
15328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(wps->cred.key, hex, 32 * 2);
15338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->cred.key_len = 32 * 2;
15348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (wps->wps->network_key) {
15358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(wps->cred.key, wps->wps->network_key,
15368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  wps->wps->network_key_len);
15378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->cred.key_len = wps->wps->network_key_len;
15388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (wps->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) {
15398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		char hex[65];
15408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Generate a random per-device PSK */
15418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(wps->new_psk);
15428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->new_psk_len = 32;
15438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->new_psk = os_malloc(wps->new_psk_len);
15448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (wps->new_psk == NULL)
15458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
15468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (random_get_bytes(wps->new_psk, wps->new_psk_len) < 0) {
15478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_free(wps->new_psk);
15488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps->new_psk = NULL;
15498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
15508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
15518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_key(MSG_DEBUG, "WPS: Generated per-device PSK",
15528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wps->new_psk, wps->new_psk_len);
15538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_snprintf_hex(hex, sizeof(hex), wps->new_psk,
15548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 wps->new_psk_len);
15558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(wps->cred.key, hex, wps->new_psk_len * 2);
15568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->cred.key_len = wps->new_psk_len * 2;
15578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
15588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtuse_provided:
15608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS_TESTING
15618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_testing_dummy_cred)
15628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		cred = wpabuf_alloc(200);
15638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
15648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		cred = NULL;
15658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (cred) {
15668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct wps_credential dummy;
15678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Add dummy credential");
15688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memset(&dummy, 0, sizeof(dummy));
15698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(dummy.ssid, "dummy", 5);
15708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		dummy.ssid_len = 5;
15718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		dummy.auth_type = WPS_AUTH_WPA2PSK;
15728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		dummy.encr_type = WPS_ENCR_AES;
15738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(dummy.key, "dummy psk", 9);
15748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		dummy.key_len = 9;
15758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(dummy.mac_addr, wps->mac_addr_e, ETH_ALEN);
15768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_build_credential(cred, &dummy);
15778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_buf(MSG_DEBUG, "WPS: Dummy Credential", cred);
15788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_put_be16(msg, ATTR_CRED);
15808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_put_be16(msg, wpabuf_len(cred));
15818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_put_buf(msg, cred);
15828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(cred);
15848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
15858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS_TESTING */
15868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cred = wpabuf_alloc(200);
15888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (cred == NULL)
15898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
15908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_build_credential(cred, &wps->cred)) {
15928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(cred);
15938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
15948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
15958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_CRED);
15978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, wpabuf_len(cred));
15988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_buf(msg, cred);
15998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(cred);
16008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtskip_cred_build:
16028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->wps->registrar->extra_cred) {
16038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS:  * Credential (pre-configured)");
16048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_put_buf(msg, wps->wps->registrar->extra_cred);
16058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
16068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
16088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
16098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_build_ap_settings(struct wps_data *wps, struct wpabuf *msg)
16128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
16138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS:  * AP Settings");
16148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_build_credential(msg, &wps->cred))
16168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
16178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
16198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
16208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic struct wpabuf * wps_build_ap_cred(struct wps_data *wps)
16231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
16241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpabuf *msg, *plain;
16251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
16261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	msg = wpabuf_alloc(1000);
16271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (msg == NULL)
16281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NULL;
16291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
16301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	plain = wpabuf_alloc(200);
16311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (plain == NULL) {
16321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpabuf_free(msg);
16331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NULL;
16341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
16351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
16361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (wps_build_ap_settings(wps, plain)) {
16371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpabuf_free(plain);
16381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpabuf_free(msg);
16391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NULL;
16401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
16411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
16421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpabuf_put_be16(msg, ATTR_CRED);
16431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpabuf_put_be16(msg, wpabuf_len(plain));
16441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpabuf_put_buf(msg, plain);
16451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpabuf_free(plain);
16461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
16471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return msg;
16481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
16491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
16501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
16518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * wps_build_m2(struct wps_data *wps)
16528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
16538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *msg;
16548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (random_get_bytes(wps->nonce_r, WPS_NONCE_LEN) < 0)
16568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
16578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "WPS: Registrar Nonce",
16588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    wps->nonce_r, WPS_NONCE_LEN);
16598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "WPS: UUID-R", wps->uuid_r, WPS_UUID_LEN);
16608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Building Message M2");
16628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = wpabuf_alloc(1000);
16638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (msg == NULL)
16648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
16658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_build_version(msg) ||
16678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_msg_type(msg, WPS_M2) ||
16688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_enrollee_nonce(wps, msg) ||
16698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_registrar_nonce(wps, msg) ||
16708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_uuid_r(wps, msg) ||
16718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_public_key(wps, msg) ||
16728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_derive_keys(wps) ||
16738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_auth_type_flags(wps, msg) ||
16748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_encr_type_flags(wps, msg) ||
16758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_conn_type_flags(wps, msg) ||
16768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_config_methods_r(wps->wps->registrar, msg) ||
16778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_device_attrs(&wps->wps->dev, msg) ||
16788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_rf_bands(&wps->wps->dev, msg) ||
16798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_assoc_state(wps, msg) ||
16808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_config_error(msg, WPS_CFG_NO_ERROR) ||
16818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_dev_password_id(msg, wps->dev_pw_id) ||
16828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_os_version(&wps->wps->dev, msg) ||
16838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_wfa_ext(msg, 0, NULL, 0) ||
16848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_authenticator(wps, msg)) {
16858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(msg);
16868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
16878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
16888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->int_reg = 1;
16908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->state = RECV_M3;
16918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return msg;
16928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
16938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * wps_build_m2d(struct wps_data *wps)
16968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
16978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *msg;
16988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 err = wps->config_error;
16998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Building Message M2D");
17018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = wpabuf_alloc(1000);
17028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (msg == NULL)
17038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
17048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->wps->ap && wps->wps->ap_setup_locked &&
17068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    err == WPS_CFG_NO_ERROR)
17078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		err = WPS_CFG_SETUP_LOCKED;
17088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_build_version(msg) ||
17108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_msg_type(msg, WPS_M2D) ||
17118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_enrollee_nonce(wps, msg) ||
17128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_registrar_nonce(wps, msg) ||
17138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_uuid_r(wps, msg) ||
17148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_auth_type_flags(wps, msg) ||
17158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_encr_type_flags(wps, msg) ||
17168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_conn_type_flags(wps, msg) ||
17178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_config_methods_r(wps->wps->registrar, msg) ||
17188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_device_attrs(&wps->wps->dev, msg) ||
17198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_rf_bands(&wps->wps->dev, msg) ||
17208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_assoc_state(wps, msg) ||
17218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_config_error(msg, err) ||
17228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_os_version(&wps->wps->dev, msg) ||
17238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_wfa_ext(msg, 0, NULL, 0)) {
17248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(msg);
17258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
17268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
17278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->state = RECV_M2D_ACK;
17298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return msg;
17308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
17318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * wps_build_m4(struct wps_data *wps)
17348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
17358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *msg, *plain;
17368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Building Message M4");
17388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_derive_psk(wps, wps->dev_password, wps->dev_password_len);
17408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	plain = wpabuf_alloc(200);
17428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (plain == NULL)
17438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
17448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = wpabuf_alloc(1000);
17468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (msg == NULL) {
17478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(plain);
17488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
17498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
17508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_build_version(msg) ||
17528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_msg_type(msg, WPS_M4) ||
17538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_enrollee_nonce(wps, msg) ||
17548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_r_hash(wps, msg) ||
17558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_r_snonce1(wps, plain) ||
17568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_key_wrap_auth(wps, plain) ||
17578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_encr_settings(wps, msg, plain) ||
17588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_wfa_ext(msg, 0, NULL, 0) ||
17598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_authenticator(wps, msg)) {
17608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(plain);
17618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(msg);
17628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
17638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
17648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(plain);
17658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->state = RECV_M5;
17678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return msg;
17688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
17698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * wps_build_m6(struct wps_data *wps)
17728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
17738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *msg, *plain;
17748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Building Message M6");
17768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	plain = wpabuf_alloc(200);
17788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (plain == NULL)
17798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
17808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = wpabuf_alloc(1000);
17828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (msg == NULL) {
17838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(plain);
17848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
17858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
17868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_build_version(msg) ||
17888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_msg_type(msg, WPS_M6) ||
17898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_enrollee_nonce(wps, msg) ||
17908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_r_snonce2(wps, plain) ||
17918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_key_wrap_auth(wps, plain) ||
17928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_encr_settings(wps, msg, plain) ||
17938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_wfa_ext(msg, 0, NULL, 0) ||
17948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_authenticator(wps, msg)) {
17958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(plain);
17968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(msg);
17978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
17988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
17998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(plain);
18008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->wps_pin_revealed = 1;
18028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->state = RECV_M7;
18038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return msg;
18048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
18058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * wps_build_m8(struct wps_data *wps)
18088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
18098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *msg, *plain;
18108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Building Message M8");
18128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	plain = wpabuf_alloc(500);
18148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (plain == NULL)
18158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
18168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = wpabuf_alloc(1000);
18188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (msg == NULL) {
18198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(plain);
18208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
18218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
18228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_build_version(msg) ||
18248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_msg_type(msg, WPS_M8) ||
18258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_enrollee_nonce(wps, msg) ||
18268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    ((wps->wps->ap || wps->er) && wps_build_cred(wps, plain)) ||
18278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    (!wps->wps->ap && !wps->er && wps_build_ap_settings(wps, plain)) ||
18288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_key_wrap_auth(wps, plain) ||
18298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_encr_settings(wps, msg, plain) ||
18308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_wfa_ext(msg, 0, NULL, 0) ||
18318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_authenticator(wps, msg)) {
18328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(plain);
18338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(msg);
18348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
18358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
18368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(plain);
18378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->state = RECV_DONE;
18398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return msg;
18408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
18418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpabuf * wps_registrar_get_msg(struct wps_data *wps,
18448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      enum wsc_op_code *op_code)
18458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
18468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *msg;
18478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS_UPNP
18498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!wps->int_reg && wps->wps->wps_upnp) {
18508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct upnp_pending_message *p, *prev = NULL;
18518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (wps->ext_reg > 1)
18528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps_registrar_free_pending_m2(wps->wps);
18538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		p = wps->wps->upnp_msgs;
18548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* TODO: check pending message MAC address */
18558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		while (p && p->next) {
18568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			prev = p;
18578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			p = p->next;
18588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
18598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (p) {
18608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "WPS: Use pending message from "
18618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "UPnP");
18628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (prev)
18638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				prev->next = NULL;
18648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			else
18658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wps->wps->upnp_msgs = NULL;
18668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			msg = p->msg;
18678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			switch (p->type) {
18688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			case WPS_WSC_ACK:
18698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				*op_code = WSC_ACK;
18708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				break;
18718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			case WPS_WSC_NACK:
18728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				*op_code = WSC_NACK;
18738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				break;
18748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			default:
18758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				*op_code = WSC_MSG;
18768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				break;
18778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
18788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_free(p);
18798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (wps->ext_reg == 0)
18808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wps->ext_reg = 1;
18818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return msg;
18828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
18838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
18848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->ext_reg) {
18858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Using external Registrar, but no "
18868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "pending message available");
18878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
18888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
18898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS_UPNP */
18908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (wps->state) {
18928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SEND_M2:
18938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (wps_get_dev_password(wps) < 0)
18948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			msg = wps_build_m2d(wps);
18958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		else
18968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			msg = wps_build_m2(wps);
18978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*op_code = WSC_MSG;
18988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
18998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SEND_M2D:
19008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg = wps_build_m2d(wps);
19018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*op_code = WSC_MSG;
19028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
19038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SEND_M4:
19048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg = wps_build_m4(wps);
19058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*op_code = WSC_MSG;
19068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
19078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SEND_M6:
19088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg = wps_build_m6(wps);
19098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*op_code = WSC_MSG;
19108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
19118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SEND_M8:
19128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg = wps_build_m8(wps);
19138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*op_code = WSC_MSG;
19148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
19158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case RECV_DONE:
19168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg = wps_build_wsc_ack(wps);
19178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*op_code = WSC_ACK;
19188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
19198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SEND_WSC_NACK:
19208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg = wps_build_wsc_nack(wps);
19218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*op_code = WSC_NACK;
19228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
19238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	default:
19248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Unsupported state %d for building "
19258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "a message", wps->state);
19268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		msg = NULL;
19278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
19288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
19298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (*op_code == WSC_MSG && msg) {
19318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Save a copy of the last message for Authenticator derivation
19328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
19338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(wps->last_msg);
19348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->last_msg = wpabuf_dup(msg);
19358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
19368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return msg;
19388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
19398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_process_enrollee_nonce(struct wps_data *wps, const u8 *e_nonce)
19428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
19438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (e_nonce == NULL) {
19448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No Enrollee Nonce received");
19458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
19468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
19478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(wps->nonce_e, e_nonce, WPS_NONCE_LEN);
19498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "WPS: Enrollee Nonce",
19508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    wps->nonce_e, WPS_NONCE_LEN);
19518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
19538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
19548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_process_registrar_nonce(struct wps_data *wps, const u8 *r_nonce)
19578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
19588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (r_nonce == NULL) {
19598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No Registrar Nonce received");
19608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
19618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
19628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (os_memcmp(wps->nonce_r, r_nonce, WPS_NONCE_LEN) != 0) {
19648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Invalid Registrar Nonce received");
19658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
19668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
19678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
19698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
19708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_process_uuid_e(struct wps_data *wps, const u8 *uuid_e)
19738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
19748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (uuid_e == NULL) {
19758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No UUID-E received");
19768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
19778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
19788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(wps->uuid_e, uuid_e, WPS_UUID_LEN);
19808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "WPS: UUID-E", wps->uuid_e, WPS_UUID_LEN);
19818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
19838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
19848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_process_dev_password_id(struct wps_data *wps, const u8 *pw_id)
19878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
19888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pw_id == NULL) {
19898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No Device Password ID received");
19908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
19918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
19928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->dev_pw_id = WPA_GET_BE16(pw_id);
19948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Device Password ID %d", wps->dev_pw_id);
19958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
19978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
19988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_process_e_hash1(struct wps_data *wps, const u8 *e_hash1)
20018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
20028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (e_hash1 == NULL) {
20038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No E-Hash1 received");
20048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
20058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
20068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(wps->peer_hash1, e_hash1, WPS_HASH_LEN);
20088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "WPS: E-Hash1", wps->peer_hash1, WPS_HASH_LEN);
20098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
20118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
20128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_process_e_hash2(struct wps_data *wps, const u8 *e_hash2)
20158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
20168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (e_hash2 == NULL) {
20178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No E-Hash2 received");
20188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
20198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
20208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(wps->peer_hash2, e_hash2, WPS_HASH_LEN);
20228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "WPS: E-Hash2", wps->peer_hash2, WPS_HASH_LEN);
20238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
20258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
20268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_process_e_snonce1(struct wps_data *wps, const u8 *e_snonce1)
20298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
20308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 hash[SHA256_MAC_LEN];
20318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *addr[4];
20328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t len[4];
20338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (e_snonce1 == NULL) {
20358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No E-SNonce1 received");
20368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
20378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
20388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "WPS: E-SNonce1", e_snonce1,
20408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			WPS_SECRET_NONCE_LEN);
20418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* E-Hash1 = HMAC_AuthKey(E-S1 || PSK1 || PK_E || PK_R) */
20438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[0] = e_snonce1;
20448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[0] = WPS_SECRET_NONCE_LEN;
20458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[1] = wps->psk1;
20468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[1] = WPS_PSK_LEN;
20478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[2] = wpabuf_head(wps->dh_pubkey_e);
20488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[2] = wpabuf_len(wps->dh_pubkey_e);
20498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[3] = wpabuf_head(wps->dh_pubkey_r);
20508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[3] = wpabuf_len(wps->dh_pubkey_r);
20518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
20528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (os_memcmp(wps->peer_hash1, hash, WPS_HASH_LEN) != 0) {
20548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: E-Hash1 derived from E-S1 does "
20558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "not match with the pre-committed value");
20568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
20578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_pwd_auth_fail_event(wps->wps, 0, 1);
20588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
20598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
20608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Enrollee proved knowledge of the first "
20628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "half of the device password");
20638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
20658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
20668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_process_e_snonce2(struct wps_data *wps, const u8 *e_snonce2)
20698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
20708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 hash[SHA256_MAC_LEN];
20718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *addr[4];
20728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t len[4];
20738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (e_snonce2 == NULL) {
20758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No E-SNonce2 received");
20768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
20778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
20788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_key(MSG_DEBUG, "WPS: E-SNonce2", e_snonce2,
20808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			WPS_SECRET_NONCE_LEN);
20818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* E-Hash2 = HMAC_AuthKey(E-S2 || PSK2 || PK_E || PK_R) */
20838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[0] = e_snonce2;
20848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[0] = WPS_SECRET_NONCE_LEN;
20858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[1] = wps->psk2;
20868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[1] = WPS_PSK_LEN;
20878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[2] = wpabuf_head(wps->dh_pubkey_e);
20888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[2] = wpabuf_len(wps->dh_pubkey_e);
20898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr[3] = wpabuf_head(wps->dh_pubkey_r);
20908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len[3] = wpabuf_len(wps->dh_pubkey_r);
20918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
20928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (os_memcmp(wps->peer_hash2, hash, WPS_HASH_LEN) != 0) {
20948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: E-Hash2 derived from E-S2 does "
20958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "not match with the pre-committed value");
20968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_registrar_invalidate_pin(wps->wps->registrar, wps->uuid_e);
20978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
20988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_pwd_auth_fail_event(wps->wps, 0, 2);
20998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
21008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
21018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Enrollee proved knowledge of the second "
21038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "half of the device password");
21048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->wps_pin_revealed = 0;
21058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_registrar_unlock_pin(wps->wps->registrar, wps->uuid_e);
21068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2107c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	/*
2108c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 * In case wildcard PIN is used and WPS handshake succeeds in the first
2109c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 * attempt, wps_registrar_unlock_pin() would not free the PIN, so make
2110c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 * sure the PIN gets invalidated here.
2111c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 */
2112c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	wps_registrar_invalidate_pin(wps->wps->registrar, wps->uuid_e);
2113c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
21148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
21158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
21168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_process_mac_addr(struct wps_data *wps, const u8 *mac_addr)
21198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
21208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (mac_addr == NULL) {
21218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No MAC Address received");
21228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
21238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
21248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Enrollee MAC Address " MACSTR,
21268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   MAC2STR(mac_addr));
21278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(wps->mac_addr_e, mac_addr, ETH_ALEN);
21288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(wps->peer_dev.mac_addr, mac_addr, ETH_ALEN);
21298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
21318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
21328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_process_pubkey(struct wps_data *wps, const u8 *pk,
21358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      size_t pk_len)
21368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
21378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pk == NULL || pk_len == 0) {
21388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No Public Key received");
21398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
21408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
21418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS_OOB
21438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->wps->oob_conf.pubkey_hash != NULL) {
21448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		const u8 *addr[1];
21458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		u8 hash[WPS_HASH_LEN];
21468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		addr[0] = pk;
21488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sha256_vector(1, addr, &pk_len, hash);
21498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_memcmp(hash,
21508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      wpabuf_head(wps->wps->oob_conf.pubkey_hash),
21518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      WPS_OOB_PUBKEY_HASH_LEN) != 0) {
21528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_ERROR, "WPS: Public Key hash error");
21538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
21548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
21558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
21568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS_OOB */
21578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(wps->dh_pubkey_e);
21598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->dh_pubkey_e = wpabuf_alloc_copy(pk, pk_len);
21608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->dh_pubkey_e == NULL)
21618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
21628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
21648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
21658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_process_auth_type_flags(struct wps_data *wps, const u8 *auth)
21688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
21698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 auth_types;
21708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (auth == NULL) {
21728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No Authentication Type flags "
21738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "received");
21748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
21758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
21768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	auth_types = WPA_GET_BE16(auth);
21788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Enrollee Authentication Type flags 0x%x",
21808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   auth_types);
21818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->auth_type = wps->wps->auth_types & auth_types;
21828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->auth_type == 0) {
21838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No match in supported "
21848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "authentication types (own 0x%x Enrollee 0x%x)",
21858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   wps->wps->auth_types, auth_types);
21868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef WPS_WORKAROUNDS
21878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
21888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * Some deployed implementations seem to advertise incorrect
21898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * information in this attribute. For example, Linksys WRT350N
21908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * seems to have a byteorder bug that breaks this negotiation.
21918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * In order to interoperate with existing implementations,
21928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * assume that the Enrollee supports everything we do.
21938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
21948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Workaround - assume Enrollee "
21958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "does not advertise supported authentication types "
21968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "correctly");
21978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->auth_type = wps->wps->auth_types;
21988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else /* WPS_WORKAROUNDS */
21998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
22008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* WPS_WORKAROUNDS */
22018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
22028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
22048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
22058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_process_encr_type_flags(struct wps_data *wps, const u8 *encr)
22088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
22098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 encr_types;
22108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (encr == NULL) {
22128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No Encryption Type flags "
22138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "received");
22148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
22158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
22168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	encr_types = WPA_GET_BE16(encr);
22188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Enrollee Encryption Type flags 0x%x",
22208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   encr_types);
22218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->encr_type = wps->wps->encr_types & encr_types;
22228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->encr_type == 0) {
22238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No match in supported "
22248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "encryption types (own 0x%x Enrollee 0x%x)",
22258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   wps->wps->encr_types, encr_types);
22268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef WPS_WORKAROUNDS
22278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
22288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * Some deployed implementations seem to advertise incorrect
22298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * information in this attribute. For example, Linksys WRT350N
22308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * seems to have a byteorder bug that breaks this negotiation.
22318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * In order to interoperate with existing implementations,
22328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * assume that the Enrollee supports everything we do.
22338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
22348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Workaround - assume Enrollee "
22358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "does not advertise supported encryption types "
22368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "correctly");
22378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->encr_type = wps->wps->encr_types;
22388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else /* WPS_WORKAROUNDS */
22398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
22408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* WPS_WORKAROUNDS */
22418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
22428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
22448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
22458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_process_conn_type_flags(struct wps_data *wps, const u8 *conn)
22488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
22498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn == NULL) {
22508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No Connection Type flags "
22518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "received");
22528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
22538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
22548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Enrollee Connection Type flags 0x%x",
22568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   *conn);
22578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
22598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
22608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_process_config_methods(struct wps_data *wps, const u8 *methods)
22638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
22648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 m;
22658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (methods == NULL) {
22678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No Config Methods received");
22688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
22698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
22708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	m = WPA_GET_BE16(methods);
22728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Enrollee Config Methods 0x%x"
22748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "%s%s%s%s%s%s%s%s%s", m,
22758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   m & WPS_CONFIG_USBA ? " [USBA]" : "",
22768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   m & WPS_CONFIG_ETHERNET ? " [Ethernet]" : "",
22778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   m & WPS_CONFIG_LABEL ? " [Label]" : "",
22788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   m & WPS_CONFIG_DISPLAY ? " [Display]" : "",
22798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   m & WPS_CONFIG_EXT_NFC_TOKEN ? " [Ext NFC Token]" : "",
22808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   m & WPS_CONFIG_INT_NFC_TOKEN ? " [Int NFC Token]" : "",
22818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   m & WPS_CONFIG_NFC_INTERFACE ? " [NFC]" : "",
22828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   m & WPS_CONFIG_PUSHBUTTON ? " [PBC]" : "",
22838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   m & WPS_CONFIG_KEYPAD ? " [Keypad]" : "");
22848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!(m & WPS_CONFIG_DISPLAY) && !wps->use_psk_key) {
22868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
22878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * The Enrollee does not have a display so it is unlikely to be
22888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * able to show the passphrase to a user and as such, could
22898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * benefit from receiving PSK to reduce key derivation time.
22908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
22918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Prefer PSK format key due to "
22928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "Enrollee not supporting display");
22938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->use_psk_key = 1;
22948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
22958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
22978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
22988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_process_wps_state(struct wps_data *wps, const u8 *state)
23018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
23028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (state == NULL) {
23038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No Wi-Fi Protected Setup State "
23048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "received");
23058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
23068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
23078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Enrollee Wi-Fi Protected Setup State %d",
23098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   *state);
23108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
23128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
23138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_process_assoc_state(struct wps_data *wps, const u8 *assoc)
23168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
23178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 a;
23188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (assoc == NULL) {
23208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No Association State received");
23218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
23228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
23238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	a = WPA_GET_BE16(assoc);
23258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Enrollee Association State %d", a);
23268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
23288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
23298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_process_config_error(struct wps_data *wps, const u8 *err)
23328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
23338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 e;
23348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (err == NULL) {
23368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No Configuration Error received");
23378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
23388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
23398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	e = WPA_GET_BE16(err);
23418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Enrollee Configuration Error %d", e);
23428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
23448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
23458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_registrar_p2p_dev_addr_match(struct wps_data *wps)
23488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
23498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_P2P
23508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_registrar *reg = wps->wps->registrar;
23518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (is_zero_ether_addr(reg->p2p_dev_addr))
23538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 1; /* no filtering in use */
23548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (os_memcmp(reg->p2p_dev_addr, wps->p2p_dev_addr, ETH_ALEN) != 0) {
23568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No match on P2P Device Address "
23578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "filtering for PBC: expected " MACSTR " was "
23588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   MACSTR " - indicate PBC session overlap",
23598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   MAC2STR(reg->p2p_dev_addr),
23608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   MAC2STR(wps->p2p_dev_addr));
23618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
23628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
23638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_P2P */
23648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 1;
23658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
23668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_registrar_skip_overlap(struct wps_data *wps)
23698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
23708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_P2P
23718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_registrar *reg = wps->wps->registrar;
23728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (is_zero_ether_addr(reg->p2p_dev_addr))
23748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0; /* no specific Enrollee selected */
23758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (os_memcmp(reg->p2p_dev_addr, wps->p2p_dev_addr, ETH_ALEN) == 0) {
23778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Skip PBC overlap due to selected "
23788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "Enrollee match");
23798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 1;
23808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
23818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_P2P */
23828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
23838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
23848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic enum wps_process_res wps_process_m1(struct wps_data *wps,
23878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   struct wps_parse_attr *attr)
23888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
23898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Received M1");
23908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->state != RECV_M1) {
23928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
23938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "receiving M1", wps->state);
23948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_FAILURE;
23958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
23968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_process_uuid_e(wps, attr->uuid_e) ||
23988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_process_mac_addr(wps, attr->mac_addr) ||
23998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_process_enrollee_nonce(wps, attr->enrollee_nonce) ||
24008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_process_pubkey(wps, attr->public_key, attr->public_key_len) ||
24018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_process_auth_type_flags(wps, attr->auth_type_flags) ||
24028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_process_encr_type_flags(wps, attr->encr_type_flags) ||
24038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_process_conn_type_flags(wps, attr->conn_type_flags) ||
24048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_process_config_methods(wps, attr->config_methods) ||
24058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_process_wps_state(wps, attr->wps_state) ||
24068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_process_device_attrs(&wps->peer_dev, attr) ||
24078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_process_rf_bands(&wps->peer_dev, attr->rf_bands) ||
24088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_process_assoc_state(wps, attr->assoc_state) ||
24098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_process_dev_password_id(wps, attr->dev_password_id) ||
24108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_process_config_error(wps, attr->config_error) ||
24118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_process_os_version(&wps->peer_dev, attr->os_version))
24128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_FAILURE;
24138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
24148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->dev_pw_id < 0x10 &&
24158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps->dev_pw_id != DEV_PW_DEFAULT &&
24168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps->dev_pw_id != DEV_PW_USER_SPECIFIED &&
24178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps->dev_pw_id != DEV_PW_MACHINE_SPECIFIED &&
24188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps->dev_pw_id != DEV_PW_REGISTRAR_SPECIFIED &&
24198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    (wps->dev_pw_id != DEV_PW_PUSHBUTTON ||
24208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	     !wps->wps->registrar->pbc)) {
24218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Unsupported Device Password ID %d",
24228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   wps->dev_pw_id);
24238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->state = SEND_M2D;
24248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_CONTINUE;
24258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
24268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
24278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS_OOB
24288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->dev_pw_id >= 0x10 &&
24298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps->dev_pw_id != wps->wps->oob_dev_pw_id) {
24308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: OOB Device Password ID "
24318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "%d mismatch", wps->dev_pw_id);
24328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->state = SEND_M2D;
24338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_CONTINUE;
24348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
24358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS_OOB */
24368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
24378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->dev_pw_id == DEV_PW_PUSHBUTTON) {
24388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if ((wps->wps->registrar->force_pbc_overlap ||
24398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		     wps_registrar_pbc_overlap(wps->wps->registrar,
24408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					       wps->mac_addr_e, wps->uuid_e) ||
24418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		     !wps_registrar_p2p_dev_addr_match(wps)) &&
24428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    !wps_registrar_skip_overlap(wps)) {
24438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "WPS: PBC overlap - deny PBC "
24448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "negotiation");
24458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps->state = SEND_M2D;
24468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps->config_error = WPS_CFG_MULTIPLE_PBC_DETECTED;
24478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps_pbc_overlap_event(wps->wps);
24488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps_fail_event(wps->wps, WPS_M1,
24498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       WPS_CFG_MULTIPLE_PBC_DETECTED,
24508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       WPS_EI_NO_ERROR);
24518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps->wps->registrar->force_pbc_overlap = 1;
24528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return WPS_CONTINUE;
24538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
24548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_registrar_add_pbc_session(wps->wps->registrar,
24558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					      wps->mac_addr_e, wps->uuid_e);
24568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->pbc = 1;
24578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
24588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
24598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef WPS_WORKAROUNDS
24608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
24618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * It looks like Mac OS X 10.6.3 and 10.6.4 do not like Network Key in
24628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * passphrase format. To avoid interop issues, force PSK format to be
24638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * used.
24648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
24658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!wps->use_psk_key &&
24668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps->peer_dev.manufacturer &&
24678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    os_strncmp(wps->peer_dev.manufacturer, "Apple ", 6) == 0 &&
24688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps->peer_dev.model_name &&
24698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    os_strcmp(wps->peer_dev.model_name, "AirPort") == 0) {
24708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Workaround - Force Network Key in "
24718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "PSK format");
24728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->use_psk_key = 1;
24738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
24748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* WPS_WORKAROUNDS */
24758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
24768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->state = SEND_M2;
24778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return WPS_CONTINUE;
24788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
24798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
24808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
24818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic enum wps_process_res wps_process_m3(struct wps_data *wps,
24828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   const struct wpabuf *msg,
24838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   struct wps_parse_attr *attr)
24848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
24858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Received M3");
24868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
24878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->state != RECV_M3) {
24888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
24898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "receiving M3", wps->state);
24908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->state = SEND_WSC_NACK;
24918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_CONTINUE;
24928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
24938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
24948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->pbc && wps->wps->registrar->force_pbc_overlap &&
24958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    !wps_registrar_skip_overlap(wps)) {
24968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Reject negotiation due to PBC "
24978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "session overlap");
24988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->state = SEND_WSC_NACK;
24998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->config_error = WPS_CFG_MULTIPLE_PBC_DETECTED;
25008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_CONTINUE;
25018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
25028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_process_registrar_nonce(wps, attr->registrar_nonce) ||
25048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_process_authenticator(wps, attr->authenticator, msg) ||
25058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_process_e_hash1(wps, attr->e_hash1) ||
25068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_process_e_hash2(wps, attr->e_hash2)) {
25078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->state = SEND_WSC_NACK;
25088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_CONTINUE;
25098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
25108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->state = SEND_M4;
25128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return WPS_CONTINUE;
25138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
25148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic enum wps_process_res wps_process_m5(struct wps_data *wps,
25178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   const struct wpabuf *msg,
25188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   struct wps_parse_attr *attr)
25198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
25208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *decrypted;
25218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_parse_attr eattr;
25228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Received M5");
25248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->state != RECV_M5) {
25268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
25278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "receiving M5", wps->state);
25288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->state = SEND_WSC_NACK;
25298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_CONTINUE;
25308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
25318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->pbc && wps->wps->registrar->force_pbc_overlap &&
25338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    !wps_registrar_skip_overlap(wps)) {
25348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Reject negotiation due to PBC "
25358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "session overlap");
25368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->state = SEND_WSC_NACK;
25378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->config_error = WPS_CFG_MULTIPLE_PBC_DETECTED;
25388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_CONTINUE;
25398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
25408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_process_registrar_nonce(wps, attr->registrar_nonce) ||
25428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_process_authenticator(wps, attr->authenticator, msg)) {
25438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->state = SEND_WSC_NACK;
25448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_CONTINUE;
25458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
25468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings,
25488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					      attr->encr_settings_len);
25498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (decrypted == NULL) {
25508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Failed to decrypted Encrypted "
25518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "Settings attribute");
25528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->state = SEND_WSC_NACK;
25538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_CONTINUE;
25548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
25558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_validate_m5_encr(decrypted, attr->version2 != NULL) < 0) {
25578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(decrypted);
25588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->state = SEND_WSC_NACK;
25598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_CONTINUE;
25608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
25618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
25638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "attribute");
25648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_parse_msg(decrypted, &eattr) < 0 ||
25658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) ||
25668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_process_e_snonce1(wps, eattr.e_snonce1)) {
25678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(decrypted);
25688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->state = SEND_WSC_NACK;
25698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_CONTINUE;
25708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
25718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(decrypted);
25728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->state = SEND_M6;
25748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return WPS_CONTINUE;
25758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
25768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_sta_cred_cb(struct wps_data *wps)
25798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
25808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
25818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Update credential to only include a single authentication and
25828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * encryption type in case the AP configuration includes more than one
25838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * option.
25848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
25858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->cred.auth_type & WPS_AUTH_WPA2PSK)
25868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->cred.auth_type = WPS_AUTH_WPA2PSK;
25878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else if (wps->cred.auth_type & WPS_AUTH_WPAPSK)
25888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->cred.auth_type = WPS_AUTH_WPAPSK;
25898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->cred.encr_type & WPS_ENCR_AES)
25908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->cred.encr_type = WPS_ENCR_AES;
25918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else if (wps->cred.encr_type & WPS_ENCR_TKIP)
25928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->cred.encr_type = WPS_ENCR_TKIP;
25938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Update local configuration based on the "
25948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "AP configuration");
25958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->wps->cred_cb)
25968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->wps->cred_cb(wps->wps->cb_ctx, &wps->cred);
25978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
25988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_cred_update(struct wps_credential *dst,
26018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    struct wps_credential *src)
26028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
26038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(dst->ssid, src->ssid, sizeof(dst->ssid));
26048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dst->ssid_len = src->ssid_len;
26058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dst->auth_type = src->auth_type;
26068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dst->encr_type = src->encr_type;
26078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dst->key_idx = src->key_idx;
26088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(dst->key, src->key, sizeof(dst->key));
26098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dst->key_len = src->key_len;
26108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
26118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_process_ap_settings_r(struct wps_data *wps,
26148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     struct wps_parse_attr *attr)
26158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
26161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpabuf *msg;
26171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
26188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->wps->ap || wps->er)
26198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
26208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* AP Settings Attributes in M7 when Enrollee is an AP */
26228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_process_ap_settings(attr, &wps->cred) < 0)
26238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
26248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_INFO, "WPS: Received old AP configuration from AP");
26268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->new_ap_settings) {
26288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "WPS: Update AP configuration based on "
26298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "new settings");
26308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_cred_update(&wps->cred, wps->new_ap_settings);
26318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
26328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
26338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
26348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * Use the AP PIN only to receive the current AP settings, not
26358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * to reconfigure the AP.
26368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
26378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
26398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * Clear selected registrar here since we do not get to
26408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * WSC_Done in this protocol run.
26418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
26428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_registrar_pin_completed(wps->wps->registrar);
26438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		msg = wps_build_ap_cred(wps);
26451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (msg == NULL)
26461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			return -1;
26471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wps->cred.cred_attr = wpabuf_head(msg);
26481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wps->cred.cred_attr_len = wpabuf_len(msg);
26491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
26508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (wps->ap_settings_cb) {
26518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps->ap_settings_cb(wps->ap_settings_cb_ctx,
26528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					    &wps->cred);
26531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wpabuf_free(msg);
26548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return 1;
26558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
26568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_sta_cred_cb(wps);
26571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
26581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wps->cred.cred_attr = NULL;
26591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wps->cred.cred_attr_len = 0;
26601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpabuf_free(msg);
26611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
26628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 1;
26638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
26648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
26658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic enum wps_process_res wps_process_m7(struct wps_data *wps,
26688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   const struct wpabuf *msg,
26698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   struct wps_parse_attr *attr)
26708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
26718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *decrypted;
26728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_parse_attr eattr;
26738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Received M7");
26758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->state != RECV_M7) {
26778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
26788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "receiving M7", wps->state);
26798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->state = SEND_WSC_NACK;
26808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_CONTINUE;
26818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
26828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->pbc && wps->wps->registrar->force_pbc_overlap &&
26848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    !wps_registrar_skip_overlap(wps)) {
26858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Reject negotiation due to PBC "
26868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "session overlap");
26878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->state = SEND_WSC_NACK;
26888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->config_error = WPS_CFG_MULTIPLE_PBC_DETECTED;
26898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_CONTINUE;
26908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
26918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_process_registrar_nonce(wps, attr->registrar_nonce) ||
26938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_process_authenticator(wps, attr->authenticator, msg)) {
26948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->state = SEND_WSC_NACK;
26958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_CONTINUE;
26968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
26978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings,
26998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					      attr->encr_settings_len);
27008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (decrypted == NULL) {
27018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Failed to decrypt Encrypted "
27028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "Settings attribute");
27038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->state = SEND_WSC_NACK;
27048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_CONTINUE;
27058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
27068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_validate_m7_encr(decrypted, wps->wps->ap || wps->er,
27088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 attr->version2 != NULL) < 0) {
27098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(decrypted);
27108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->state = SEND_WSC_NACK;
27118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_CONTINUE;
27128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
27138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
27158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "attribute");
27168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_parse_msg(decrypted, &eattr) < 0 ||
27178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) ||
27188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_process_e_snonce2(wps, eattr.e_snonce2) ||
27198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_process_ap_settings_r(wps, &eattr)) {
27208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(decrypted);
27218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->state = SEND_WSC_NACK;
27228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_CONTINUE;
27238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
27248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(decrypted);
27268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->state = SEND_M8;
27288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return WPS_CONTINUE;
27298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
27308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,
27338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						const struct wpabuf *msg)
27348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
27358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_parse_attr attr;
27368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	enum wps_process_res ret = WPS_CONTINUE;
27378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Received WSC_MSG");
27398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_parse_msg(msg, &attr) < 0)
27418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_FAILURE;
27428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (attr.msg_type == NULL) {
27448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
27458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->state = SEND_WSC_NACK;
27468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_CONTINUE;
27478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
27488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (*attr.msg_type != WPS_M1 &&
27508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    (attr.registrar_nonce == NULL ||
27518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	     os_memcmp(wps->nonce_r, attr.registrar_nonce,
27528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       WPS_NONCE_LEN != 0))) {
27538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
27548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_FAILURE;
27558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
27568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (*attr.msg_type) {
27588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPS_M1:
27598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (wps_validate_m1(msg) < 0)
27608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return WPS_FAILURE;
27618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS_UPNP
27628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (wps->wps->wps_upnp && attr.mac_addr) {
27638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			/* Remove old pending messages when starting new run */
27648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps_free_pending_msgs(wps->wps->upnp_msgs);
27658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps->wps->upnp_msgs = NULL;
27668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			upnp_wps_device_send_wlan_event(
27688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wps->wps->wps_upnp, attr.mac_addr,
27698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				UPNP_WPS_WLANEVENT_TYPE_EAP, msg);
27708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
27718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS_UPNP */
27728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = wps_process_m1(wps, &attr);
27738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
27748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPS_M3:
27758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (wps_validate_m3(msg) < 0)
27768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return WPS_FAILURE;
27778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = wps_process_m3(wps, msg, &attr);
27788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
27798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps_fail_event(wps->wps, WPS_M3, wps->config_error,
27808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       wps->error_indication);
27818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
27828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPS_M5:
27838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (wps_validate_m5(msg) < 0)
27848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return WPS_FAILURE;
27858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = wps_process_m5(wps, msg, &attr);
27868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
27878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps_fail_event(wps->wps, WPS_M5, wps->config_error,
27888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       wps->error_indication);
27898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
27908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPS_M7:
27918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (wps_validate_m7(msg) < 0)
27928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return WPS_FAILURE;
27938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = wps_process_m7(wps, msg, &attr);
27948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
27958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps_fail_event(wps->wps, WPS_M7, wps->config_error,
27968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       wps->error_indication);
27978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
27988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	default:
27998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Unsupported Message Type %d",
28008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   *attr.msg_type);
28018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_FAILURE;
28028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
28038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret == WPS_CONTINUE) {
28058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Save a copy of the last message for Authenticator derivation
28068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
28078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(wps->last_msg);
28088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->last_msg = wpabuf_dup(msg);
28098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
28108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
28128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
28138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic enum wps_process_res wps_process_wsc_ack(struct wps_data *wps,
28168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						const struct wpabuf *msg)
28178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
28188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_parse_attr attr;
28198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Received WSC_ACK");
28218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_parse_msg(msg, &attr) < 0)
28238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_FAILURE;
28248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (attr.msg_type == NULL) {
28268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
28278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_FAILURE;
28288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
28298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (*attr.msg_type != WPS_WSC_ACK) {
28318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d",
28328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   *attr.msg_type);
28338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_FAILURE;
28348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
28358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS_UPNP
28378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->wps->wps_upnp && wps->ext_reg && wps->state == RECV_M2D_ACK &&
28388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    upnp_wps_subscribers(wps->wps->wps_upnp)) {
28398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (wps->wps->upnp_msgs)
28408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return WPS_CONTINUE;
28418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Wait for response from an "
28428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "external Registrar");
28438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_PENDING;
28448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
28458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS_UPNP */
28468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (attr.registrar_nonce == NULL ||
28488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN != 0))
28498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	{
28508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
28518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_FAILURE;
28528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
28538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (attr.enrollee_nonce == NULL ||
28558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN != 0)) {
28568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
28578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_FAILURE;
28588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
28598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->state == RECV_M2D_ACK) {
28618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS_UPNP
28628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (wps->wps->wps_upnp &&
28638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    upnp_wps_subscribers(wps->wps->wps_upnp)) {
28648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (wps->wps->upnp_msgs)
28658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				return WPS_CONTINUE;
28668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (wps->ext_reg == 0)
28678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wps->ext_reg = 1;
28688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "WPS: Wait for response from an "
28698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "external Registrar");
28708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return WPS_PENDING;
28718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
28728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS_UPNP */
28738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No more registrars available - "
28758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "terminate negotiation");
28768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
28778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return WPS_FAILURE;
28798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
28808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic enum wps_process_res wps_process_wsc_nack(struct wps_data *wps,
28838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						 const struct wpabuf *msg)
28848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
28858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_parse_attr attr;
28868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int old_state;
28878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 config_error;
28888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Received WSC_NACK");
28908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	old_state = wps->state;
28928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->state = SEND_WSC_NACK;
28938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_parse_msg(msg, &attr) < 0)
28958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_FAILURE;
28968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (attr.msg_type == NULL) {
28988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
28998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_FAILURE;
29008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
29018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (*attr.msg_type != WPS_WSC_NACK) {
29038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d",
29048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   *attr.msg_type);
29058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_FAILURE;
29068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
29078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS_UPNP
29098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->wps->wps_upnp && wps->ext_reg) {
29108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Negotiation using external "
29118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "Registrar terminated by the Enrollee");
29128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_FAILURE;
29138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
29148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS_UPNP */
29158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (attr.registrar_nonce == NULL ||
29178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN != 0))
29188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	{
29198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
29208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_FAILURE;
29218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
29228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (attr.enrollee_nonce == NULL ||
29248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN != 0)) {
29258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
29268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_FAILURE;
29278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
29288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (attr.config_error == NULL) {
29308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No Configuration Error attribute "
29318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "in WSC_NACK");
29328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_FAILURE;
29338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
29348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	config_error = WPA_GET_BE16(attr.config_error);
29368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Enrollee terminated negotiation with "
29378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "Configuration Error %d", config_error);
29388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (old_state) {
29408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case RECV_M3:
29418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_fail_event(wps->wps, WPS_M2, config_error,
29428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       wps->error_indication);
29438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
29448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case RECV_M5:
29458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_fail_event(wps->wps, WPS_M4, config_error,
29468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       wps->error_indication);
29478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
29488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case RECV_M7:
29498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_fail_event(wps->wps, WPS_M6, config_error,
29508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       wps->error_indication);
29518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
29528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case RECV_DONE:
29538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_fail_event(wps->wps, WPS_M8, config_error,
29548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       wps->error_indication);
29558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
29568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	default:
29578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
29588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
29598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return WPS_FAILURE;
29618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
29628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic enum wps_process_res wps_process_wsc_done(struct wps_data *wps,
29658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						 const struct wpabuf *msg)
29668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
29678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_parse_attr attr;
29688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Received WSC_Done");
29708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->state != RECV_DONE &&
29728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    (!wps->wps->wps_upnp || !wps->ext_reg)) {
29738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
29748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "receiving WSC_Done", wps->state);
29758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_FAILURE;
29768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
29778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_parse_msg(msg, &attr) < 0)
29798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_FAILURE;
29808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (attr.msg_type == NULL) {
29828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
29838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_FAILURE;
29848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
29858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (*attr.msg_type != WPS_WSC_DONE) {
29878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d",
29888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   *attr.msg_type);
29898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_FAILURE;
29908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
29918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS_UPNP
29938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->wps->wps_upnp && wps->ext_reg) {
29948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Negotiation using external "
29958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "Registrar completed successfully");
29968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_device_store(wps->wps->registrar, &wps->peer_dev,
29978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 wps->uuid_e);
29988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_DONE;
29998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
30008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS_UPNP */
30018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (attr.registrar_nonce == NULL ||
30038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN != 0))
30048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	{
30058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
30068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_FAILURE;
30078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
30088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (attr.enrollee_nonce == NULL ||
30108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN != 0)) {
30118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
30128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_FAILURE;
30138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
30148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Negotiation completed successfully");
30168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_device_store(wps->wps->registrar, &wps->peer_dev,
30178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 wps->uuid_e);
30188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->wps->wps_state == WPS_STATE_NOT_CONFIGURED && wps->new_psk &&
30208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps->wps->ap && !wps->wps->registrar->disable_auto_conf) {
30218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct wps_credential cred;
30228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Moving to Configured state based "
30248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "on first Enrollee connection");
30258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memset(&cred, 0, sizeof(cred));
30278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(cred.ssid, wps->wps->ssid, wps->wps->ssid_len);
30288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		cred.ssid_len = wps->wps->ssid_len;
30298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		cred.auth_type = WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK;
30308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		cred.encr_type = WPS_ENCR_TKIP | WPS_ENCR_AES;
30318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(cred.key, wps->new_psk, wps->new_psk_len);
30328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		cred.key_len = wps->new_psk_len;
30338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->wps->wps_state = WPS_STATE_CONFIGURED;
30358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_ascii_key(MSG_DEBUG,
30368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      "WPS: Generated random passphrase",
30378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      wps->new_psk, wps->new_psk_len);
30388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (wps->wps->cred_cb)
30398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps->wps->cred_cb(wps->wps->cb_ctx, &cred);
30408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(wps->new_psk);
30428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->new_psk = NULL;
30438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
30448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!wps->wps->ap && !wps->er)
30468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_sta_cred_cb(wps);
30478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->new_psk) {
30498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (wps_cb_new_psk(wps->wps->registrar, wps->mac_addr_e,
30508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   wps->new_psk, wps->new_psk_len)) {
30518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "WPS: Failed to configure the "
30528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "new PSK");
30538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
30548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(wps->new_psk);
30558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps->new_psk = NULL;
30568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
30578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_cb_reg_success(wps->wps->registrar, wps->mac_addr_e, wps->uuid_e);
30598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->pbc) {
30618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_registrar_remove_pbc_session(wps->wps->registrar,
30621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt						 wps->uuid_e,
30631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt						 wps->p2p_dev_addr);
30648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_registrar_pbc_completed(wps->wps->registrar);
30658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
30668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_registrar_pin_completed(wps->wps->registrar);
30678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
30688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* TODO: maintain AuthorizedMACs somewhere separately for each ER and
30698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * merge them into APs own list.. */
30708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_success_event(wps->wps);
30728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return WPS_DONE;
30748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
30758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtenum wps_process_res wps_registrar_process_msg(struct wps_data *wps,
30788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					       enum wsc_op_code op_code,
30798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					       const struct wpabuf *msg)
30808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
30818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	enum wps_process_res ret;
30828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Processing received message (len=%lu "
30848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "op_code=%d)",
30858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   (unsigned long) wpabuf_len(msg), op_code);
30868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS_UPNP
30888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->wps->wps_upnp && op_code == WSC_MSG && wps->ext_reg == 1) {
30898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct wps_parse_attr attr;
30908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (wps_parse_msg(msg, &attr) == 0 && attr.msg_type &&
30918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    *attr.msg_type == WPS_M3)
30928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps->ext_reg = 2; /* past M2/M2D phase */
30938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
30948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->ext_reg > 1)
30958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_registrar_free_pending_m2(wps->wps);
30968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->wps->wps_upnp && wps->ext_reg &&
30978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps->wps->upnp_msgs == NULL &&
30988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    (op_code == WSC_MSG || op_code == WSC_Done || op_code == WSC_NACK))
30998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	{
31008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct wps_parse_attr attr;
31018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int type;
31028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (wps_parse_msg(msg, &attr) < 0 || attr.msg_type == NULL)
31038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			type = -1;
31048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		else
31058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			type = *attr.msg_type;
31068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Sending received message (type %d)"
31078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   " to external Registrar for processing", type);
31088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		upnp_wps_device_send_wlan_event(wps->wps->wps_upnp,
31098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						wps->mac_addr_e,
31108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						UPNP_WPS_WLANEVENT_TYPE_EAP,
31118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						msg);
31128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (op_code == WSC_MSG)
31138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return WPS_PENDING;
31148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (wps->wps->wps_upnp && wps->ext_reg && op_code == WSC_MSG) {
31158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Skip internal processing - using "
31168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "external Registrar");
31178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_CONTINUE;
31188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
31198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS_UPNP */
31208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (op_code) {
31228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WSC_MSG:
31238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return wps_process_wsc_msg(wps, msg);
31248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WSC_ACK:
31258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (wps_validate_wsc_ack(msg) < 0)
31268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return WPS_FAILURE;
31278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return wps_process_wsc_ack(wps, msg);
31288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WSC_NACK:
31298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (wps_validate_wsc_nack(msg) < 0)
31308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return WPS_FAILURE;
31318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return wps_process_wsc_nack(wps, msg);
31328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WSC_Done:
31338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (wps_validate_wsc_done(msg) < 0)
31348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return WPS_FAILURE;
31358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = wps_process_wsc_done(wps, msg);
31368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret == WPS_FAILURE) {
31378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps->state = SEND_WSC_NACK;
31388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps_fail_event(wps->wps, WPS_WSC_DONE,
31398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       wps->config_error,
31408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       wps->error_indication);
31418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
31428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return ret;
31438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	default:
31448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Unsupported op_code %d", op_code);
31458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return WPS_FAILURE;
31468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
31478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
31488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wps_registrar_update_ie(struct wps_registrar *reg)
31518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
31528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return wps_set_ie(reg);
31538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
31548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_registrar_set_selected_timeout(void *eloop_ctx,
31578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					       void *timeout_ctx)
31588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
31598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_registrar *reg = eloop_ctx;
31608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Selected Registrar timeout - "
31628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "unselect internal Registrar");
31638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	reg->selected_registrar = 0;
31648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	reg->pbc = 0;
31658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_registrar_selected_registrar_changed(reg);
31668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
31678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS_UPNP
31708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_registrar_sel_reg_add(struct wps_registrar *reg,
31718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      struct subscription *s)
31728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
31738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i, j;
31748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: External Registrar selected (dev_pw_id=%d "
31758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "config_methods=0x%x)",
31768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   s->dev_password_id, s->config_methods);
31778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	reg->sel_reg_union = 1;
31788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (reg->sel_reg_dev_password_id_override != DEV_PW_PUSHBUTTON)
31798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		reg->sel_reg_dev_password_id_override = s->dev_password_id;
31808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (reg->sel_reg_config_methods_override == -1)
31818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		reg->sel_reg_config_methods_override = 0;
31828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	reg->sel_reg_config_methods_override |= s->config_methods;
31838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < WPS_MAX_AUTHORIZED_MACS; i++)
31848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (is_zero_ether_addr(reg->authorized_macs_union[i]))
31858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
31868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (j = 0; i < WPS_MAX_AUTHORIZED_MACS && j < WPS_MAX_AUTHORIZED_MACS;
31878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	     j++) {
31888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (is_zero_ether_addr(s->authorized_macs[j]))
31898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
31908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Add authorized MAC into union: "
31918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   MACSTR, MAC2STR(s->authorized_macs[j]));
31928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(reg->authorized_macs_union[i],
31938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  s->authorized_macs[j], ETH_ALEN);
31948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		i++;
31958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
31968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "WPS: Authorized MACs union",
31978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    (u8 *) reg->authorized_macs_union,
31988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    sizeof(reg->authorized_macs_union));
31998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
32008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS_UPNP */
32018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_registrar_sel_reg_union(struct wps_registrar *reg)
32048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
32058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS_UPNP
32068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct subscription *s;
32078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (reg->wps->wps_upnp == NULL)
32098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
32108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_for_each(s, &reg->wps->wps_upnp->subscriptions,
32128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 struct subscription, list) {
32138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct subscr_addr *sa;
32148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sa = dl_list_first(&s->addr_list, struct subscr_addr, list);
32158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (sa) {
32168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "WPS: External Registrar %s:%d",
32178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   inet_ntoa(sa->saddr.sin_addr),
32188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   ntohs(sa->saddr.sin_port));
32198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
32208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (s->selected_registrar)
32218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps_registrar_sel_reg_add(reg, s);
32228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		else
32238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "WPS: External Registrar not "
32248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "selected");
32258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
32268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS_UPNP */
32278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
32288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
32318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wps_registrar_selected_registrar_changed - SetSelectedRegistrar change
32328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @reg: Registrar data from wps_registrar_init()
32338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
32348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This function is called when selected registrar state changes, e.g., when an
32358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * AP receives a SetSelectedRegistrar UPnP message.
32368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
32378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wps_registrar_selected_registrar_changed(struct wps_registrar *reg)
32388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
32398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS: Selected registrar information changed");
32408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	reg->sel_reg_union = reg->selected_registrar;
32428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	reg->sel_reg_dev_password_id_override = -1;
32438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	reg->sel_reg_config_methods_override = -1;
32448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(reg->authorized_macs_union, reg->authorized_macs,
32458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  WPS_MAX_AUTHORIZED_MACS * ETH_ALEN);
32468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "WPS: Authorized MACs union (start with own)",
32478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    (u8 *) reg->authorized_macs_union,
32488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    sizeof(reg->authorized_macs_union));
32498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (reg->selected_registrar) {
32508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		u16 methods;
32518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON;
32538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS2
32548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON |
32558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     WPS_CONFIG_PHY_PUSHBUTTON);
32568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS2 */
32578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (reg->pbc) {
32588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			reg->sel_reg_dev_password_id_override =
32598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				DEV_PW_PUSHBUTTON;
32608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps_set_pushbutton(&methods, reg->wps->config_methods);
32618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
32628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Internal Registrar selected "
32638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(pbc=%d)", reg->pbc);
32648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		reg->sel_reg_config_methods_override = methods;
32658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else
32668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Internal Registrar not selected");
32678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_registrar_sel_reg_union(reg);
32698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_set_ie(reg);
32718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_cb_set_sel_reg(reg);
32728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
32738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wps_registrar_get_info(struct wps_registrar *reg, const u8 *addr,
32768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   char *buf, size_t buflen)
32778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
32788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_registrar_device *d;
32798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int len = 0, ret;
32808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char uuid[40];
32818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char devtype[WPS_DEV_TYPE_BUFSIZE];
32828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	d = wps_device_get(reg, addr);
32848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (d == NULL)
32858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
32868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (uuid_bin2str(d->uuid, uuid, sizeof(uuid)))
32878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
32888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = os_snprintf(buf + len, buflen - len,
32908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  "wpsUuid=%s\n"
32918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  "wpsPrimaryDeviceType=%s\n"
32928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  "wpsDeviceName=%s\n"
32938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  "wpsManufacturer=%s\n"
32948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  "wpsModelName=%s\n"
32958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  "wpsModelNumber=%s\n"
32968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  "wpsSerialNumber=%s\n",
32978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  uuid,
32988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  wps_dev_type_bin2str(d->dev.pri_dev_type, devtype,
32998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					       sizeof(devtype)),
33008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  d->dev.device_name ? d->dev.device_name : "",
33018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  d->dev.manufacturer ? d->dev.manufacturer : "",
33028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  d->dev.model_name ? d->dev.model_name : "",
33038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  d->dev.model_number ? d->dev.model_number : "",
33048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  d->dev.serial_number ? d->dev.serial_number : "");
33058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret < 0 || (size_t) ret >= buflen - len)
33068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return len;
33078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len += ret;
33088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return len;
33108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
33118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wps_registrar_config_ap(struct wps_registrar *reg,
33148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    struct wps_credential *cred)
33158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
33168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS2
33178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	printf("encr_type=0x%x\n", cred->encr_type);
33188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!(cred->encr_type & (WPS_ENCR_NONE | WPS_ENCR_TKIP |
33198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 WPS_ENCR_AES))) {
33208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (cred->encr_type & WPS_ENCR_WEP) {
33218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "WPS: Reject new AP settings "
33228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "due to WEP configuration");
33238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
33248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
33258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "WPS: Reject new AP settings due to "
33278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "invalid encr_type 0x%x", cred->encr_type);
33288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
33298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
33308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if ((cred->encr_type & (WPS_ENCR_TKIP | WPS_ENCR_AES)) ==
33328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    WPS_ENCR_TKIP) {
33338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Upgrade encr_type TKIP -> "
33348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "TKIP+AES");
33358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		cred->encr_type |= WPS_ENCR_AES;
33368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
33378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if ((cred->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) ==
33398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    WPS_AUTH_WPAPSK) {
33408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS: Upgrade auth_type WPAPSK -> "
33418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "WPAPSK+WPA2PSK");
33428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		cred->auth_type |= WPS_AUTH_WPA2PSK;
33438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
33448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS2 */
33458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (reg->wps->cred_cb)
33478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return reg->wps->cred_cb(reg->wps->cb_ctx, cred);
33488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
33508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3351