18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Wi-Fi Protected Setup - External Registrar
31e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt * Copyright (c) 2009-2013, 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 "includes.h"
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h"
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "base64.h"
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "uuid.h"
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eloop.h"
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "httpread.h"
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "http_client.h"
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "http_server.h"
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "upnp_xml.h"
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "wps_i.h"
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "wps_upnp.h"
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "wps_upnp_i.h"
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "wps_er.h"
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_deinit_finish(void *eloop_data, void *user_ctx);
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_ap_timeout(void *eloop_data, void *user_ctx);
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_sta_timeout(void *eloop_data, void *user_ctx);
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_ap_process(struct wps_er_ap *ap, struct wpabuf *msg);
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_er_send_get_device_info(struct wps_er_ap *ap,
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       void (*m1_handler)(struct wps_er_ap *ap,
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt							  struct wpabuf *m1));
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_sta_event(struct wps_context *wps, struct wps_er_sta *sta,
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     enum wps_event event)
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wps_event_data data;
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_event_er_enrollee *ev = &data.enrollee;
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->event_cb == NULL)
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&data, 0, sizeof(data));
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ev->uuid = sta->uuid;
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ev->mac_addr = sta->addr;
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ev->m1_received = sta->m1_received;
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ev->config_methods = sta->config_methods;
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ev->dev_passwd_id = sta->dev_passwd_id;
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ev->pri_dev_type = sta->pri_dev_type;
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ev->dev_name = sta->dev_name;
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ev->manufacturer = sta->manufacturer;
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ev->model_name = sta->model_name;
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ev->model_number = sta->model_number;
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ev->serial_number = sta->serial_number;
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->event_cb(wps->cb_ctx, event, &data);
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wps_er_sta * wps_er_sta_get(struct wps_er_ap *ap, const u8 *addr,
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  const u8 *uuid)
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_er_sta *sta;
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_for_each(sta, &ap->sta, struct wps_er_sta, list) {
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if ((addr == NULL ||
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		     os_memcmp(sta->addr, addr, ETH_ALEN) == 0) &&
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    (uuid == NULL ||
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		     os_memcmp(uuid, sta->uuid, WPS_UUID_LEN) == 0))
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return sta;
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_sta_free(struct wps_er_sta *sta)
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_er_sta_event(sta->ap->er->wps, sta, WPS_EV_ER_ENROLLEE_REMOVE);
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sta->wps)
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_deinit(sta->wps);
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(sta->manufacturer);
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(sta->model_name);
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(sta->model_number);
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(sta->serial_number);
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(sta->dev_name);
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	http_client_free(sta->http);
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_cancel_timeout(wps_er_sta_timeout, sta, NULL);
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(sta->cred);
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(sta);
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_sta_remove_all(struct wps_er_ap *ap)
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_er_sta *prev, *sta;
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_for_each_safe(sta, prev, &ap->sta, struct wps_er_sta, list)
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_er_sta_free(sta);
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wps_er_ap * wps_er_ap_get(struct wps_er *er,
1001e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt					struct in_addr *addr, const u8 *uuid,
1011e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt					const u8 *mac_addr)
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_er_ap *ap;
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if ((addr == NULL || ap->addr.s_addr == addr->s_addr) &&
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    (uuid == NULL ||
1071e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt		     os_memcmp(uuid, ap->uuid, WPS_UUID_LEN) == 0) &&
1081e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt		    (mac_addr == NULL ||
1091e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt		     os_memcmp(mac_addr, ap->mac_addr, ETH_ALEN) == 0))
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return ap;
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wps_er_ap * wps_er_ap_get_id(struct wps_er *er, unsigned int id)
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_er_ap *ap;
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ap->id == id)
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return ap;
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_ap_event(struct wps_context *wps, struct wps_er_ap *ap,
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    enum wps_event event)
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wps_event_data data;
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_event_er_ap *evap = &data.ap;
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps->event_cb == NULL)
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&data, 0, sizeof(data));
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	evap->uuid = ap->uuid;
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	evap->friendly_name = ap->friendly_name;
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	evap->manufacturer = ap->manufacturer;
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	evap->manufacturer_url = ap->manufacturer_url;
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	evap->model_description = ap->model_description;
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	evap->model_name = ap->model_name;
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	evap->model_number = ap->model_number;
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	evap->model_url = ap->model_url;
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	evap->serial_number = ap->serial_number;
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	evap->upc = ap->upc;
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	evap->pri_dev_type = ap->pri_dev_type;
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	evap->wps_state = ap->wps_state;
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	evap->mac_addr = ap->mac_addr;
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps->event_cb(wps->cb_ctx, event, &data);
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_ap_free(struct wps_er_ap *ap)
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	http_client_free(ap->http);
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->http = NULL;
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(ap->location);
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(ap->friendly_name);
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(ap->manufacturer);
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(ap->manufacturer_url);
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(ap->model_description);
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(ap->model_name);
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(ap->model_number);
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(ap->model_url);
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(ap->serial_number);
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(ap->udn);
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(ap->upc);
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(ap->scpd_url);
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(ap->control_url);
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(ap->event_sub_url);
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(ap->ap_settings);
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(ap);
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_ap_unsubscribed(struct wps_er *er, struct wps_er_ap *ap)
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS ER: Unsubscribed from AP %s (%s)",
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   inet_ntoa(ap->addr), ap->location);
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_del(&ap->list);
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_er_ap_free(ap);
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
188fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (er->deinitializing && dl_list_empty(&er->ap_unsubscribing))
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_er_deinit_finish(er, NULL);
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_http_unsubscribe_cb(void *ctx, struct http_client *c,
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       enum http_client_event event)
1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_er_ap *ap = ctx;
1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (event) {
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case HTTP_CLIENT_OK:
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: Unsubscribed from events");
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ap->subscribed = 0;
2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case HTTP_CLIENT_FAILED:
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case HTTP_CLIENT_INVALID_REPLY:
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case HTTP_CLIENT_TIMEOUT:
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: Failed to unsubscribe from "
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "events");
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	http_client_free(ap->http);
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->http = NULL;
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Need to get rid of the AP entry regardless of whether we managed to
2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * unsubscribe cleanly or not.
2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_er_ap_unsubscribed(ap->er, ap);
2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_ap_unsubscribe(struct wps_er *er, struct wps_er_ap *ap)
2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *req;
2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct sockaddr_in dst;
2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *url, *path;
2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char sid[100];
2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap->event_sub_url == NULL) {
2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: No eventSubURL - cannot "
2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "subscribe");
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fail;
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap->http) {
2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP request - cannot "
2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "send subscribe request");
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fail;
2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	url = http_client_url_parse(ap->event_sub_url, &dst, &path);
2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (url == NULL) {
2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse eventSubURL");
2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fail;
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	req = wpabuf_alloc(os_strlen(ap->event_sub_url) + 1000);
2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (req == NULL) {
2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(url);
2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fail;
2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	uuid_bin2str(ap->sid, sid, sizeof(sid));
2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_printf(req,
2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      "UNSUBSCRIBE %s HTTP/1.1\r\n"
2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      "HOST: %s:%d\r\n"
2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      "SID: uuid:%s\r\n"
2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      "\r\n",
2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      path, inet_ntoa(dst.sin_addr), ntohs(dst.sin_port), sid);
2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(url);
2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Unsubscription request",
2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  wpabuf_head(req), wpabuf_len(req));
2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->http = http_client_addr(&dst, req, 1000,
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    wps_er_http_unsubscribe_cb, ap);
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap->http == NULL) {
2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(req);
2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fail;
2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return;
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtfail:
2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Need to get rid of the AP entry even when we fail to unsubscribe
2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * cleanly.
2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_er_ap_unsubscribed(ap->er, ap);
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wps_er_ap_settings * wps_er_ap_get_settings(struct wps_er *er,
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt							  const u8 *uuid)
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_er_ap_settings *s;
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_for_each(s, &er->ap_settings, struct wps_er_ap_settings, list)
2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_memcmp(uuid, s->uuid, WPS_UUID_LEN) == 0)
2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return s;
2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint wps_er_ap_cache_settings(struct wps_er *er, struct in_addr *addr)
2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_er_ap *ap;
2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_er_ap_settings *settings;
2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2941e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt	ap = wps_er_ap_get(er, addr, NULL, NULL);
2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap == NULL || ap->ap_settings == NULL)
2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	settings = wps_er_ap_get_settings(er, ap->uuid);
2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!settings) {
3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		settings = os_zalloc(sizeof(*settings));
3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (settings == NULL)
3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(settings->uuid, ap->uuid, WPS_UUID_LEN);
3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		dl_list_add(&er->ap_settings, &settings->list);
3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(&settings->ap_settings, ap->ap_settings,
3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  sizeof(struct wps_credential));
3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_er_ap_use_cached_settings(struct wps_er *er,
3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 struct wps_er_ap *ap)
3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_er_ap_settings *s;
3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap->ap_settings)
3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	s = wps_er_ap_get_settings(ap->er, ap->uuid);
3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!s)
3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
325d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt	ap->ap_settings = os_memdup(&s->ap_settings, sizeof(*ap->ap_settings));
3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap->ap_settings == NULL)
3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS ER: Use cached AP settings");
3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_ap_remove_entry(struct wps_er *er, struct wps_er_ap *ap)
3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS ER: Removing AP entry for %s (%s)",
3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   inet_ntoa(ap->addr), ap->location);
3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_cancel_timeout(wps_er_ap_timeout, er, ap);
3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_er_sta_remove_all(ap);
3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_er_ap_event(er->wps, ap, WPS_EV_ER_AP_REMOVE);
3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	http_client_free(ap->http);
3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->http = NULL;
3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap->wps) {
3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_deinit(ap->wps);
3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ap->wps = NULL;
3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_del(&ap->list);
3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap->subscribed) {
3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		dl_list_add(&er->ap_unsubscribing, &ap->list);
3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_er_ap_unsubscribe(er, ap);
3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else
3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_er_ap_free(ap);
3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_ap_timeout(void *eloop_data, void *user_ctx)
3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_er *er = eloop_data;
3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_er_ap *ap = user_ctx;
3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS ER: AP advertisement timed out");
3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_er_ap_remove_entry(er, ap);
3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_er_get_sid(struct wps_er_ap *ap, char *sid)
3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *pos;
3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char txt[100];
3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!sid) {
3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: No SID received from %s (%s)",
3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   inet_ntoa(ap->addr), ap->location);
3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = os_strstr(sid, "uuid:");
3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!pos) {
3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: Invalid SID received from "
3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "%s (%s): '%s'", inet_ntoa(ap->addr), ap->location,
3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   sid);
3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += 5;
3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (uuid_str2bin(pos, ap->sid) < 0) {
3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: Invalid SID received from "
3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "%s (%s): '%s'", inet_ntoa(ap->addr), ap->location,
3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   sid);
3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	uuid_bin2str(ap->sid, txt, sizeof(txt));
3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS ER: SID for subscription with %s (%s): %s",
3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   inet_ntoa(ap->addr), ap->location, txt);
3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_http_subscribe_cb(void *ctx, struct http_client *c,
4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     enum http_client_event event)
4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_er_ap *ap = ctx;
4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (event) {
4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case HTTP_CLIENT_OK:
4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: Subscribed to events");
4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ap->subscribed = 1;
4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_er_get_sid(ap, http_client_get_hdr_line(c, "SID"));
4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_er_ap_use_cached_settings(ap->er, ap);
4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_er_ap_event(ap->er->wps, ap, WPS_EV_ER_AP_ADD);
4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case HTTP_CLIENT_FAILED:
4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case HTTP_CLIENT_INVALID_REPLY:
4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case HTTP_CLIENT_TIMEOUT:
4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: Failed to subscribe to events");
4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	http_client_free(ap->http);
4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->http = NULL;
4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_subscribe(struct wps_er_ap *ap)
4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *req;
4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct sockaddr_in dst;
4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *url, *path;
4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap->event_sub_url == NULL) {
4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: No eventSubURL - cannot "
4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "subscribe");
4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap->http) {
4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP request - cannot "
4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "send subscribe request");
4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	url = http_client_url_parse(ap->event_sub_url, &dst, &path);
4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (url == NULL) {
4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse eventSubURL");
4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	req = wpabuf_alloc(os_strlen(ap->event_sub_url) + 1000);
4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (req == NULL) {
4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(url);
4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_printf(req,
4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      "SUBSCRIBE %s HTTP/1.1\r\n"
4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      "HOST: %s:%d\r\n"
4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      "CALLBACK: <http://%s:%d/event/%u/%u>\r\n"
4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      "NT: upnp:event\r\n"
4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      "TIMEOUT: Second-%d\r\n"
4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      "\r\n",
4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      path, inet_ntoa(dst.sin_addr), ntohs(dst.sin_port),
4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      ap->er->ip_addr_text, ap->er->http_port,
4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      ap->er->event_id, ap->id, 1800);
4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(url);
4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Subscription request",
4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  wpabuf_head(req), wpabuf_len(req));
4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->http = http_client_addr(&dst, req, 1000, wps_er_http_subscribe_cb,
4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    ap);
4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap->http == NULL)
4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(req);
4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_ap_get_m1(struct wps_er_ap *ap, struct wpabuf *m1)
4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_parse_attr attr;
4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_parse_msg(m1, &attr) < 0) {
4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse M1");
4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (attr.primary_dev_type)
4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(ap->pri_dev_type, attr.primary_dev_type, 8);
4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (attr.wps_state)
4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ap->wps_state = *attr.wps_state;
4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (attr.mac_addr)
4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(ap->mac_addr, attr.mac_addr, ETH_ALEN);
4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_er_subscribe(ap);
4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_get_device_info(struct wps_er_ap *ap)
4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_er_send_get_device_info(ap, wps_er_ap_get_m1);
4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic const char * wps_er_find_wfadevice(const char *data)
5001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
5011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	const char *tag, *tagname, *end;
5021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	char *val;
5031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int found = 0;
5041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
5051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	while (!found) {
5061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		/* Find next <device> */
5071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		for (;;) {
5081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			if (xml_next_tag(data, &tag, &tagname, &end))
5091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				return NULL;
5101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			data = end;
5111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			if (!os_strncasecmp(tagname, "device", 6) &&
5121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			    *tag != '/' &&
5131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			    (tagname[6] == '>' || !isgraph(tagname[6]))) {
5141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				break;
5151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			}
5161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
5171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
5181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		/* Check whether deviceType is WFADevice */
5191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		val = xml_get_first_item(data, "deviceType");
5201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (val == NULL)
5211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			return NULL;
5221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: Found deviceType '%s'", val);
5231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		found = os_strcasecmp(val, "urn:schemas-wifialliance-org:"
5241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				      "device:WFADevice:1") == 0;
5251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		os_free(val);
5261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
5271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
5281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return data;
5291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
5301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
5311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
5328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_parse_device_description(struct wps_er_ap *ap,
5338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					    struct wpabuf *reply)
5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Note: reply includes null termination after the buffer data */
5361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	const char *tmp, *data = wpabuf_head(reply);
5378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *pos;
5388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Device info",
5408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  wpabuf_head(reply), wpabuf_len(reply));
5418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	/*
5431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 * The root device description may include multiple devices, so first
5441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 * find the beginning of the WFADevice description to allow the
5451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 * simplistic parser to pick the correct entries.
5461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 */
5471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	tmp = wps_er_find_wfadevice(data);
5481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (tmp == NULL) {
5491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: WFADevice:1 device not found - "
5501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "trying to parse invalid data");
5511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	} else
5521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		data = tmp;
5531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
5548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->friendly_name = xml_get_first_item(data, "friendlyName");
5558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS ER: friendlyName='%s'", ap->friendly_name);
5568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->manufacturer = xml_get_first_item(data, "manufacturer");
5588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS ER: manufacturer='%s'", ap->manufacturer);
5598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->manufacturer_url = xml_get_first_item(data, "manufacturerURL");
5618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS ER: manufacturerURL='%s'",
5628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   ap->manufacturer_url);
5638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->model_description = xml_get_first_item(data, "modelDescription");
5658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS ER: modelDescription='%s'",
5668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   ap->model_description);
5678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->model_name = xml_get_first_item(data, "modelName");
5698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS ER: modelName='%s'", ap->model_name);
5708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->model_number = xml_get_first_item(data, "modelNumber");
5728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS ER: modelNumber='%s'", ap->model_number);
5738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->model_url = xml_get_first_item(data, "modelURL");
5758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS ER: modelURL='%s'", ap->model_url);
5768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->serial_number = xml_get_first_item(data, "serialNumber");
5788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS ER: serialNumber='%s'", ap->serial_number);
5798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->udn = xml_get_first_item(data, "UDN");
58109f57babfc1e4473db20ced4f58a4c9f082c8ed8Dmitry Shmidt	if (ap->udn) {
58209f57babfc1e4473db20ced4f58a4c9f082c8ed8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: UDN='%s'", ap->udn);
58309f57babfc1e4473db20ced4f58a4c9f082c8ed8Dmitry Shmidt		pos = os_strstr(ap->udn, "uuid:");
58409f57babfc1e4473db20ced4f58a4c9f082c8ed8Dmitry Shmidt		if (pos) {
58509f57babfc1e4473db20ced4f58a4c9f082c8ed8Dmitry Shmidt			pos += 5;
58609f57babfc1e4473db20ced4f58a4c9f082c8ed8Dmitry Shmidt			if (uuid_str2bin(pos, ap->uuid) < 0)
58709f57babfc1e4473db20ced4f58a4c9f082c8ed8Dmitry Shmidt				wpa_printf(MSG_DEBUG,
58809f57babfc1e4473db20ced4f58a4c9f082c8ed8Dmitry Shmidt					   "WPS ER: Invalid UUID in UDN");
58909f57babfc1e4473db20ced4f58a4c9f082c8ed8Dmitry Shmidt		}
5908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->upc = xml_get_first_item(data, "UPC");
5938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS ER: UPC='%s'", ap->upc);
5948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->scpd_url = http_link_update(
5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		xml_get_first_item(data, "SCPDURL"), ap->location);
5978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS ER: SCPDURL='%s'", ap->scpd_url);
5988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->control_url = http_link_update(
6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		xml_get_first_item(data, "controlURL"), ap->location);
6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS ER: controlURL='%s'", ap->control_url);
6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->event_sub_url = http_link_update(
6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		xml_get_first_item(data, "eventSubURL"), ap->location);
6058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS ER: eventSubURL='%s'", ap->event_sub_url);
6068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_http_dev_desc_cb(void *ctx, struct http_client *c,
6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    enum http_client_event event)
6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_er_ap *ap = ctx;
6138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *reply;
6148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ok = 0;
6158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (event) {
6178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case HTTP_CLIENT_OK:
6188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		reply = http_client_get_body(c);
6198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (reply == NULL)
6208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
6218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_er_parse_device_description(ap, reply);
6228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ok = 1;
6238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
6248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case HTTP_CLIENT_FAILED:
6258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case HTTP_CLIENT_INVALID_REPLY:
6268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case HTTP_CLIENT_TIMEOUT:
6278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: Failed to fetch device info");
6288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
6298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	http_client_free(ap->http);
6318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->http = NULL;
6328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ok)
6338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_er_get_device_info(ap);
6348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wps_er_ap_add(struct wps_er *er, const u8 *uuid, struct in_addr *addr,
6388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   const char *location, int max_age)
6398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_er_ap *ap;
6418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6421e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt	ap = wps_er_ap_get(er, addr, uuid, NULL);
6438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap) {
6448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Update advertisement timeout */
6458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eloop_cancel_timeout(wps_er_ap_timeout, er, ap);
6468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eloop_register_timeout(max_age, 0, wps_er_ap_timeout, er, ap);
6478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
6488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap = os_zalloc(sizeof(*ap));
6518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap == NULL)
6528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
6538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_init(&ap->sta);
6548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->er = er;
6558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->id = ++er->next_ap_id;
6568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->location = os_strdup(location);
6578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap->location == NULL) {
6588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(ap);
6598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
6608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_add(&er->ap, &ap->list);
6628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->addr.s_addr = addr->s_addr;
6648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(ap->uuid, uuid, WPS_UUID_LEN);
6658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_register_timeout(max_age, 0, wps_er_ap_timeout, er, ap);
6668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS ER: Added AP entry for %s (%s)",
6688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   inet_ntoa(ap->addr), ap->location);
6698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Fetch device description */
6718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->http = http_client_url(ap->location, NULL, 10000,
6728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   wps_er_http_dev_desc_cb, ap);
6738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wps_er_ap_remove(struct wps_er *er, struct in_addr *addr)
6778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_er_ap *ap;
6798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
6808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ap->addr.s_addr == addr->s_addr) {
6818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps_er_ap_remove_entry(er, ap);
6828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return;
6838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
6848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_ap_remove_all(struct wps_er *er)
6898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_er_ap *prev, *ap;
6918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_er_ap_settings *prev_s, *s;
6928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_for_each_safe(ap, prev, &er->ap, struct wps_er_ap, list)
6938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_er_ap_remove_entry(er, ap);
6948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_for_each_safe(s, prev_s, &er->ap_settings,
6958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      struct wps_er_ap_settings, list)
6968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(s);
6978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void http_put_date(struct wpabuf *buf)
7018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_str(buf, "Date: ");
7038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	format_date(buf);
7048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_str(buf, "\r\n");
7058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_http_resp_not_found(struct http_request *req)
7098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *buf;
7118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf = wpabuf_alloc(200);
7128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (buf == NULL) {
7138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		http_request_deinit(req);
7148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
7158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_str(buf,
7188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       "HTTP/1.1 404 Not Found\r\n"
7198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       "Server: unspecified, UPnP/1.0, unspecified\r\n"
7208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       "Connection: close\r\n");
7218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	http_put_date(buf);
7228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_str(buf, "\r\n");
7238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	http_request_send_and_deinit(req, buf);
7248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_http_resp_ok(struct http_request *req)
7288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *buf;
7308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf = wpabuf_alloc(200);
7318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (buf == NULL) {
7328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		http_request_deinit(req);
7338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
7348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_str(buf,
7378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       "HTTP/1.1 200 OK\r\n"
7388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       "Server: unspecified, UPnP/1.0, unspecified\r\n"
7398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       "Connection: close\r\n"
7408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       "Content-Length: 0\r\n");
7418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	http_put_date(buf);
7428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_str(buf, "\r\n");
7438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	http_request_send_and_deinit(req, buf);
7448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_sta_timeout(void *eloop_data, void *user_ctx)
7488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_er_sta *sta = eloop_data;
7508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS ER: STA entry timed out");
7518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_del(&sta->list);
7528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_er_sta_free(sta);
7538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wps_er_sta * wps_er_add_sta_data(struct wps_er_ap *ap,
7578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					       const u8 *addr,
7588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					       struct wps_parse_attr *attr,
7598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					       int probe_req)
7608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_er_sta *sta = wps_er_sta_get(ap, addr, NULL);
7628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int new_sta = 0;
7638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int m1;
7648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	m1 = !probe_req && attr->msg_type && *attr->msg_type == WPS_M1;
7668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sta == NULL) {
7688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
7698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * Only allow new STA entry to be added based on Probe Request
7708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * or M1. This will filter out bogus events and anything that
7718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * may have been ongoing at the time ER subscribed for events.
7728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
7738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!probe_req && !m1)
7748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return NULL;
7758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sta = os_zalloc(sizeof(*sta));
7778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (sta == NULL)
7788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return NULL;
7798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(sta->addr, addr, ETH_ALEN);
7808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sta->ap = ap;
7818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		dl_list_add(&ap->sta, &sta->list);
7828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		new_sta = 1;
7838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (m1)
7868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sta->m1_received = 1;
7878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (attr->config_methods && (!probe_req || !sta->m1_received))
7898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sta->config_methods = WPA_GET_BE16(attr->config_methods);
7908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (attr->uuid_e && (!probe_req || !sta->m1_received))
7918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(sta->uuid, attr->uuid_e, WPS_UUID_LEN);
7928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (attr->primary_dev_type && (!probe_req || !sta->m1_received))
7938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(sta->pri_dev_type, attr->primary_dev_type, 8);
7948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (attr->dev_password_id && (!probe_req || !sta->m1_received))
7958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sta->dev_passwd_id = WPA_GET_BE16(attr->dev_password_id);
7968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (attr->manufacturer) {
7988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(sta->manufacturer);
7994b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		sta->manufacturer = dup_binstr(attr->manufacturer,
8004b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt					       attr->manufacturer_len);
8018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (attr->model_name) {
8048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(sta->model_name);
8054b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		sta->model_name = dup_binstr(attr->model_name,
8064b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt					     attr->model_name_len);
8078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (attr->model_number) {
8108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(sta->model_number);
8114b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		sta->model_number = dup_binstr(attr->model_number,
8124b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt					       attr->model_number_len);
8138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (attr->serial_number) {
8168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(sta->serial_number);
8174b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		sta->serial_number = dup_binstr(attr->serial_number,
8184b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt						attr->serial_number_len);
8198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (attr->dev_name) {
8228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(sta->dev_name);
8234b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		sta->dev_name = dup_binstr(attr->dev_name, attr->dev_name_len);
8248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_cancel_timeout(wps_er_sta_timeout, sta, NULL);
8278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_register_timeout(300, 0, wps_er_sta_timeout, sta, NULL);
8288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (m1 || new_sta)
8308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_er_sta_event(ap->er->wps, sta, WPS_EV_ER_ENROLLEE_ADD);
8318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return sta;
8338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
8348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_process_wlanevent_probe_req(struct wps_er_ap *ap,
8378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					       const u8 *addr,
8388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					       struct wpabuf *msg)
8398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
8408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_parse_attr attr;
8418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS ER: WLANEvent - Probe Request - from "
8438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   MACSTR, MAC2STR(addr));
8448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_buf(MSG_MSGDUMP, "WPS ER: WLANEvent - Enrollee's message "
8458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			"(TLVs from Probe Request)", msg);
8468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_validate_probe_req(msg, addr) < 0) {
8488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "WPS-STRICT: ER: Ignore invalid proxied "
8498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "Probe Request frame from " MACSTR, MAC2STR(addr));
8508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
8518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_parse_msg(msg, &attr) < 0) {
8548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse TLVs in "
8558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "WLANEvent message");
8568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
8578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_er_add_sta_data(ap, addr, &attr, 1);
8608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_registrar_probe_req_rx(ap->er->wps->registrar, addr, msg, 0);
8618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
8628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_http_put_wlan_response_cb(void *ctx, struct http_client *c,
8658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					     enum http_client_event event)
8668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
8678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_er_sta *sta = ctx;
8688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (event) {
8708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case HTTP_CLIENT_OK:
8718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: PutWLANResponse OK");
8728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
8738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case HTTP_CLIENT_FAILED:
8748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case HTTP_CLIENT_INVALID_REPLY:
8758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case HTTP_CLIENT_TIMEOUT:
8768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: PutWLANResponse failed");
8778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
8788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	http_client_free(sta->http);
8808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sta->http = NULL;
8818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
8828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic const char *soap_prefix =
8858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	"<?xml version=\"1.0\"?>\n"
8868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
8878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	"s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n"
8888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	"<s:Body>\n";
8898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic const char *soap_postfix =
8908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	"</s:Body>\n</s:Envelope>\n";
8918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic const char *urn_wfawlanconfig =
8928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	"urn:schemas-wifialliance-org:service:WFAWLANConfig:1";
8938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * wps_er_soap_hdr(const struct wpabuf *msg,
8958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       const char *name, const char *arg_name,
8968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       const char *path,
8978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       const struct sockaddr_in *dst,
8988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       char **len_ptr, char **body_ptr)
8998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
9008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned char *encoded;
9018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t encoded_len;
9028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *buf;
9038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (msg) {
9058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		encoded = base64_encode(wpabuf_head(msg), wpabuf_len(msg),
9068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					&encoded_len);
9078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (encoded == NULL)
9088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return NULL;
9098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
9108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		encoded = NULL;
9118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		encoded_len = 0;
9128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
9138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf = wpabuf_alloc(1000 + encoded_len);
9158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (buf == NULL) {
9168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(encoded);
9178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
9188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
9198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_printf(buf,
9218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      "POST %s HTTP/1.1\r\n"
9228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      "Host: %s:%d\r\n"
9238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      "Content-Type: text/xml; charset=\"utf-8\"\r\n"
9248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      "Content-Length: ",
9258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      path, inet_ntoa(dst->sin_addr), ntohs(dst->sin_port));
9268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*len_ptr = wpabuf_put(buf, 0);
9288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_printf(buf,
9298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      "        \r\n"
9308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      "SOAPACTION: \"%s#%s\"\r\n"
9318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      "\r\n",
9328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      urn_wfawlanconfig, name);
9338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*body_ptr = wpabuf_put(buf, 0);
9358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_str(buf, soap_prefix);
9378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_printf(buf, "<u:%s xmlns:u=\"", name);
9388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_str(buf, urn_wfawlanconfig);
9398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_str(buf, "\">\n");
9408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (encoded) {
9418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_printf(buf, "<%s>%s</%s>\n",
9428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      arg_name, (char *) encoded, arg_name);
9438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(encoded);
9448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
9458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return buf;
9478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
9488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_soap_end(struct wpabuf *buf, const char *name,
9518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    char *len_ptr, char *body_ptr)
9528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
9538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char len_buf[10];
9548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_printf(buf, "</u:%s>\n", name);
9558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_str(buf, soap_postfix);
9568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_snprintf(len_buf, sizeof(len_buf), "%d",
9578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    (int) ((char *) wpabuf_put(buf, 0) - body_ptr));
9588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(len_ptr, len_buf, os_strlen(len_buf));
9598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
9608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_sta_send_msg(struct wps_er_sta *sta, struct wpabuf *msg)
9638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
9648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *buf;
9658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *len_ptr, *body_ptr;
9668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct sockaddr_in dst;
9678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *url, *path;
9688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sta->http) {
9708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP request for STA - "
9718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "ignore new request");
9728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(msg);
9738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
9748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
9758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sta->ap->control_url == NULL) {
9778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: No controlURL for AP");
9788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(msg);
9798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
9808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
9818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	url = http_client_url_parse(sta->ap->control_url, &dst, &path);
9838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (url == NULL) {
9848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse controlURL");
9858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(msg);
9868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
9878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
9888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf = wps_er_soap_hdr(msg, "PutWLANResponse", "NewMessage", path, &dst,
9908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      &len_ptr, &body_ptr);
9918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(msg);
9928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(url);
9938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (buf == NULL)
9948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
9958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_printf(buf, "<NewWLANEventType>%d</NewWLANEventType>\n",
9968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      UPNP_WPS_WLANEVENT_TYPE_EAP);
9978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_printf(buf, "<NewWLANEventMAC>" MACSTR "</NewWLANEventMAC>\n",
9988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      MAC2STR(sta->addr));
9998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_er_soap_end(buf, "PutWLANResponse", len_ptr, body_ptr);
10018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sta->http = http_client_addr(&dst, buf, 1000,
10038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     wps_er_http_put_wlan_response_cb, sta);
10048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sta->http == NULL)
10058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(buf);
10068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_sta_process(struct wps_er_sta *sta, struct wpabuf *msg,
10108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       enum wsc_op_code op_code)
10118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
10128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	enum wps_process_res res;
10138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res = wps_process_msg(sta->wps, op_code, msg);
10158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (res == WPS_CONTINUE) {
10168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct wpabuf *next = wps_get_msg(sta->wps, &op_code);
10178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (next)
10188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps_er_sta_send_msg(sta, next);
10198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
10208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: Protocol run %s with the "
10218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "enrollee (res=%d)",
10228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   res == WPS_DONE ? "succeeded" : "failed", res);
10238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_deinit(sta->wps);
10248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sta->wps = NULL;
10258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (res == WPS_DONE) {
10268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			/* Remove the STA entry after short timeout */
10278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			eloop_cancel_timeout(wps_er_sta_timeout, sta, NULL);
10288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			eloop_register_timeout(10, 0, wps_er_sta_timeout, sta,
10298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					       NULL);
10308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
10318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_sta_start(struct wps_er_sta *sta, struct wpabuf *msg)
10368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
10378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_config cfg;
10388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sta->wps)
10408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_deinit(sta->wps);
10418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&cfg, 0, sizeof(cfg));
10438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cfg.wps = sta->ap->er->wps;
10448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cfg.registrar = 1;
10458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cfg.peer_addr = sta->addr;
10468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sta->wps = wps_init(&cfg);
10488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sta->wps == NULL)
10498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
10508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sta->wps->er = 1;
10518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sta->wps->use_cred = sta->ap->ap_settings;
10528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sta->ap->ap_settings) {
10538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(sta->cred);
10548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sta->cred = os_malloc(sizeof(*sta->cred));
10558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (sta->cred) {
10568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_memcpy(sta->cred, sta->ap->ap_settings,
10578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  sizeof(*sta->cred));
10588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			sta->cred->cred_attr = NULL;
10598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_memcpy(sta->cred->mac_addr, sta->addr, ETH_ALEN);
10608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			sta->wps->use_cred = sta->cred;
10618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
10628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_er_sta_process(sta, msg, WSC_MSG);
10658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_process_wlanevent_eap(struct wps_er_ap *ap, const u8 *addr,
10698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 struct wpabuf *msg)
10708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
10718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_parse_attr attr;
10728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_er_sta *sta;
10738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS ER: WLANEvent - EAP - from " MACSTR,
10758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   MAC2STR(addr));
10768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_buf(MSG_MSGDUMP, "WPS ER: WLANEvent - Enrollee's message "
10778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			"(TLVs from EAP-WSC)", msg);
10788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_parse_msg(msg, &attr) < 0) {
10808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse TLVs in "
10818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "WLANEvent message");
10828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
10838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sta = wps_er_add_sta_data(ap, addr, &attr, 0);
10868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sta == NULL)
10878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
10888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (attr.msg_type && *attr.msg_type == WPS_M1)
10908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_er_sta_start(sta, msg);
10918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else if (sta->wps) {
10928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		enum wsc_op_code op_code = WSC_MSG;
10938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (attr.msg_type) {
10948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			switch (*attr.msg_type) {
10958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			case WPS_WSC_ACK:
10968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				op_code = WSC_ACK;
10978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				break;
10988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			case WPS_WSC_NACK:
10998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				op_code = WSC_NACK;
11008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				break;
11018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			case WPS_WSC_DONE:
11028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				op_code = WSC_Done;
11038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				break;
11048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
11058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
11068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_er_sta_process(sta, msg, op_code);
11078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
11088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
11098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_process_wlanevent(struct wps_er_ap *ap,
11128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     struct wpabuf *event)
11138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
11148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *data;
11158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 wlan_event_type;
11168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 wlan_event_mac[ETH_ALEN];
11178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf msg;
11188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_MSGDUMP, "WPS ER: Received WLANEvent",
11208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    wpabuf_head(event), wpabuf_len(event));
11218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpabuf_len(event) < 1 + 17) {
11228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: Too short WLANEvent");
11238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
11248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
11258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data = wpabuf_mhead(event);
11278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wlan_event_type = data[0];
11288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hwaddr_aton((char *) data + 1, wlan_event_mac) < 0) {
11298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: Invalid WLANEventMAC in "
11308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "WLANEvent");
11318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
11328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
11338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_set(&msg, data + 1 + 17, wpabuf_len(event) - (1 + 17));
11358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (wlan_event_type) {
11378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case 1:
11388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_er_process_wlanevent_probe_req(ap, wlan_event_mac, &msg);
11398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
11408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case 2:
11418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_er_process_wlanevent_eap(ap, wlan_event_mac, &msg);
11428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
11438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	default:
11448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: Unknown WLANEventType %d",
11458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   wlan_event_type);
11468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
11478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
11488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
11498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_http_event(struct wps_er *er, struct http_request *req,
11528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      unsigned int ap_id)
11538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
11548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_er_ap *ap = wps_er_ap_get_id(er, ap_id);
11558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *event;
11568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	enum http_reply_code ret;
11578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap == NULL) {
11598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: HTTP event from unknown AP id "
11608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "%u", ap_id);
11618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_er_http_resp_not_found(req);
11628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
11638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
11648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_MSGDUMP, "WPS ER: HTTP event from AP id %u: %s",
11658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   ap_id, http_request_get_data(req));
11668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event = xml_get_base64_item(http_request_get_data(req), "WLANEvent",
11688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    &ret);
11698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (event == NULL) {
11708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: Could not extract WLANEvent "
11718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "from the event notification");
11728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
11738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * Reply with OK anyway to avoid getting unregistered from
11748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * events.
11758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
11768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_er_http_resp_ok(req);
11778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
11788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
11798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_er_process_wlanevent(ap, event);
11818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(event);
11838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_er_http_resp_ok(req);
11848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
11858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_http_notify(struct wps_er *er, struct http_request *req)
11888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
11898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *uri = http_request_get_uri(req);
11908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (os_strncmp(uri, "/event/", 7) == 0) {
11928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		unsigned int event_id;
11938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		char *pos;
11948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event_id = atoi(uri + 7);
11958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (event_id != er->event_id) {
11968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "WPS ER: HTTP event for an "
11978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "unknown event id %u", event_id);
11988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return;
11998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
12008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos = os_strchr(uri + 7, '/');
12018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (pos == NULL)
12028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return;
12038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos++;
12048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_er_http_event(er, req, atoi(pos));
12058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
12068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: Unknown HTTP NOTIFY for '%s'",
12078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   uri);
12088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_er_http_resp_not_found(req);
12098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
12108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
12118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_http_req(void *ctx, struct http_request *req)
12148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
12158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_er *er = ctx;
12168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct sockaddr_in *cli = http_request_get_cli_addr(req);
12178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	enum httpread_hdr_type type = http_request_get_type(req);
12188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *buf;
12198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS ER: HTTP request: '%s' (type %d) from "
12218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "%s:%d",
12228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   http_request_get_uri(req), type,
12238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   inet_ntoa(cli->sin_addr), ntohs(cli->sin_port));
12248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (type) {
12268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case HTTPREAD_HDR_TYPE_NOTIFY:
12278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_er_http_notify(er, req);
12288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
12298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	default:
12308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: Unsupported HTTP request type "
12318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "%d", type);
12328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		buf = wpabuf_alloc(200);
12338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (buf == NULL) {
12348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			http_request_deinit(req);
12358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return;
12368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
12378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_put_str(buf,
12388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       "HTTP/1.1 501 Unimplemented\r\n"
12398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       "Connection: close\r\n");
12408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		http_put_date(buf);
12418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_put_str(buf, "\r\n");
12428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		http_request_send_and_deinit(req, buf);
12438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
12448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
12458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
12468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wps_er *
12498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtwps_er_init(struct wps_context *wps, const char *ifname, const char *filter)
12508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
12518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_er *er;
12528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct in_addr addr;
12538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	er = os_zalloc(sizeof(*er));
12558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (er == NULL)
12568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
12578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_init(&er->ap);
12588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_init(&er->ap_unsubscribing);
12598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_init(&er->ap_settings);
12608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	er->multicast_sd = -1;
12628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	er->ssdp_sd = -1;
12638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_strlcpy(er->ifname, ifname, sizeof(er->ifname));
12658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	er->wps = wps;
12668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (os_get_random((unsigned char *) &er->event_id,
12678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  sizeof(er->event_id)) < 0) {
12688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_er_deinit(er, NULL, NULL);
12698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
12708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
12718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Limit event_id to < 32 bits to avoid issues with atoi() */
12728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	er->event_id &= 0x0fffffff;
12738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12744b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt	if (filter && os_strncmp(filter, "ifname=", 7) == 0) {
12754b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		const char *pos, *end;
12764b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		pos = filter + 7;
12774b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		end = os_strchr(pos, ' ');
12784b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		if (end) {
12794b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt			size_t len = end - pos;
12804b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt			os_strlcpy(er->ifname, pos, len < sizeof(er->ifname) ?
12814b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt				   len + 1 : sizeof(er->ifname));
12824b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt			filter = end + 1;
12834b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		} else {
12844b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt			os_strlcpy(er->ifname, pos, sizeof(er->ifname));
12854b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt			filter = NULL;
12864b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		}
12874b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		er->forced_ifname = 1;
12884b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt	}
12894b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt
12908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (filter) {
12918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (inet_aton(filter, &er->filter_addr) == 0) {
12928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "WPS UPnP: Invalid filter "
12938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "address %s", filter);
12948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps_er_deinit(er, NULL, NULL);
12958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return NULL;
12968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
12978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS UPnP: Only accepting connections "
12988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "with %s", filter);
12998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
13004b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt	if (get_netif_info(er->ifname, &er->ip_addr, &er->ip_addr_text,
13018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   er->mac_addr)) {
13028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "WPS UPnP: Could not get IP/MAC address "
13034b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt			   "for %s. Does it have IP address?", er->ifname);
13048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_er_deinit(er, NULL, NULL);
13058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
13068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
13078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_er_ssdp_init(er) < 0) {
13098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "WPS UPnP: SSDP initialization failed");
13108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_er_deinit(er, NULL, NULL);
13118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
13128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
13138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr.s_addr = er->ip_addr;
13158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	er->http_srv = http_server_init(&addr, -1, wps_er_http_req, er);
13168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (er->http_srv == NULL) {
13178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "WPS UPnP: HTTP initialization failed");
13188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_er_deinit(er, NULL, NULL);
13198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
13208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
13218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	er->http_port = http_server_get_port(er->http_srv);
13228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS ER: Start (ifname=%s ip_addr=%s)",
13248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   er->ifname, er->ip_addr_text);
13258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return er;
13278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
13288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wps_er_refresh(struct wps_er *er)
13318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
13328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_er_ap *ap;
13338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_er_sta *sta;
13348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
13368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_er_ap_event(er->wps, ap, WPS_EV_ER_AP_ADD);
13378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		dl_list_for_each(sta, &ap->sta, struct wps_er_sta, list)
13388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps_er_sta_event(er->wps, sta, WPS_EV_ER_ENROLLEE_ADD);
13398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
13408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_er_send_ssdp_msearch(er);
13428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
13438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_deinit_finish(void *eloop_data, void *user_ctx)
13468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
13478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_er *er = eloop_data;
13488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void (*deinit_done_cb)(void *ctx);
13498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void *deinit_done_ctx;
1350fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	struct wps_er_ap *ap, *tmp;
13518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS ER: Finishing deinit");
13538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1354fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	dl_list_for_each_safe(ap, tmp, &er->ap_unsubscribing, struct wps_er_ap,
1355fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			      list) {
1356fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: AP entry for %s (%s) still in ap_unsubscribing list - free it",
1357fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			   inet_ntoa(ap->addr), ap->location);
1358fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		dl_list_del(&ap->list);
1359fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		wps_er_ap_free(ap);
1360fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	}
1361fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
1362fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	eloop_cancel_timeout(wps_er_deinit_finish, er, NULL);
13638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	deinit_done_cb = er->deinit_done_cb;
13648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	deinit_done_ctx = er->deinit_done_ctx;
13658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(er->ip_addr_text);
13668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(er);
13678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (deinit_done_cb)
13698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		deinit_done_cb(deinit_done_ctx);
13708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
13718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wps_er_deinit(struct wps_er *er, void (*cb)(void *ctx), void *ctx)
13748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
13758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (er == NULL)
13768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
13778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	http_server_deinit(er->http_srv);
13788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_er_ap_remove_all(er);
13798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_er_ssdp_deinit(er);
13808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_register_timeout(dl_list_empty(&er->ap_unsubscribing) ? 0 : 5, 0,
13818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       wps_er_deinit_finish, er, NULL);
13828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS ER: Finish deinit from timeout");
13838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	er->deinitializing = 1;
13848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	er->deinit_done_cb = cb;
13858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	er->deinit_done_ctx = ctx;
13868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
13878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_http_set_sel_reg_cb(void *ctx, struct http_client *c,
13908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       enum http_client_event event)
13918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
13928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_er_ap *ap = ctx;
13938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wps_event_data data;
13948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&data, 0, sizeof(data));
13968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (event) {
13988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case HTTP_CLIENT_OK:
13998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: SetSelectedRegistrar OK");
14008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data.set_sel_reg.state = WPS_ER_SET_SEL_REG_DONE;
14018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data.set_sel_reg.uuid = ap->uuid;
14028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
14038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case HTTP_CLIENT_FAILED:
14048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case HTTP_CLIENT_INVALID_REPLY:
14058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case HTTP_CLIENT_TIMEOUT:
14068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: SetSelectedRegistrar failed");
14078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data.set_sel_reg.state = WPS_ER_SET_SEL_REG_FAILED;
14088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data.set_sel_reg.uuid = ap->uuid;
14098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
14108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
14118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	http_client_free(ap->http);
14128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->http = NULL;
14138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (data.set_sel_reg.uuid)
14158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ap->er->wps->event_cb(ap->er->wps->cb_ctx,
14168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      WPS_EV_ER_SET_SELECTED_REGISTRAR, &data);
14178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
14188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_send_set_sel_reg(struct wps_er_ap *ap, struct wpabuf *msg)
14218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
14228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *buf;
14238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *len_ptr, *body_ptr;
14248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct sockaddr_in dst;
14258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *url, *path;
14268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap->control_url == NULL) {
14288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: No controlURL for AP");
14298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
14308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
14318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap->http) {
14338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP request for AP - "
14348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "ignore new request");
14358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
14368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
14378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap->wps) {
14398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: Pending WPS operation for AP - "
14408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "skip SetSelectedRegistrar");
14418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
14428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
14438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	url = http_client_url_parse(ap->control_url, &dst, &path);
14458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (url == NULL) {
14468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse controlURL");
14478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
14488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
14498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf = wps_er_soap_hdr(msg, "SetSelectedRegistrar", "NewMessage", path,
14518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      &dst, &len_ptr, &body_ptr);
14528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(url);
14538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (buf == NULL)
14548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
14558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_er_soap_end(buf, "SetSelectedRegistrar", len_ptr, body_ptr);
14578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->http = http_client_addr(&dst, buf, 1000,
14598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    wps_er_http_set_sel_reg_cb, ap);
14608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap->http == NULL)
14618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(buf);
14628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
14638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_er_build_selected_registrar(struct wpabuf *msg, int sel_reg)
14668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
14678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_SELECTED_REGISTRAR);
14688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, 1);
14698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_u8(msg, !!sel_reg);
14708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
14718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
14728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_er_build_dev_password_id(struct wpabuf *msg, u16 dev_passwd_id)
14758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
14768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_DEV_PASSWORD_ID);
14778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, 2);
14788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, dev_passwd_id);
14798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
14808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
14818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_er_build_sel_reg_config_methods(struct wpabuf *msg,
14848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					       u16 sel_reg_config_methods)
14858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
14868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_SELECTED_REGISTRAR_CONFIG_METHODS);
14878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, 2);
14888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, sel_reg_config_methods);
14898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
14908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
14918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_er_build_uuid_r(struct wpabuf *msg, const u8 *uuid_r)
14948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
14958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, ATTR_UUID_R);
14968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(msg, WPS_UUID_LEN);
14978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_data(msg, uuid_r, WPS_UUID_LEN);
14988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
14998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
15008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid wps_er_set_sel_reg(struct wps_er *er, int sel_reg, u16 dev_passwd_id,
15038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			u16 sel_reg_config_methods)
15048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
15058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *msg;
15068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_er_ap *ap;
15078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_registrar *reg = er->wps->registrar;
15088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *auth_macs;
15098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 bcast[ETH_ALEN];
15108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t count;
15118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wps_event_data data;
15128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (er->skip_set_sel_reg) {
15148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: Skip SetSelectedRegistrar");
15158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
15168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
15178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = wpabuf_alloc(500);
15198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (msg == NULL)
15208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
15218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	auth_macs = wps_authorized_macs(reg, &count);
15238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (count == 0) {
15248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memset(bcast, 0xff, ETH_ALEN);
15258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		auth_macs = bcast;
15268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		count = 1;
15278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
15288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_build_version(msg) ||
15308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_er_build_selected_registrar(msg, sel_reg) ||
15318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_er_build_dev_password_id(msg, dev_passwd_id) ||
15328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_er_build_sel_reg_config_methods(msg, sel_reg_config_methods) ||
15338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_build_wfa_ext(msg, 0, auth_macs, count) ||
15348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wps_er_build_uuid_r(msg, er->wps->uuid)) {
15358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(msg);
15368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
15378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
15388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&data, 0, sizeof(data));
15408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.set_sel_reg.sel_reg = sel_reg;
15418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.set_sel_reg.dev_passwd_id = dev_passwd_id;
15428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.set_sel_reg.sel_reg_config_methods = sel_reg_config_methods;
15438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.set_sel_reg.state = WPS_ER_SET_SEL_REG_START;
15448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
15468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (er->set_sel_reg_uuid_filter &&
15478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    os_memcmp(ap->uuid, er->set_sel_reg_uuid_filter,
15488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      WPS_UUID_LEN) != 0)
15498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
15508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data.set_sel_reg.uuid = ap->uuid;
15518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		er->wps->event_cb(er->wps->cb_ctx,
15528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  WPS_EV_ER_SET_SELECTED_REGISTRAR, &data);
15538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_er_send_set_sel_reg(ap, msg);
15548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
15558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(msg);
15578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
15588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15601e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidtint wps_er_pbc(struct wps_er *er, const u8 *uuid, const u8 *addr)
15618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
15628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int res;
15638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_er_ap *ap;
15648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (er == NULL || er->wps == NULL)
15668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
15678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_registrar_pbc_overlap(er->wps->registrar, NULL, NULL)) {
15698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: PBC overlap - do not start PBC "
15708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "mode");
15718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -2;
15728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
15738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15741e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt	if (uuid)
15751e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt		ap = wps_er_ap_get(er, NULL, uuid, NULL);
15761e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt	else
15771e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt		ap = NULL;
15788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap == NULL) {
15798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct wps_er_sta *sta = NULL;
15808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
15811e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt			sta = wps_er_sta_get(ap, addr, uuid);
15828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (sta) {
15838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				uuid = ap->uuid;
15848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				break;
15858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
15868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
15878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (sta == NULL)
15888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -3; /* Unknown UUID */
15898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
15908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap->ap_settings == NULL) {
15928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: AP settings not known");
15938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -4;
15948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
15958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	er->set_sel_reg_uuid_filter = uuid;
15978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res = wps_registrar_button_pushed(er->wps->registrar, NULL);
15988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	er->set_sel_reg_uuid_filter = NULL;
15998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (res)
16008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
16018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
16038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
16048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_ap_settings_cb(void *ctx, const struct wps_credential *cred)
16078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
16088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_er_ap *ap = ctx;
16098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wps_event_data data;
16108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS ER: AP Settings received");
16128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(ap->ap_settings);
16138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->ap_settings = os_malloc(sizeof(*cred));
16148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap->ap_settings) {
16158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(ap->ap_settings, cred, sizeof(*cred));
16168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ap->ap_settings->cred_attr = NULL;
16178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
16188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&data, 0, sizeof(data));
16208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.ap_settings.uuid = ap->uuid;
16218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.ap_settings.cred = cred;
16228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->er->wps->event_cb(ap->er->wps->cb_ctx, WPS_EV_ER_AP_SETTINGS,
16238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      &data);
16248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
16258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16271e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidtconst u8 * wps_er_get_sta_uuid(struct wps_er *er, const u8 *addr)
16281e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt{
16291e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt	struct wps_er_ap *ap;
16301e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt	dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
16311e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt		struct wps_er_sta *sta;
16321e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt		sta = wps_er_sta_get(ap, addr, NULL);
16331e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt		if (sta)
16341e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt			return sta->uuid;
16351e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt	}
16361e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt	return NULL;
16371e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt}
16381e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt
16391e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt
16408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_http_put_message_cb(void *ctx, struct http_client *c,
16418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       enum http_client_event event)
16428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
16438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_er_ap *ap = ctx;
16448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *reply;
16458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *msg = NULL;
16468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (event) {
16488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case HTTP_CLIENT_OK:
16498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: PutMessage OK");
16508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		reply = http_client_get_body(c);
1651d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		if (reply)
1652d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			msg = os_zalloc(wpabuf_len(reply) + 1);
1653d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		if (msg == NULL) {
1654d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			if (ap->wps) {
1655d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt				wps_deinit(ap->wps);
1656d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt				ap->wps = NULL;
1657d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			}
16588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
1659d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		}
16608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(msg, wpabuf_head(reply), wpabuf_len(reply));
16618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
16628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case HTTP_CLIENT_FAILED:
16638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case HTTP_CLIENT_INVALID_REPLY:
16648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case HTTP_CLIENT_TIMEOUT:
16658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: PutMessage failed");
16668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ap->wps) {
16678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps_deinit(ap->wps);
16688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ap->wps = NULL;
16698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
16708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
16718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
16728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	http_client_free(ap->http);
16738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->http = NULL;
16748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (msg) {
16768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct wpabuf *buf;
16778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		enum http_reply_code ret;
16788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		buf = xml_get_base64_item(msg, "NewOutMessage", &ret);
16798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(msg);
16808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (buf == NULL) {
16818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "WPS ER: Could not extract "
16828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "NewOutMessage from PutMessage response");
16838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps_deinit(ap->wps);
16848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ap->wps = NULL;
16858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return;
16868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
16878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_er_ap_process(ap, buf);
16888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(buf);
16898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
16908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
16918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_ap_put_message(struct wps_er_ap *ap,
16948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  const struct wpabuf *msg)
16958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
16968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *buf;
16978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *len_ptr, *body_ptr;
16988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct sockaddr_in dst;
16998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *url, *path;
17008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap->http) {
17028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP operation ongoing "
17038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "with the AP - cannot continue learn");
17048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
17058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
17068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap->control_url == NULL) {
17088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: No controlURL for AP");
17098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
17108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
17118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	url = http_client_url_parse(ap->control_url, &dst, &path);
17138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (url == NULL) {
17148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse controlURL");
1715d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		goto fail;
17168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
17178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf = wps_er_soap_hdr(msg, "PutMessage", "NewInMessage", path, &dst,
17198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      &len_ptr, &body_ptr);
17208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(url);
17218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (buf == NULL)
1722d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		goto fail;
17238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_er_soap_end(buf, "PutMessage", len_ptr, body_ptr);
17258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->http = http_client_addr(&dst, buf, 10000,
17278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    wps_er_http_put_message_cb, ap);
1728d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	if (ap->http == NULL) {
17298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(buf);
1730d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		goto fail;
1731d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	}
1732d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	return;
1733d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
1734d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidtfail:
1735d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	if (ap->wps) {
1736d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		wps_deinit(ap->wps);
1737d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		ap->wps = NULL;
1738d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	}
17398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
17408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_ap_process(struct wps_er_ap *ap, struct wpabuf *msg)
17438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
17448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	enum wps_process_res res;
17458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_parse_attr attr;
17468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	enum wsc_op_code op_code;
17478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	op_code = WSC_MSG;
17498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_parse_msg(msg, &attr) == 0 && attr.msg_type) {
17508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		switch (*attr.msg_type) {
17518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case WPS_WSC_ACK:
17528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			op_code = WSC_ACK;
17538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
17548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case WPS_WSC_NACK:
17558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			op_code = WSC_NACK;
17568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
17578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case WPS_WSC_DONE:
17588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			op_code = WSC_Done;
17598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
17608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
17618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
17628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res = wps_process_msg(ap->wps, op_code, msg);
17648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (res == WPS_CONTINUE) {
17658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct wpabuf *next = wps_get_msg(ap->wps, &op_code);
17668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (next) {
17678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps_er_ap_put_message(ap, next);
17688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpabuf_free(next);
17698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else {
17708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "WPS ER: Failed to build "
17718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "message");
17728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wps_deinit(ap->wps);
17738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ap->wps = NULL;
17748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
17758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (res == WPS_DONE) {
17768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: Protocol run done");
17778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_deinit(ap->wps);
17788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ap->wps = NULL;
17798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
17808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: Failed to process message from "
17818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "AP (res=%d)", res);
17828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_deinit(ap->wps);
17838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ap->wps = NULL;
17848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
17858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
17868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_ap_learn_m1(struct wps_er_ap *ap, struct wpabuf *m1)
17898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
17908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_config cfg;
17918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap->wps) {
17938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: Protocol run already in "
17948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "progress with this AP");
17958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
17968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
17978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&cfg, 0, sizeof(cfg));
17998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cfg.wps = ap->er->wps;
18008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cfg.registrar = 1;
18018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->wps = wps_init(&cfg);
18028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap->wps == NULL)
18038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
18048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->wps->ap_settings_cb = wps_er_ap_settings_cb;
18058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->wps->ap_settings_cb_ctx = ap;
18068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_er_ap_process(ap, m1);
18088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
18098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_ap_learn(struct wps_er_ap *ap, const char *dev_info)
18128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
18138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *info;
18148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	enum http_reply_code ret;
18158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS ER: Received GetDeviceInfo response (M1) "
18178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "from the AP");
18188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	info = xml_get_base64_item(dev_info, "NewDeviceInfo", &ret);
18198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (info == NULL) {
18208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: Could not extract "
18218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "NewDeviceInfo from GetDeviceInfo response");
18228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
18238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
18248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->m1_handler(ap, info);
18268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(info);
18278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
18288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_http_get_dev_info_cb(void *ctx, struct http_client *c,
18318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					enum http_client_event event)
18328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
18338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_er_ap *ap = ctx;
18348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *reply;
18358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *dev_info = NULL;
18368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (event) {
18388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case HTTP_CLIENT_OK:
18398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: GetDeviceInfo OK");
18408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		reply = http_client_get_body(c);
18418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (reply == NULL)
18428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
18438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		dev_info = os_zalloc(wpabuf_len(reply) + 1);
18448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (dev_info == NULL)
18458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
18468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(dev_info, wpabuf_head(reply), wpabuf_len(reply));
18478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
18488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case HTTP_CLIENT_FAILED:
18498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case HTTP_CLIENT_INVALID_REPLY:
18508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case HTTP_CLIENT_TIMEOUT:
18518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: GetDeviceInfo failed");
18528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
18538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
18548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	http_client_free(ap->http);
18558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->http = NULL;
18568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (dev_info) {
18588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wps_er_ap_learn(ap, dev_info);
18598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(dev_info);
18608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
18618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
18628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wps_er_send_get_device_info(struct wps_er_ap *ap,
18658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       void (*m1_handler)(struct wps_er_ap *ap,
18668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt							  struct wpabuf *m1))
18678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
18688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *buf;
18698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *len_ptr, *body_ptr;
18708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct sockaddr_in dst;
18718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *url, *path;
18728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap->http) {
18748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP operation ongoing "
18758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "with the AP - cannot get device info");
18768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
18778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
18788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap->control_url == NULL) {
18808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: No controlURL for AP");
18818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
18828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
18838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	url = http_client_url_parse(ap->control_url, &dst, &path);
18858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (url == NULL) {
18868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse controlURL");
18878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
18888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
18898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf = wps_er_soap_hdr(NULL, "GetDeviceInfo", NULL, path, &dst,
18918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      &len_ptr, &body_ptr);
18928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(url);
18938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (buf == NULL)
18948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
18958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_er_soap_end(buf, "GetDeviceInfo", len_ptr, body_ptr);
18978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->http = http_client_addr(&dst, buf, 10000,
18998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    wps_er_http_get_dev_info_cb, ap);
19008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap->http == NULL) {
19018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(buf);
19028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
19038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
19048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->m1_handler = m1_handler;
19068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
19088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
19098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19111e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidtint wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *addr,
19121e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt		 const u8 *pin, size_t pin_len)
19138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
19148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_er_ap *ap;
19158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (er == NULL)
19178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
19188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19191e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt	ap = wps_er_ap_get(er, NULL, uuid, addr);
19208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap == NULL) {
19218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: AP not found for learn "
19228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "request");
19238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
19248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
19251e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt	if (uuid == NULL)
19261e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt		uuid = ap->uuid;
19278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap->wps) {
19288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: Pending operation ongoing "
19298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "with the AP - cannot start learn");
19308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
19318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
19328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_er_send_get_device_info(ap, wps_er_ap_learn_m1) < 0)
19348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
19358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	er->skip_set_sel_reg = 1;
19378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_registrar_add_pin(er->wps->registrar, NULL, uuid, pin, pin_len, 0);
19388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	er->skip_set_sel_reg = 0;
19398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
19418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
19428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19441e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidtint wps_er_set_config(struct wps_er *er, const u8 *uuid, const u8 *addr,
19458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      const struct wps_credential *cred)
19468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
19478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_er_ap *ap;
19488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (er == NULL)
19508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
19518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19521e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt	ap = wps_er_ap_get(er, NULL, uuid, addr);
19538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap == NULL) {
19548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: AP not found for set config "
19558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "request");
19568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
19578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
19588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(ap->ap_settings);
1960d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt	ap->ap_settings = os_memdup(cred, sizeof(*cred));
19618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap->ap_settings == NULL)
19628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
19638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->ap_settings->cred_attr = NULL;
19648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS ER: Updated local AP settings based set "
19658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "config request");
19668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
19688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
19698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wps_er_ap_config_m1(struct wps_er_ap *ap, struct wpabuf *m1)
19728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
19738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_config cfg;
19748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap->wps) {
19768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: Protocol run already in "
19778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "progress with this AP");
19788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
19798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
19808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&cfg, 0, sizeof(cfg));
19828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cfg.wps = ap->er->wps;
19838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cfg.registrar = 1;
19848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cfg.new_ap_settings = ap->ap_settings;
19858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->wps = wps_init(&cfg);
19868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap->wps == NULL)
19878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
19888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->wps->ap_settings_cb = NULL;
19898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->wps->ap_settings_cb_ctx = NULL;
19908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_er_ap_process(ap, m1);
19928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
19938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19951e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidtint wps_er_config(struct wps_er *er, const u8 *uuid, const u8 *addr,
19961e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt		  const u8 *pin, size_t pin_len,
19971e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt		  const struct wps_credential *cred)
19988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
19998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_er_ap *ap;
20008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (er == NULL)
20028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
20038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20041e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt	ap = wps_er_ap_get(er, NULL, uuid, addr);
20058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap == NULL) {
20068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: AP not found for config "
20078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "request");
20088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
20098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
20101e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt	if (uuid == NULL)
20111e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt		uuid = ap->uuid;
20128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap->wps) {
20138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: Pending operation ongoing "
20148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "with the AP - cannot start config");
20158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
20168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
20178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(ap->ap_settings);
2019d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt	ap->ap_settings = os_memdup(cred, sizeof(*cred));
20208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap->ap_settings == NULL)
20218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
20228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->ap_settings->cred_attr = NULL;
20238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wps_er_send_get_device_info(ap, wps_er_ap_config_m1) < 0)
20258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
20268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	er->skip_set_sel_reg = 1;
20288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_registrar_add_pin(er->wps->registrar, NULL, uuid, pin, pin_len, 0);
20298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	er->skip_set_sel_reg = 0;
20308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
20328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
203304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
203404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
203504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#ifdef CONFIG_WPS_NFC
20361e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt
20371e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidtstruct wpabuf * wps_er_config_token_from_cred(struct wps_context *wps,
20381e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt					      struct wps_credential *cred)
203904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
204004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	struct wpabuf *ret;
204104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	struct wps_data data;
204204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
204304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	ret = wpabuf_alloc(500);
204404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (ret == NULL)
204504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return NULL;
204604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
204704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	os_memset(&data, 0, sizeof(data));
20481e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt	data.wps = wps;
20491e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt	data.use_cred = cred;
2050cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (wps_build_cred(&data, ret) ||
205104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	    wps_build_wfa_ext(ret, 0, NULL, 0)) {
205204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpabuf_free(ret);
205304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return NULL;
205404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
205504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
205604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	return ret;
205704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
20581e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt
20591e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt
20601e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidtstruct wpabuf * wps_er_nfc_config_token(struct wps_er *er, const u8 *uuid,
20611e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt					const u8 *addr)
20621e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt{
20631e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt	struct wps_er_ap *ap;
20641e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt
20651e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt	if (er == NULL)
20661e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt		return NULL;
20671e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt
20681e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt	ap = wps_er_ap_get(er, NULL, uuid, addr);
20691e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt	if (ap == NULL)
20701e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt		return NULL;
20711e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt	if (ap->ap_settings == NULL) {
20721e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: No settings known for the "
20731e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt			   "selected AP");
20741e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt		return NULL;
20751e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt	}
20761e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt
20771e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt	return wps_er_config_token_from_cred(er->wps, ap->ap_settings);
20781e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt}
20791e78e76961664775f58b139f8c6388cfa0485f3dDmitry Shmidt
2080cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
2081cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidtstruct wpabuf * wps_er_nfc_handover_sel(struct wps_er *er,
2082cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt					struct wps_context *wps, const u8 *uuid,
2083cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt					const u8 *addr, struct wpabuf *pubkey)
2084cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt{
2085cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	struct wps_er_ap *ap;
2086cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
2087cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (er == NULL)
2088cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return NULL;
2089cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
2090cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	ap = wps_er_ap_get(er, NULL, uuid, addr);
2091cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (ap == NULL)
2092cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return NULL;
2093cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	if (ap->ap_settings == NULL) {
2094cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS ER: No settings known for the "
2095cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt			   "selected AP");
2096cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt		return NULL;
2097cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	}
2098cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
2099cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	os_memcpy(wps->ssid, ap->ap_settings->ssid, ap->ap_settings->ssid_len);
2100cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	wps->ssid_len = ap->ap_settings->ssid_len;
2101cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
2102cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	return wps_build_nfc_handover_sel(wps, pubkey, addr, 0);
2103cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt}
2104cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
210504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#endif /* CONFIG_WPS_NFC */
2106