18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Wi-Fi Direct - P2P provision discovery
38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2009-2010, Atheros Communications
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
58d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This program is free software; you can redistribute it and/or modify
68d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * it under the terms of the GNU General Public License version 2 as
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * published by the Free Software Foundation.
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Alternatively, this software may be distributed under the terms of BSD
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * license.
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * See README and COPYING for more details.
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h"
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h"
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common/ieee802_11_defs.h"
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "wps/wps_defs.h"
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "p2p_i.h"
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "p2p.h"
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen/*
2575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen * Number of retries to attempt for provision discovery requests during IDLE
2675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen * state in case the peer is not listening.
2775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen */
2875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen#define MAX_PROV_DISC_REQ_RETRIES 10
2975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
3075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void p2p_build_wps_ie_config_methods(struct wpabuf *buf,
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					    u16 config_methods)
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *len;
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len = wpabuf_put(buf, 1);
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be32(buf, WPS_DEV_OUI_WFA);
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Config Methods */
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(buf, ATTR_CONFIG_METHODS);
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(buf, 2);
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(buf, config_methods);
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	p2p_buf_update_ie_hdr(buf, len);
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p,
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					       u8 dialog_token,
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					       u16 config_methods,
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					       struct p2p_device *go)
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *buf;
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *len;
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf = wpabuf_alloc(1000);
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (buf == NULL)
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_REQ, dialog_token);
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len = p2p_buf_add_ie_hdr(buf);
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	p2p_buf_add_capability(buf, p2p->dev_capab, 0);
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	p2p_buf_add_device_info(buf, p2p, NULL);
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (go) {
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		p2p_buf_add_group_id(buf, go->info.p2p_device_addr,
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     go->oper_ssid, go->oper_ssid_len);
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	p2p_buf_update_ie_hdr(buf, len);
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* WPS IE with Config Methods attribute */
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	p2p_build_wps_ie_config_methods(buf, config_methods);
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return buf;
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						u8 dialog_token,
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						u16 config_methods)
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *buf;
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf = wpabuf_alloc(100);
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (buf == NULL)
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_RESP, dialog_token);
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* WPS IE with Config Methods attribute */
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	p2p_build_wps_ie_config_methods(buf, config_methods);
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return buf;
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       const u8 *data, size_t len, int rx_freq)
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct p2p_message msg;
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct p2p_device *dev;
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int freq;
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int reject = 1;
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *resp;
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (p2p_parse(data, len, &msg))
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		"P2P: Received Provision Discovery Request from " MACSTR
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		" with config methods 0x%x (freq=%d)",
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		MAC2STR(sa), msg.wps_config_methods, rx_freq);
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dev = p2p_get_device(p2p, sa);
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (dev == NULL || !(dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			"P2P: Provision Discovery Request from "
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			"unknown peer " MACSTR, MAC2STR(sa));
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (p2p_add_device(p2p, sa, rx_freq, 0, data + 1, len - 1)) {
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			        "P2P: Provision Discovery Request add device "
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				"failed " MACSTR, MAC2STR(sa));
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!(msg.wps_config_methods &
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	      (WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD |
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	       WPS_CONFIG_PUSHBUTTON))) {
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Unsupported "
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			"Config Methods in Provision Discovery Request");
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto out;
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (dev)
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				P2P_DEV_PD_PEER_KEYPAD);
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (msg.wps_config_methods & WPS_CONFIG_DISPLAY) {
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			" requested us to show a PIN on display", MAC2STR(sa));
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (dev)
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			" requested us to write its PIN using keypad",
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			MAC2STR(sa));
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (dev)
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	reject = 0;
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtout:
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	resp = p2p_build_prov_disc_resp(p2p, msg.dialog_token,
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					reject ? 0 : msg.wps_config_methods);
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (resp == NULL) {
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		p2p_parse_free(&msg);
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		"P2P: Sending Provision Discovery Response");
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (rx_freq > 0)
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		freq = rx_freq;
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		freq = p2p_channel_to_freq(p2p->cfg->country,
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   p2p->cfg->reg_class,
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   p2p->cfg->channel);
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (freq < 0) {
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			"P2P: Unknown regulatory class/channel");
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(resp);
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		p2p_parse_free(&msg);
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	p2p->pending_action_state = P2P_NO_PENDING_ACTION;
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr,
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    p2p->cfg->dev_addr,
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    wpabuf_head(resp), wpabuf_len(resp), 200) < 0) {
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			"P2P: Failed to send Action frame");
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(resp);
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!reject && p2p->cfg->prov_disc_req) {
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		const u8 *dev_addr = sa;
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (msg.p2p_device_addr)
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			dev_addr = msg.p2p_device_addr;
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		p2p->cfg->prov_disc_req(p2p->cfg->cb_ctx, sa,
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					msg.wps_config_methods,
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					dev_addr, msg.pri_dev_type,
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					msg.device_name, msg.config_methods,
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					msg.capability ? msg.capability[0] : 0,
1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					msg.capability ? msg.capability[1] :
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					0);
1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	p2p_parse_free(&msg);
1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				const u8 *data, size_t len)
2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct p2p_message msg;
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct p2p_device *dev;
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 report_config_methods = 0;
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (p2p_parse(data, len, &msg))
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		"P2P: Received Provisioning Discovery Response from " MACSTR
2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		" with config methods 0x%x",
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		MAC2STR(sa), msg.wps_config_methods);
2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dev = p2p_get_device(p2p, sa);
2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (dev == NULL || !dev->req_config_methods) {
2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			"P2P: Ignore Provisioning Discovery Response from "
2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			MACSTR " with no pending request", MAC2STR(sa));
2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		p2p_parse_free(&msg);
2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	if (p2p->pending_action_state == P2P_PENDING_PD) {
22675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
22775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		p2p->pending_action_state = P2P_NO_PENDING_ACTION;
22875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	}
22975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (dev->dialog_token != msg.dialog_token) {
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			"P2P: Ignore Provisioning Discovery Response with "
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			"unexpected Dialog Token %u (expected %u)",
2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			msg.dialog_token, dev->dialog_token);
2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		p2p_parse_free(&msg);
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	/*
24075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	 * If the response is from the peer to whom a user initiated request
24175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	 * was sent earlier, we reset that state info here.
24275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	 */
24375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	if (p2p->user_initiated_pd &&
24475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	    os_memcmp(p2p->pending_pd_devaddr, sa, ETH_ALEN) == 0)
24575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		p2p_reset_pending_pd(p2p);
24675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (msg.wps_config_methods != dev->req_config_methods) {
2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer rejected "
2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			"our Provisioning Discovery Request");
25075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		if (p2p->cfg->prov_disc_fail)
25175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa,
25275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen						 P2P_PROV_DISC_REJECTED);
2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		p2p_parse_free(&msg);
2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto out;
2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	report_config_methods = dev->req_config_methods;
2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			P2P_DEV_PD_PEER_KEYPAD);
2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (dev->req_config_methods & WPS_CONFIG_DISPLAY) {
2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			" accepted to show a PIN on display", MAC2STR(sa));
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR
2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			" accepted to write our PIN using keypad",
2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			MAC2STR(sa));
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	p2p_parse_free(&msg);
2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtout:
2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dev->req_config_methods = 0;
2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (p2p->cfg->prov_disc_resp)
2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		p2p->cfg->prov_disc_resp(p2p->cfg->cb_ctx, sa,
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 report_config_methods);
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   int join)
2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *req;
2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int freq;
286497c1d5e50162d6b3c1cce5dbd9c5fd9da69aaefDmitry Shmidt#ifdef ANDROID_BRCM_P2P_PATCH
287497c1d5e50162d6b3c1cce5dbd9c5fd9da69aaefDmitry Shmidt	if(dev->go_state == REMOTE_GO) {
288497c1d5e50162d6b3c1cce5dbd9c5fd9da69aaefDmitry Shmidt		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
289497c1d5e50162d6b3c1cce5dbd9c5fd9da69aaefDmitry Shmidt			"P2P: GO Sending it to oper_freq %d", dev->oper_freq);
290497c1d5e50162d6b3c1cce5dbd9c5fd9da69aaefDmitry Shmidt		freq= dev->oper_freq;
291497c1d5e50162d6b3c1cce5dbd9c5fd9da69aaefDmitry Shmidt	}
292497c1d5e50162d6b3c1cce5dbd9c5fd9da69aaefDmitry Shmidt	else {
293497c1d5e50162d6b3c1cce5dbd9c5fd9da69aaefDmitry Shmidt		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
294497c1d5e50162d6b3c1cce5dbd9c5fd9da69aaefDmitry Shmidt			"P2P: NOT GO oper_freq %d listen_freq %d", dev->oper_freq, dev->listen_freq);
295497c1d5e50162d6b3c1cce5dbd9c5fd9da69aaefDmitry Shmidt		freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
296497c1d5e50162d6b3c1cce5dbd9c5fd9da69aaefDmitry Shmidt	}
297497c1d5e50162d6b3c1cce5dbd9c5fd9da69aaefDmitry Shmidt#else
2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
299497c1d5e50162d6b3c1cce5dbd9c5fd9da69aaefDmitry Shmidt#endif
300497c1d5e50162d6b3c1cce5dbd9c5fd9da69aaefDmitry Shmidt
3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (freq <= 0) {
3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			"P2P: No Listen/Operating frequency known for the "
3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			"peer " MACSTR " to send Provision Discovery Request",
3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			MAC2STR(dev->info.p2p_device_addr));
3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) {
3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!(dev->info.dev_capab &
3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) {
3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				"P2P: Cannot use PD with P2P Device " MACSTR
3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				" that is in a group and is not discoverable",
3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				MAC2STR(dev->info.p2p_device_addr));
3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* TODO: use device discoverability request through GO */
3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dev->dialog_token++;
3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (dev->dialog_token == 0)
3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		dev->dialog_token = 1;
3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	req = p2p_build_prov_disc_req(p2p, dev->dialog_token,
3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      dev->req_config_methods,
3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      join ? dev : NULL);
3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (req == NULL)
3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	p2p->pending_action_state = P2P_PENDING_PD;
3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    p2p->cfg->dev_addr, dev->info.p2p_device_addr,
3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    wpabuf_head(req), wpabuf_len(req), 200) < 0) {
3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			"P2P: Failed to send Action frame");
3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(req);
3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
34075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	os_memcpy(p2p->pending_pd_devaddr, dev->info.p2p_device_addr, ETH_ALEN);
34175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(req);
3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      u16 config_methods, int join)
3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct p2p_device *dev;
3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dev = p2p_get_device(p2p, peer_addr);
3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (dev == NULL)
3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		dev = p2p_get_device_interface(p2p, peer_addr);
3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Provision "
3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			"Discovery Request destination " MACSTR
3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			" not yet known", MAC2STR(peer_addr));
3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Provision Discovery "
3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		"Request with " MACSTR " (config methods 0x%x)",
3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		MAC2STR(peer_addr), config_methods);
3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (config_methods == 0)
3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dev->req_config_methods = config_methods;
3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (join)
3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		dev->flags |= P2P_DEV_PD_FOR_JOIN;
3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		dev->flags &= ~P2P_DEV_PD_FOR_JOIN;
3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (p2p->go_neg_peer ||
3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    (p2p->state != P2P_IDLE && p2p->state != P2P_SEARCH &&
3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	     p2p->state != P2P_LISTEN_ONLY)) {
3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Busy with other "
3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			"operations; postpone Provision Discovery Request "
3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			"with " MACSTR " (config methods 0x%x)",
3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			MAC2STR(peer_addr), config_methods);
3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
38475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	/*
38575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	 * We use the join param as a cue to differentiate between user
38675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	 * initiated PD request and one issued during finds (internal).
38775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	 */
38875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	p2p->user_initiated_pd = !join;
38975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
39075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	/* Also set some retries to attempt in case of IDLE state */
39175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	if (p2p->user_initiated_pd && p2p->state == P2P_IDLE)
39275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		p2p->pd_retries = MAX_PROV_DISC_REQ_RETRIES;
39375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return p2p_send_prov_disc_req(p2p, dev, join);
3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
39675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
39775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
39875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinenvoid p2p_reset_pending_pd(struct p2p_data *p2p)
39975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen{
40075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	p2p->user_initiated_pd = 0;
40175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
40275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	p2p->pd_retries = 0;
40375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen}
404