1e5b75505Sopenharmony_ci/*
2e5b75505Sopenharmony_ci * Wi-Fi Direct - P2P module
3e5b75505Sopenharmony_ci * Copyright (c) 2009-2010, Atheros Communications
4e5b75505Sopenharmony_ci *
5e5b75505Sopenharmony_ci * This software may be distributed under the terms of the BSD license.
6e5b75505Sopenharmony_ci * See README for more details.
7e5b75505Sopenharmony_ci */
8e5b75505Sopenharmony_ci
9e5b75505Sopenharmony_ci#include "includes.h"
10e5b75505Sopenharmony_ci
11e5b75505Sopenharmony_ci#include "common.h"
12e5b75505Sopenharmony_ci#include "eloop.h"
13e5b75505Sopenharmony_ci#include "common/defs.h"
14e5b75505Sopenharmony_ci#include "common/ieee802_11_defs.h"
15e5b75505Sopenharmony_ci#include "common/ieee802_11_common.h"
16e5b75505Sopenharmony_ci#include "common/wpa_ctrl.h"
17e5b75505Sopenharmony_ci#include "crypto/sha256.h"
18e5b75505Sopenharmony_ci#include "crypto/crypto.h"
19e5b75505Sopenharmony_ci#include "wps/wps_i.h"
20e5b75505Sopenharmony_ci#include "p2p_i.h"
21e5b75505Sopenharmony_ci#include "p2p.h"
22e5b75505Sopenharmony_ci
23e5b75505Sopenharmony_ci
24e5b75505Sopenharmony_cistatic void p2p_state_timeout(void *eloop_ctx, void *timeout_ctx);
25e5b75505Sopenharmony_cistatic void p2p_device_free(struct p2p_data *p2p, struct p2p_device *dev);
26e5b75505Sopenharmony_cistatic void p2p_process_presence_req(struct p2p_data *p2p, const u8 *da,
27e5b75505Sopenharmony_ci				     const u8 *sa, const u8 *data, size_t len,
28e5b75505Sopenharmony_ci				     int rx_freq);
29e5b75505Sopenharmony_cistatic void p2p_process_presence_resp(struct p2p_data *p2p, const u8 *da,
30e5b75505Sopenharmony_ci				      const u8 *sa, const u8 *data,
31e5b75505Sopenharmony_ci				      size_t len);
32e5b75505Sopenharmony_cistatic void p2p_ext_listen_timeout(void *eloop_ctx, void *timeout_ctx);
33e5b75505Sopenharmony_cistatic void p2p_scan_timeout(void *eloop_ctx, void *timeout_ctx);
34e5b75505Sopenharmony_ci
35e5b75505Sopenharmony_ci
36e5b75505Sopenharmony_ci/*
37e5b75505Sopenharmony_ci * p2p_scan recovery timeout
38e5b75505Sopenharmony_ci *
39e5b75505Sopenharmony_ci * Many drivers are using 30 second timeout on scan results. Allow a bit larger
40e5b75505Sopenharmony_ci * timeout for this to avoid hitting P2P timeout unnecessarily.
41e5b75505Sopenharmony_ci */
42e5b75505Sopenharmony_ci#define P2P_SCAN_TIMEOUT 35
43e5b75505Sopenharmony_ci
44e5b75505Sopenharmony_ci/**
45e5b75505Sopenharmony_ci * P2P_PEER_EXPIRATION_AGE - Number of seconds after which inactive peer
46e5b75505Sopenharmony_ci * entries will be removed
47e5b75505Sopenharmony_ci */
48e5b75505Sopenharmony_ci#ifndef P2P_PEER_EXPIRATION_AGE
49e5b75505Sopenharmony_ci#define P2P_PEER_EXPIRATION_AGE 60
50e5b75505Sopenharmony_ci#endif /* P2P_PEER_EXPIRATION_AGE */
51e5b75505Sopenharmony_ci
52e5b75505Sopenharmony_ci
53e5b75505Sopenharmony_civoid p2p_expire_peers(struct p2p_data *p2p)
54e5b75505Sopenharmony_ci{
55e5b75505Sopenharmony_ci	struct p2p_device *dev, *n;
56e5b75505Sopenharmony_ci	struct os_reltime now;
57e5b75505Sopenharmony_ci	size_t i;
58e5b75505Sopenharmony_ci
59e5b75505Sopenharmony_ci	os_get_reltime(&now);
60e5b75505Sopenharmony_ci	dl_list_for_each_safe(dev, n, &p2p->devices, struct p2p_device, list) {
61e5b75505Sopenharmony_ci		if (dev->last_seen.sec + P2P_PEER_EXPIRATION_AGE >= now.sec)
62e5b75505Sopenharmony_ci			continue;
63e5b75505Sopenharmony_ci
64e5b75505Sopenharmony_ci		if (dev == p2p->go_neg_peer) {
65e5b75505Sopenharmony_ci			/*
66e5b75505Sopenharmony_ci			 * GO Negotiation is in progress with the peer, so
67e5b75505Sopenharmony_ci			 * don't expire the peer entry until GO Negotiation
68e5b75505Sopenharmony_ci			 * fails or times out.
69e5b75505Sopenharmony_ci			 */
70e5b75505Sopenharmony_ci			continue;
71e5b75505Sopenharmony_ci		}
72e5b75505Sopenharmony_ci
73e5b75505Sopenharmony_ci		if (p2p->cfg->go_connected &&
74e5b75505Sopenharmony_ci		    p2p->cfg->go_connected(p2p->cfg->cb_ctx,
75e5b75505Sopenharmony_ci					   dev->info.p2p_device_addr)) {
76e5b75505Sopenharmony_ci			/*
77e5b75505Sopenharmony_ci			 * We are connected as a client to a group in which the
78e5b75505Sopenharmony_ci			 * peer is the GO, so do not expire the peer entry.
79e5b75505Sopenharmony_ci			 */
80e5b75505Sopenharmony_ci			os_get_reltime(&dev->last_seen);
81e5b75505Sopenharmony_ci			continue;
82e5b75505Sopenharmony_ci		}
83e5b75505Sopenharmony_ci
84e5b75505Sopenharmony_ci		for (i = 0; i < p2p->num_groups; i++) {
85e5b75505Sopenharmony_ci			if (p2p_group_is_client_connected(
86e5b75505Sopenharmony_ci				    p2p->groups[i], dev->info.p2p_device_addr))
87e5b75505Sopenharmony_ci				break;
88e5b75505Sopenharmony_ci		}
89e5b75505Sopenharmony_ci		if (i < p2p->num_groups) {
90e5b75505Sopenharmony_ci			/*
91e5b75505Sopenharmony_ci			 * The peer is connected as a client in a group where
92e5b75505Sopenharmony_ci			 * we are the GO, so do not expire the peer entry.
93e5b75505Sopenharmony_ci			 */
94e5b75505Sopenharmony_ci			os_get_reltime(&dev->last_seen);
95e5b75505Sopenharmony_ci			continue;
96e5b75505Sopenharmony_ci		}
97e5b75505Sopenharmony_ci
98e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Expiring old peer entry " MACSTR,
99e5b75505Sopenharmony_ci			MAC2STR(dev->info.p2p_device_addr));
100e5b75505Sopenharmony_ci		dl_list_del(&dev->list);
101e5b75505Sopenharmony_ci		p2p_device_free(p2p, dev);
102e5b75505Sopenharmony_ci	}
103e5b75505Sopenharmony_ci}
104e5b75505Sopenharmony_ci
105e5b75505Sopenharmony_ci
106e5b75505Sopenharmony_cistatic const char * p2p_state_txt(int state)
107e5b75505Sopenharmony_ci{
108e5b75505Sopenharmony_ci	switch (state) {
109e5b75505Sopenharmony_ci	case P2P_IDLE:
110e5b75505Sopenharmony_ci		return "IDLE";
111e5b75505Sopenharmony_ci	case P2P_SEARCH:
112e5b75505Sopenharmony_ci		return "SEARCH";
113e5b75505Sopenharmony_ci	case P2P_CONNECT:
114e5b75505Sopenharmony_ci		return "CONNECT";
115e5b75505Sopenharmony_ci	case P2P_CONNECT_LISTEN:
116e5b75505Sopenharmony_ci		return "CONNECT_LISTEN";
117e5b75505Sopenharmony_ci	case P2P_GO_NEG:
118e5b75505Sopenharmony_ci		return "GO_NEG";
119e5b75505Sopenharmony_ci	case P2P_LISTEN_ONLY:
120e5b75505Sopenharmony_ci		return "LISTEN_ONLY";
121e5b75505Sopenharmony_ci	case P2P_WAIT_PEER_CONNECT:
122e5b75505Sopenharmony_ci		return "WAIT_PEER_CONNECT";
123e5b75505Sopenharmony_ci	case P2P_WAIT_PEER_IDLE:
124e5b75505Sopenharmony_ci		return "WAIT_PEER_IDLE";
125e5b75505Sopenharmony_ci	case P2P_SD_DURING_FIND:
126e5b75505Sopenharmony_ci		return "SD_DURING_FIND";
127e5b75505Sopenharmony_ci	case P2P_PROVISIONING:
128e5b75505Sopenharmony_ci		return "PROVISIONING";
129e5b75505Sopenharmony_ci	case P2P_PD_DURING_FIND:
130e5b75505Sopenharmony_ci		return "PD_DURING_FIND";
131e5b75505Sopenharmony_ci	case P2P_INVITE:
132e5b75505Sopenharmony_ci		return "INVITE";
133e5b75505Sopenharmony_ci	case P2P_INVITE_LISTEN:
134e5b75505Sopenharmony_ci		return "INVITE_LISTEN";
135e5b75505Sopenharmony_ci	default:
136e5b75505Sopenharmony_ci		return "?";
137e5b75505Sopenharmony_ci	}
138e5b75505Sopenharmony_ci}
139e5b75505Sopenharmony_ci
140e5b75505Sopenharmony_ci
141e5b75505Sopenharmony_ciconst char * p2p_get_state_txt(struct p2p_data *p2p)
142e5b75505Sopenharmony_ci{
143e5b75505Sopenharmony_ci	return p2p_state_txt(p2p->state);
144e5b75505Sopenharmony_ci}
145e5b75505Sopenharmony_ci
146e5b75505Sopenharmony_ci
147e5b75505Sopenharmony_cistruct p2ps_advertisement * p2p_get_p2ps_adv_list(struct p2p_data *p2p)
148e5b75505Sopenharmony_ci{
149e5b75505Sopenharmony_ci	return p2p ? p2p->p2ps_adv_list : NULL;
150e5b75505Sopenharmony_ci}
151e5b75505Sopenharmony_ci
152e5b75505Sopenharmony_ci
153e5b75505Sopenharmony_civoid p2p_set_intended_addr(struct p2p_data *p2p, const u8 *intended_addr)
154e5b75505Sopenharmony_ci{
155e5b75505Sopenharmony_ci	if (p2p && intended_addr)
156e5b75505Sopenharmony_ci		os_memcpy(p2p->intended_addr, intended_addr, ETH_ALEN);
157e5b75505Sopenharmony_ci}
158e5b75505Sopenharmony_ci
159e5b75505Sopenharmony_ci
160e5b75505Sopenharmony_ciu16 p2p_get_provisioning_info(struct p2p_data *p2p, const u8 *addr)
161e5b75505Sopenharmony_ci{
162e5b75505Sopenharmony_ci	struct p2p_device *dev = NULL;
163e5b75505Sopenharmony_ci
164e5b75505Sopenharmony_ci	if (!addr || !p2p)
165e5b75505Sopenharmony_ci		return 0;
166e5b75505Sopenharmony_ci
167e5b75505Sopenharmony_ci	dev = p2p_get_device(p2p, addr);
168e5b75505Sopenharmony_ci	if (dev)
169e5b75505Sopenharmony_ci		return dev->wps_prov_info;
170e5b75505Sopenharmony_ci	else
171e5b75505Sopenharmony_ci		return 0;
172e5b75505Sopenharmony_ci}
173e5b75505Sopenharmony_ci
174e5b75505Sopenharmony_ci
175e5b75505Sopenharmony_civoid p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *addr)
176e5b75505Sopenharmony_ci{
177e5b75505Sopenharmony_ci	struct p2p_device *dev = NULL;
178e5b75505Sopenharmony_ci
179e5b75505Sopenharmony_ci	if (!addr || !p2p)
180e5b75505Sopenharmony_ci		return;
181e5b75505Sopenharmony_ci
182e5b75505Sopenharmony_ci	dev = p2p_get_device(p2p, addr);
183e5b75505Sopenharmony_ci	if (dev)
184e5b75505Sopenharmony_ci		dev->wps_prov_info = 0;
185e5b75505Sopenharmony_ci}
186e5b75505Sopenharmony_ci
187e5b75505Sopenharmony_ci
188e5b75505Sopenharmony_civoid p2p_set_state(struct p2p_data *p2p, int new_state)
189e5b75505Sopenharmony_ci{
190e5b75505Sopenharmony_ci	p2p_dbg(p2p, "State %s -> %s",
191e5b75505Sopenharmony_ci		p2p_state_txt(p2p->state), p2p_state_txt(new_state));
192e5b75505Sopenharmony_ci	p2p->state = new_state;
193e5b75505Sopenharmony_ci
194e5b75505Sopenharmony_ci	if (new_state == P2P_IDLE && p2p->pending_channel) {
195e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Apply change in listen channel");
196e5b75505Sopenharmony_ci		p2p->cfg->reg_class = p2p->pending_reg_class;
197e5b75505Sopenharmony_ci		p2p->cfg->channel = p2p->pending_channel;
198e5b75505Sopenharmony_ci		p2p->pending_reg_class = 0;
199e5b75505Sopenharmony_ci		p2p->pending_channel = 0;
200e5b75505Sopenharmony_ci	}
201e5b75505Sopenharmony_ci}
202e5b75505Sopenharmony_ci
203e5b75505Sopenharmony_ci
204e5b75505Sopenharmony_civoid p2p_set_timeout(struct p2p_data *p2p, unsigned int sec, unsigned int usec)
205e5b75505Sopenharmony_ci{
206e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Set timeout (state=%s): %u.%06u sec",
207e5b75505Sopenharmony_ci		p2p_state_txt(p2p->state), sec, usec);
208e5b75505Sopenharmony_ci	eloop_cancel_timeout(p2p_state_timeout, p2p, NULL);
209e5b75505Sopenharmony_ci	eloop_register_timeout(sec, usec, p2p_state_timeout, p2p, NULL);
210e5b75505Sopenharmony_ci}
211e5b75505Sopenharmony_ci
212e5b75505Sopenharmony_ci
213e5b75505Sopenharmony_civoid p2p_clear_timeout(struct p2p_data *p2p)
214e5b75505Sopenharmony_ci{
215e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Clear timeout (state=%s)", p2p_state_txt(p2p->state));
216e5b75505Sopenharmony_ci	eloop_cancel_timeout(p2p_state_timeout, p2p, NULL);
217e5b75505Sopenharmony_ci}
218e5b75505Sopenharmony_ci
219e5b75505Sopenharmony_ci
220e5b75505Sopenharmony_civoid p2p_go_neg_failed(struct p2p_data *p2p, int status)
221e5b75505Sopenharmony_ci{
222e5b75505Sopenharmony_ci	struct p2p_go_neg_results res;
223e5b75505Sopenharmony_ci	struct p2p_device *peer = p2p->go_neg_peer;
224e5b75505Sopenharmony_ci
225e5b75505Sopenharmony_ci	if (!peer)
226e5b75505Sopenharmony_ci		return;
227e5b75505Sopenharmony_ci
228e5b75505Sopenharmony_ci	eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p, NULL);
229e5b75505Sopenharmony_ci	if (p2p->state != P2P_SEARCH) {
230e5b75505Sopenharmony_ci		/*
231e5b75505Sopenharmony_ci		 * Clear timeouts related to GO Negotiation if no new p2p_find
232e5b75505Sopenharmony_ci		 * has been started.
233e5b75505Sopenharmony_ci		 */
234e5b75505Sopenharmony_ci		p2p_clear_timeout(p2p);
235e5b75505Sopenharmony_ci		p2p_set_state(p2p, P2P_IDLE);
236e5b75505Sopenharmony_ci	}
237e5b75505Sopenharmony_ci
238e5b75505Sopenharmony_ci	peer->flags &= ~P2P_DEV_PEER_WAITING_RESPONSE;
239e5b75505Sopenharmony_ci	peer->wps_method = WPS_NOT_READY;
240e5b75505Sopenharmony_ci	peer->oob_pw_id = 0;
241e5b75505Sopenharmony_ci	wpabuf_free(peer->go_neg_conf);
242e5b75505Sopenharmony_ci	peer->go_neg_conf = NULL;
243e5b75505Sopenharmony_ci	p2p->go_neg_peer = NULL;
244e5b75505Sopenharmony_ci
245e5b75505Sopenharmony_ci	os_memset(&res, 0, sizeof(res));
246e5b75505Sopenharmony_ci	res.status = status;
247e5b75505Sopenharmony_ci	os_memcpy(res.peer_device_addr, peer->info.p2p_device_addr, ETH_ALEN);
248e5b75505Sopenharmony_ci	os_memcpy(res.peer_interface_addr, peer->intended_addr, ETH_ALEN);
249e5b75505Sopenharmony_ci	p2p->cfg->go_neg_completed(p2p->cfg->cb_ctx, &res);
250e5b75505Sopenharmony_ci}
251e5b75505Sopenharmony_ci
252e5b75505Sopenharmony_ci
253e5b75505Sopenharmony_cistatic void p2p_listen_in_find(struct p2p_data *p2p, int dev_disc)
254e5b75505Sopenharmony_ci{
255e5b75505Sopenharmony_ci	unsigned int r, tu;
256e5b75505Sopenharmony_ci	int freq;
257e5b75505Sopenharmony_ci	struct wpabuf *ies;
258e5b75505Sopenharmony_ci
259e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Starting short listen state (state=%s)",
260e5b75505Sopenharmony_ci		p2p_state_txt(p2p->state));
261e5b75505Sopenharmony_ci
262e5b75505Sopenharmony_ci	if (p2p->pending_listen_freq) {
263e5b75505Sopenharmony_ci		/* We have a pending p2p_listen request */
264e5b75505Sopenharmony_ci		p2p_dbg(p2p, "p2p_listen command pending already");
265e5b75505Sopenharmony_ci		return;
266e5b75505Sopenharmony_ci	}
267e5b75505Sopenharmony_ci
268e5b75505Sopenharmony_ci	freq = p2p_channel_to_freq(p2p->cfg->reg_class, p2p->cfg->channel);
269e5b75505Sopenharmony_ci	if (freq < 0) {
270e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Unknown regulatory class/channel");
271e5b75505Sopenharmony_ci		return;
272e5b75505Sopenharmony_ci	}
273e5b75505Sopenharmony_ci
274e5b75505Sopenharmony_ci	if (os_get_random((u8 *) &r, sizeof(r)) < 0)
275e5b75505Sopenharmony_ci		r = 0;
276e5b75505Sopenharmony_ci	tu = (r % ((p2p->max_disc_int - p2p->min_disc_int) + 1) +
277e5b75505Sopenharmony_ci	      p2p->min_disc_int) * 100;
278e5b75505Sopenharmony_ci	if (p2p->max_disc_tu >= 0 && tu > (unsigned int) p2p->max_disc_tu)
279e5b75505Sopenharmony_ci		tu = p2p->max_disc_tu;
280e5b75505Sopenharmony_ci	if (!dev_disc && tu < 100)
281e5b75505Sopenharmony_ci		tu = 100; /* Need to wait in non-device discovery use cases */
282e5b75505Sopenharmony_ci	if (p2p->cfg->max_listen && 1024 * tu / 1000 > p2p->cfg->max_listen)
283e5b75505Sopenharmony_ci		tu = p2p->cfg->max_listen * 1000 / 1024;
284e5b75505Sopenharmony_ci
285e5b75505Sopenharmony_ci	if (tu == 0) {
286e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Skip listen state since duration was 0 TU");
287e5b75505Sopenharmony_ci		p2p_set_timeout(p2p, 0, 0);
288e5b75505Sopenharmony_ci		return;
289e5b75505Sopenharmony_ci	}
290e5b75505Sopenharmony_ci
291e5b75505Sopenharmony_ci	ies = p2p_build_probe_resp_ies(p2p, NULL, 0);
292e5b75505Sopenharmony_ci	if (ies == NULL)
293e5b75505Sopenharmony_ci		return;
294e5b75505Sopenharmony_ci
295e5b75505Sopenharmony_ci	p2p->pending_listen_freq = freq;
296e5b75505Sopenharmony_ci	p2p->pending_listen_sec = 0;
297e5b75505Sopenharmony_ci	p2p->pending_listen_usec = 1024 * tu;
298e5b75505Sopenharmony_ci
299e5b75505Sopenharmony_ci	if (p2p->cfg->start_listen(p2p->cfg->cb_ctx, freq, 1024 * tu / 1000,
300e5b75505Sopenharmony_ci		    ies) < 0) {
301e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Failed to start listen mode");
302e5b75505Sopenharmony_ci		p2p->pending_listen_freq = 0;
303e5b75505Sopenharmony_ci	}
304e5b75505Sopenharmony_ci	wpabuf_free(ies);
305e5b75505Sopenharmony_ci}
306e5b75505Sopenharmony_ci
307e5b75505Sopenharmony_ci
308e5b75505Sopenharmony_ciint p2p_listen(struct p2p_data *p2p, unsigned int timeout)
309e5b75505Sopenharmony_ci{
310e5b75505Sopenharmony_ci	int freq;
311e5b75505Sopenharmony_ci	struct wpabuf *ies;
312e5b75505Sopenharmony_ci
313e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Going to listen(only) state");
314e5b75505Sopenharmony_ci
315e5b75505Sopenharmony_ci	if (p2p->pending_listen_freq) {
316e5b75505Sopenharmony_ci		/* We have a pending p2p_listen request */
317e5b75505Sopenharmony_ci		p2p_dbg(p2p, "p2p_listen command pending already");
318e5b75505Sopenharmony_ci		return -1;
319e5b75505Sopenharmony_ci	}
320e5b75505Sopenharmony_ci
321e5b75505Sopenharmony_ci	freq = p2p_channel_to_freq(p2p->cfg->reg_class, p2p->cfg->channel);
322e5b75505Sopenharmony_ci	if (freq < 0) {
323e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Unknown regulatory class/channel");
324e5b75505Sopenharmony_ci		return -1;
325e5b75505Sopenharmony_ci	}
326e5b75505Sopenharmony_ci
327e5b75505Sopenharmony_ci	p2p->pending_listen_sec = timeout / 1000;
328e5b75505Sopenharmony_ci	p2p->pending_listen_usec = (timeout % 1000) * 1000;
329e5b75505Sopenharmony_ci
330e5b75505Sopenharmony_ci	if (p2p->p2p_scan_running) {
331e5b75505Sopenharmony_ci		if (p2p->start_after_scan == P2P_AFTER_SCAN_CONNECT) {
332e5b75505Sopenharmony_ci			p2p_dbg(p2p, "p2p_scan running - connect is already pending - skip listen");
333e5b75505Sopenharmony_ci			return 0;
334e5b75505Sopenharmony_ci		}
335e5b75505Sopenharmony_ci		p2p_dbg(p2p, "p2p_scan running - delay start of listen state");
336e5b75505Sopenharmony_ci		p2p->start_after_scan = P2P_AFTER_SCAN_LISTEN;
337e5b75505Sopenharmony_ci		return 0;
338e5b75505Sopenharmony_ci	}
339e5b75505Sopenharmony_ci
340e5b75505Sopenharmony_ci	ies = p2p_build_probe_resp_ies(p2p, NULL, 0);
341e5b75505Sopenharmony_ci	if (ies == NULL)
342e5b75505Sopenharmony_ci		return -1;
343e5b75505Sopenharmony_ci
344e5b75505Sopenharmony_ci	p2p->pending_listen_freq = freq;
345e5b75505Sopenharmony_ci
346e5b75505Sopenharmony_ci	if (p2p->cfg->start_listen(p2p->cfg->cb_ctx, freq, timeout, ies) < 0) {
347e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Failed to start listen mode");
348e5b75505Sopenharmony_ci		p2p->pending_listen_freq = 0;
349e5b75505Sopenharmony_ci		wpabuf_free(ies);
350e5b75505Sopenharmony_ci		return -1;
351e5b75505Sopenharmony_ci	}
352e5b75505Sopenharmony_ci	wpabuf_free(ies);
353e5b75505Sopenharmony_ci
354e5b75505Sopenharmony_ci	p2p_set_state(p2p, P2P_LISTEN_ONLY);
355e5b75505Sopenharmony_ci
356e5b75505Sopenharmony_ci	return 0;
357e5b75505Sopenharmony_ci}
358e5b75505Sopenharmony_ci
359e5b75505Sopenharmony_ci
360e5b75505Sopenharmony_cistatic void p2p_device_clear_reported(struct p2p_data *p2p)
361e5b75505Sopenharmony_ci{
362e5b75505Sopenharmony_ci	struct p2p_device *dev;
363e5b75505Sopenharmony_ci	dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
364e5b75505Sopenharmony_ci		dev->flags &= ~P2P_DEV_REPORTED;
365e5b75505Sopenharmony_ci		dev->sd_reqs = 0;
366e5b75505Sopenharmony_ci	}
367e5b75505Sopenharmony_ci}
368e5b75505Sopenharmony_ci
369e5b75505Sopenharmony_ci
370e5b75505Sopenharmony_ci/**
371e5b75505Sopenharmony_ci * p2p_get_device - Fetch a peer entry
372e5b75505Sopenharmony_ci * @p2p: P2P module context from p2p_init()
373e5b75505Sopenharmony_ci * @addr: P2P Device Address of the peer
374e5b75505Sopenharmony_ci * Returns: Pointer to the device entry or %NULL if not found
375e5b75505Sopenharmony_ci */
376e5b75505Sopenharmony_cistruct p2p_device * p2p_get_device(struct p2p_data *p2p, const u8 *addr)
377e5b75505Sopenharmony_ci{
378e5b75505Sopenharmony_ci	struct p2p_device *dev;
379e5b75505Sopenharmony_ci	dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
380e5b75505Sopenharmony_ci		if (os_memcmp(dev->info.p2p_device_addr, addr, ETH_ALEN) == 0)
381e5b75505Sopenharmony_ci			return dev;
382e5b75505Sopenharmony_ci	}
383e5b75505Sopenharmony_ci	return NULL;
384e5b75505Sopenharmony_ci}
385e5b75505Sopenharmony_ci
386e5b75505Sopenharmony_ci
387e5b75505Sopenharmony_ci/**
388e5b75505Sopenharmony_ci * p2p_get_device_interface - Fetch a peer entry based on P2P Interface Address
389e5b75505Sopenharmony_ci * @p2p: P2P module context from p2p_init()
390e5b75505Sopenharmony_ci * @addr: P2P Interface Address of the peer
391e5b75505Sopenharmony_ci * Returns: Pointer to the device entry or %NULL if not found
392e5b75505Sopenharmony_ci */
393e5b75505Sopenharmony_cistruct p2p_device * p2p_get_device_interface(struct p2p_data *p2p,
394e5b75505Sopenharmony_ci					     const u8 *addr)
395e5b75505Sopenharmony_ci{
396e5b75505Sopenharmony_ci	struct p2p_device *dev;
397e5b75505Sopenharmony_ci	dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
398e5b75505Sopenharmony_ci		if (os_memcmp(dev->interface_addr, addr, ETH_ALEN) == 0)
399e5b75505Sopenharmony_ci			return dev;
400e5b75505Sopenharmony_ci	}
401e5b75505Sopenharmony_ci	return NULL;
402e5b75505Sopenharmony_ci}
403e5b75505Sopenharmony_ci
404e5b75505Sopenharmony_ci
405e5b75505Sopenharmony_ci/**
406e5b75505Sopenharmony_ci * p2p_create_device - Create a peer entry
407e5b75505Sopenharmony_ci * @p2p: P2P module context from p2p_init()
408e5b75505Sopenharmony_ci * @addr: P2P Device Address of the peer
409e5b75505Sopenharmony_ci * Returns: Pointer to the device entry or %NULL on failure
410e5b75505Sopenharmony_ci *
411e5b75505Sopenharmony_ci * If there is already an entry for the peer, it will be returned instead of
412e5b75505Sopenharmony_ci * creating a new one.
413e5b75505Sopenharmony_ci */
414e5b75505Sopenharmony_cistatic struct p2p_device * p2p_create_device(struct p2p_data *p2p,
415e5b75505Sopenharmony_ci					     const u8 *addr)
416e5b75505Sopenharmony_ci{
417e5b75505Sopenharmony_ci	struct p2p_device *dev, *oldest = NULL;
418e5b75505Sopenharmony_ci	size_t count = 0;
419e5b75505Sopenharmony_ci
420e5b75505Sopenharmony_ci	dev = p2p_get_device(p2p, addr);
421e5b75505Sopenharmony_ci	if (dev)
422e5b75505Sopenharmony_ci		return dev;
423e5b75505Sopenharmony_ci
424e5b75505Sopenharmony_ci	dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
425e5b75505Sopenharmony_ci		count++;
426e5b75505Sopenharmony_ci		if (oldest == NULL ||
427e5b75505Sopenharmony_ci		    os_reltime_before(&dev->last_seen, &oldest->last_seen))
428e5b75505Sopenharmony_ci			oldest = dev;
429e5b75505Sopenharmony_ci	}
430e5b75505Sopenharmony_ci	if (count + 1 > p2p->cfg->max_peers && oldest) {
431e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Remove oldest peer entry to make room for a new peer");
432e5b75505Sopenharmony_ci		dl_list_del(&oldest->list);
433e5b75505Sopenharmony_ci		p2p_device_free(p2p, oldest);
434e5b75505Sopenharmony_ci	}
435e5b75505Sopenharmony_ci
436e5b75505Sopenharmony_ci	dev = os_zalloc(sizeof(*dev));
437e5b75505Sopenharmony_ci	if (dev == NULL)
438e5b75505Sopenharmony_ci		return NULL;
439e5b75505Sopenharmony_ci	dl_list_add(&p2p->devices, &dev->list);
440e5b75505Sopenharmony_ci	os_memcpy(dev->info.p2p_device_addr, addr, ETH_ALEN);
441e5b75505Sopenharmony_ci
442e5b75505Sopenharmony_ci	return dev;
443e5b75505Sopenharmony_ci}
444e5b75505Sopenharmony_ci
445e5b75505Sopenharmony_ci
446e5b75505Sopenharmony_cistatic void p2p_copy_client_info(struct p2p_device *dev,
447e5b75505Sopenharmony_ci				 struct p2p_client_info *cli)
448e5b75505Sopenharmony_ci{
449e5b75505Sopenharmony_ci	p2p_copy_filter_devname(dev->info.device_name,
450e5b75505Sopenharmony_ci				sizeof(dev->info.device_name),
451e5b75505Sopenharmony_ci				cli->dev_name, cli->dev_name_len);
452e5b75505Sopenharmony_ci	dev->info.dev_capab = cli->dev_capab;
453e5b75505Sopenharmony_ci	dev->info.config_methods = cli->config_methods;
454e5b75505Sopenharmony_ci	os_memcpy(dev->info.pri_dev_type, cli->pri_dev_type, 8);
455e5b75505Sopenharmony_ci	dev->info.wps_sec_dev_type_list_len = 8 * cli->num_sec_dev_types;
456e5b75505Sopenharmony_ci	if (dev->info.wps_sec_dev_type_list_len > WPS_SEC_DEV_TYPE_MAX_LEN)
457e5b75505Sopenharmony_ci		dev->info.wps_sec_dev_type_list_len = WPS_SEC_DEV_TYPE_MAX_LEN;
458e5b75505Sopenharmony_ci	os_memcpy(dev->info.wps_sec_dev_type_list, cli->sec_dev_types,
459e5b75505Sopenharmony_ci		  dev->info.wps_sec_dev_type_list_len);
460e5b75505Sopenharmony_ci}
461e5b75505Sopenharmony_ci
462e5b75505Sopenharmony_ci
463e5b75505Sopenharmony_cistatic int p2p_add_group_clients(struct p2p_data *p2p, const u8 *go_dev_addr,
464e5b75505Sopenharmony_ci				 const u8 *go_interface_addr, int freq,
465e5b75505Sopenharmony_ci				 const u8 *gi, size_t gi_len,
466e5b75505Sopenharmony_ci				 struct os_reltime *rx_time)
467e5b75505Sopenharmony_ci{
468e5b75505Sopenharmony_ci	struct p2p_group_info info;
469e5b75505Sopenharmony_ci	size_t c;
470e5b75505Sopenharmony_ci	struct p2p_device *dev;
471e5b75505Sopenharmony_ci
472e5b75505Sopenharmony_ci	if (gi == NULL)
473e5b75505Sopenharmony_ci		return 0;
474e5b75505Sopenharmony_ci
475e5b75505Sopenharmony_ci	if (p2p_group_info_parse(gi, gi_len, &info) < 0)
476e5b75505Sopenharmony_ci		return -1;
477e5b75505Sopenharmony_ci
478e5b75505Sopenharmony_ci	/*
479e5b75505Sopenharmony_ci	 * Clear old data for this group; if the devices are still in the
480e5b75505Sopenharmony_ci	 * group, the information will be restored in the loop following this.
481e5b75505Sopenharmony_ci	 */
482e5b75505Sopenharmony_ci	dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
483e5b75505Sopenharmony_ci		if (os_memcmp(dev->member_in_go_iface, go_interface_addr,
484e5b75505Sopenharmony_ci			      ETH_ALEN) == 0) {
485e5b75505Sopenharmony_ci			os_memset(dev->member_in_go_iface, 0, ETH_ALEN);
486e5b75505Sopenharmony_ci			os_memset(dev->member_in_go_dev, 0, ETH_ALEN);
487e5b75505Sopenharmony_ci		}
488e5b75505Sopenharmony_ci	}
489e5b75505Sopenharmony_ci
490e5b75505Sopenharmony_ci	for (c = 0; c < info.num_clients; c++) {
491e5b75505Sopenharmony_ci		struct p2p_client_info *cli = &info.client[c];
492e5b75505Sopenharmony_ci		if (os_memcmp(cli->p2p_device_addr, p2p->cfg->dev_addr,
493e5b75505Sopenharmony_ci			      ETH_ALEN) == 0)
494e5b75505Sopenharmony_ci			continue; /* ignore our own entry */
495e5b75505Sopenharmony_ci		dev = p2p_get_device(p2p, cli->p2p_device_addr);
496e5b75505Sopenharmony_ci		if (dev) {
497e5b75505Sopenharmony_ci			if (dev->flags & (P2P_DEV_GROUP_CLIENT_ONLY |
498e5b75505Sopenharmony_ci					  P2P_DEV_PROBE_REQ_ONLY)) {
499e5b75505Sopenharmony_ci				/*
500e5b75505Sopenharmony_ci				 * Update information since we have not
501e5b75505Sopenharmony_ci				 * received this directly from the client.
502e5b75505Sopenharmony_ci				 */
503e5b75505Sopenharmony_ci				p2p_copy_client_info(dev, cli);
504e5b75505Sopenharmony_ci			} else {
505e5b75505Sopenharmony_ci				/*
506e5b75505Sopenharmony_ci				 * Need to update P2P Client Discoverability
507e5b75505Sopenharmony_ci				 * flag since it is valid only in P2P Group
508e5b75505Sopenharmony_ci				 * Info attribute.
509e5b75505Sopenharmony_ci				 */
510e5b75505Sopenharmony_ci				dev->info.dev_capab &=
511e5b75505Sopenharmony_ci					~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
512e5b75505Sopenharmony_ci				dev->info.dev_capab |=
513e5b75505Sopenharmony_ci					cli->dev_capab &
514e5b75505Sopenharmony_ci					P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
515e5b75505Sopenharmony_ci			}
516e5b75505Sopenharmony_ci			if (dev->flags & P2P_DEV_PROBE_REQ_ONLY) {
517e5b75505Sopenharmony_ci				dev->flags &= ~P2P_DEV_PROBE_REQ_ONLY;
518e5b75505Sopenharmony_ci			}
519e5b75505Sopenharmony_ci		} else {
520e5b75505Sopenharmony_ci			dev = p2p_create_device(p2p, cli->p2p_device_addr);
521e5b75505Sopenharmony_ci			if (dev == NULL)
522e5b75505Sopenharmony_ci				continue;
523e5b75505Sopenharmony_ci			dev->flags |= P2P_DEV_GROUP_CLIENT_ONLY;
524e5b75505Sopenharmony_ci			p2p_copy_client_info(dev, cli);
525e5b75505Sopenharmony_ci			dev->oper_freq = freq;
526e5b75505Sopenharmony_ci			p2p->cfg->dev_found(p2p->cfg->cb_ctx,
527e5b75505Sopenharmony_ci					    dev->info.p2p_device_addr,
528e5b75505Sopenharmony_ci					    &dev->info, 1);
529e5b75505Sopenharmony_ci			dev->flags |= P2P_DEV_REPORTED | P2P_DEV_REPORTED_ONCE;
530e5b75505Sopenharmony_ci		}
531e5b75505Sopenharmony_ci
532e5b75505Sopenharmony_ci		os_memcpy(dev->interface_addr, cli->p2p_interface_addr,
533e5b75505Sopenharmony_ci			  ETH_ALEN);
534e5b75505Sopenharmony_ci		os_memcpy(&dev->last_seen, rx_time, sizeof(struct os_reltime));
535e5b75505Sopenharmony_ci		os_memcpy(dev->member_in_go_dev, go_dev_addr, ETH_ALEN);
536e5b75505Sopenharmony_ci		os_memcpy(dev->member_in_go_iface, go_interface_addr,
537e5b75505Sopenharmony_ci			  ETH_ALEN);
538e5b75505Sopenharmony_ci		dev->flags |= P2P_DEV_LAST_SEEN_AS_GROUP_CLIENT;
539e5b75505Sopenharmony_ci	}
540e5b75505Sopenharmony_ci
541e5b75505Sopenharmony_ci	return 0;
542e5b75505Sopenharmony_ci}
543e5b75505Sopenharmony_ci
544e5b75505Sopenharmony_ci
545e5b75505Sopenharmony_cistatic void p2p_copy_wps_info(struct p2p_data *p2p, struct p2p_device *dev,
546e5b75505Sopenharmony_ci			      int probe_req, const struct p2p_message *msg)
547e5b75505Sopenharmony_ci{
548e5b75505Sopenharmony_ci	os_memcpy(dev->info.device_name, msg->device_name,
549e5b75505Sopenharmony_ci		  sizeof(dev->info.device_name));
550e5b75505Sopenharmony_ci
551e5b75505Sopenharmony_ci	if (msg->manufacturer &&
552e5b75505Sopenharmony_ci	    msg->manufacturer_len < sizeof(dev->info.manufacturer)) {
553e5b75505Sopenharmony_ci		os_memset(dev->info.manufacturer, 0,
554e5b75505Sopenharmony_ci			  sizeof(dev->info.manufacturer));
555e5b75505Sopenharmony_ci		os_memcpy(dev->info.manufacturer, msg->manufacturer,
556e5b75505Sopenharmony_ci			  msg->manufacturer_len);
557e5b75505Sopenharmony_ci	}
558e5b75505Sopenharmony_ci
559e5b75505Sopenharmony_ci	if (msg->model_name &&
560e5b75505Sopenharmony_ci	    msg->model_name_len < sizeof(dev->info.model_name)) {
561e5b75505Sopenharmony_ci		os_memset(dev->info.model_name, 0,
562e5b75505Sopenharmony_ci			  sizeof(dev->info.model_name));
563e5b75505Sopenharmony_ci		os_memcpy(dev->info.model_name, msg->model_name,
564e5b75505Sopenharmony_ci			  msg->model_name_len);
565e5b75505Sopenharmony_ci	}
566e5b75505Sopenharmony_ci
567e5b75505Sopenharmony_ci	if (msg->model_number &&
568e5b75505Sopenharmony_ci	    msg->model_number_len < sizeof(dev->info.model_number)) {
569e5b75505Sopenharmony_ci		os_memset(dev->info.model_number, 0,
570e5b75505Sopenharmony_ci			  sizeof(dev->info.model_number));
571e5b75505Sopenharmony_ci		os_memcpy(dev->info.model_number, msg->model_number,
572e5b75505Sopenharmony_ci			  msg->model_number_len);
573e5b75505Sopenharmony_ci	}
574e5b75505Sopenharmony_ci
575e5b75505Sopenharmony_ci	if (msg->serial_number &&
576e5b75505Sopenharmony_ci	    msg->serial_number_len < sizeof(dev->info.serial_number)) {
577e5b75505Sopenharmony_ci		os_memset(dev->info.serial_number, 0,
578e5b75505Sopenharmony_ci			  sizeof(dev->info.serial_number));
579e5b75505Sopenharmony_ci		os_memcpy(dev->info.serial_number, msg->serial_number,
580e5b75505Sopenharmony_ci			  msg->serial_number_len);
581e5b75505Sopenharmony_ci	}
582e5b75505Sopenharmony_ci
583e5b75505Sopenharmony_ci	if (msg->pri_dev_type)
584e5b75505Sopenharmony_ci		os_memcpy(dev->info.pri_dev_type, msg->pri_dev_type,
585e5b75505Sopenharmony_ci			  sizeof(dev->info.pri_dev_type));
586e5b75505Sopenharmony_ci	else if (msg->wps_pri_dev_type)
587e5b75505Sopenharmony_ci		os_memcpy(dev->info.pri_dev_type, msg->wps_pri_dev_type,
588e5b75505Sopenharmony_ci			  sizeof(dev->info.pri_dev_type));
589e5b75505Sopenharmony_ci
590e5b75505Sopenharmony_ci	if (msg->wps_sec_dev_type_list) {
591e5b75505Sopenharmony_ci		os_memcpy(dev->info.wps_sec_dev_type_list,
592e5b75505Sopenharmony_ci			  msg->wps_sec_dev_type_list,
593e5b75505Sopenharmony_ci			  msg->wps_sec_dev_type_list_len);
594e5b75505Sopenharmony_ci		dev->info.wps_sec_dev_type_list_len =
595e5b75505Sopenharmony_ci			msg->wps_sec_dev_type_list_len;
596e5b75505Sopenharmony_ci	}
597e5b75505Sopenharmony_ci
598e5b75505Sopenharmony_ci	if (msg->capability) {
599e5b75505Sopenharmony_ci		/*
600e5b75505Sopenharmony_ci		 * P2P Client Discoverability bit is reserved in all frames
601e5b75505Sopenharmony_ci		 * that use this function, so do not change its value here.
602e5b75505Sopenharmony_ci		 */
603e5b75505Sopenharmony_ci		dev->info.dev_capab &= P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
604e5b75505Sopenharmony_ci		dev->info.dev_capab |= msg->capability[0] &
605e5b75505Sopenharmony_ci			~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
606e5b75505Sopenharmony_ci		dev->info.group_capab = msg->capability[1];
607e5b75505Sopenharmony_ci	}
608e5b75505Sopenharmony_ci
609e5b75505Sopenharmony_ci	if (msg->ext_listen_timing) {
610e5b75505Sopenharmony_ci		dev->ext_listen_period = WPA_GET_LE16(msg->ext_listen_timing);
611e5b75505Sopenharmony_ci		dev->ext_listen_interval =
612e5b75505Sopenharmony_ci			WPA_GET_LE16(msg->ext_listen_timing + 2);
613e5b75505Sopenharmony_ci	}
614e5b75505Sopenharmony_ci
615e5b75505Sopenharmony_ci	if (!probe_req) {
616e5b75505Sopenharmony_ci		u16 new_config_methods;
617e5b75505Sopenharmony_ci		new_config_methods = msg->config_methods ?
618e5b75505Sopenharmony_ci			msg->config_methods : msg->wps_config_methods;
619e5b75505Sopenharmony_ci		if (new_config_methods &&
620e5b75505Sopenharmony_ci		    dev->info.config_methods != new_config_methods) {
621e5b75505Sopenharmony_ci			p2p_dbg(p2p, "Update peer " MACSTR
622e5b75505Sopenharmony_ci				" config_methods 0x%x -> 0x%x",
623e5b75505Sopenharmony_ci				MAC2STR(dev->info.p2p_device_addr),
624e5b75505Sopenharmony_ci				dev->info.config_methods,
625e5b75505Sopenharmony_ci				new_config_methods);
626e5b75505Sopenharmony_ci			dev->info.config_methods = new_config_methods;
627e5b75505Sopenharmony_ci		}
628e5b75505Sopenharmony_ci	}
629e5b75505Sopenharmony_ci}
630e5b75505Sopenharmony_ci
631e5b75505Sopenharmony_ci
632e5b75505Sopenharmony_cistatic void p2p_update_peer_vendor_elems(struct p2p_device *dev, const u8 *ies,
633e5b75505Sopenharmony_ci					 size_t ies_len)
634e5b75505Sopenharmony_ci{
635e5b75505Sopenharmony_ci	const u8 *pos, *end;
636e5b75505Sopenharmony_ci	u8 id, len;
637e5b75505Sopenharmony_ci
638e5b75505Sopenharmony_ci	wpabuf_free(dev->info.vendor_elems);
639e5b75505Sopenharmony_ci	dev->info.vendor_elems = NULL;
640e5b75505Sopenharmony_ci
641e5b75505Sopenharmony_ci	end = ies + ies_len;
642e5b75505Sopenharmony_ci
643e5b75505Sopenharmony_ci	for (pos = ies; end - pos > 1; pos += len) {
644e5b75505Sopenharmony_ci		id = *pos++;
645e5b75505Sopenharmony_ci		len = *pos++;
646e5b75505Sopenharmony_ci
647e5b75505Sopenharmony_ci		if (len > end - pos)
648e5b75505Sopenharmony_ci			break;
649e5b75505Sopenharmony_ci
650e5b75505Sopenharmony_ci		if (id != WLAN_EID_VENDOR_SPECIFIC || len < 3)
651e5b75505Sopenharmony_ci			continue;
652e5b75505Sopenharmony_ci
653e5b75505Sopenharmony_ci		if (len >= 4) {
654e5b75505Sopenharmony_ci			u32 type = WPA_GET_BE32(pos);
655e5b75505Sopenharmony_ci
656e5b75505Sopenharmony_ci			if (type == WPA_IE_VENDOR_TYPE ||
657e5b75505Sopenharmony_ci			    type == WMM_IE_VENDOR_TYPE ||
658e5b75505Sopenharmony_ci			    type == WPS_IE_VENDOR_TYPE ||
659e5b75505Sopenharmony_ci			    type == P2P_IE_VENDOR_TYPE ||
660e5b75505Sopenharmony_ci			    type == WFD_IE_VENDOR_TYPE)
661e5b75505Sopenharmony_ci				continue;
662e5b75505Sopenharmony_ci		}
663e5b75505Sopenharmony_ci
664e5b75505Sopenharmony_ci		/* Unknown vendor element - make raw IE data available */
665e5b75505Sopenharmony_ci		if (wpabuf_resize(&dev->info.vendor_elems, 2 + len) < 0)
666e5b75505Sopenharmony_ci			break;
667e5b75505Sopenharmony_ci		wpabuf_put_data(dev->info.vendor_elems, pos - 2, 2 + len);
668e5b75505Sopenharmony_ci	}
669e5b75505Sopenharmony_ci}
670e5b75505Sopenharmony_ci
671e5b75505Sopenharmony_ci
672e5b75505Sopenharmony_cistatic int p2p_compare_wfd_info(struct p2p_device *dev,
673e5b75505Sopenharmony_ci			      const struct p2p_message *msg)
674e5b75505Sopenharmony_ci{
675e5b75505Sopenharmony_ci	if (dev->info.wfd_subelems && msg->wfd_subelems) {
676e5b75505Sopenharmony_ci		if (dev->info.wfd_subelems->used != msg->wfd_subelems->used)
677e5b75505Sopenharmony_ci			return 1;
678e5b75505Sopenharmony_ci
679e5b75505Sopenharmony_ci		return os_memcmp(dev->info.wfd_subelems->buf,
680e5b75505Sopenharmony_ci				 msg->wfd_subelems->buf,
681e5b75505Sopenharmony_ci				 dev->info.wfd_subelems->used);
682e5b75505Sopenharmony_ci	}
683e5b75505Sopenharmony_ci	if (dev->info.wfd_subelems || msg->wfd_subelems)
684e5b75505Sopenharmony_ci		return 1;
685e5b75505Sopenharmony_ci
686e5b75505Sopenharmony_ci	return 0;
687e5b75505Sopenharmony_ci}
688e5b75505Sopenharmony_ci
689e5b75505Sopenharmony_ci
690e5b75505Sopenharmony_ci/**
691e5b75505Sopenharmony_ci * p2p_add_device - Add peer entries based on scan results or P2P frames
692e5b75505Sopenharmony_ci * @p2p: P2P module context from p2p_init()
693e5b75505Sopenharmony_ci * @addr: Source address of Beacon or Probe Response frame (may be either
694e5b75505Sopenharmony_ci *	P2P Device Address or P2P Interface Address)
695e5b75505Sopenharmony_ci * @level: Signal level (signal strength of the received frame from the peer)
696e5b75505Sopenharmony_ci * @freq: Frequency on which the Beacon or Probe Response frame was received
697e5b75505Sopenharmony_ci * @rx_time: Time when the result was received
698e5b75505Sopenharmony_ci * @ies: IEs from the Beacon or Probe Response frame
699e5b75505Sopenharmony_ci * @ies_len: Length of ies buffer in octets
700e5b75505Sopenharmony_ci * @scan_res: Whether this was based on scan results
701e5b75505Sopenharmony_ci * Returns: 0 on success, -1 on failure
702e5b75505Sopenharmony_ci *
703e5b75505Sopenharmony_ci * If the scan result is for a GO, the clients in the group will also be added
704e5b75505Sopenharmony_ci * to the peer table. This function can also be used with some other frames
705e5b75505Sopenharmony_ci * like Provision Discovery Request that contains P2P Capability and P2P Device
706e5b75505Sopenharmony_ci * Info attributes.
707e5b75505Sopenharmony_ci */
708e5b75505Sopenharmony_ciint p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
709e5b75505Sopenharmony_ci		   struct os_reltime *rx_time, int level, const u8 *ies,
710e5b75505Sopenharmony_ci		   size_t ies_len, int scan_res)
711e5b75505Sopenharmony_ci{
712e5b75505Sopenharmony_ci	struct p2p_device *dev;
713e5b75505Sopenharmony_ci	struct p2p_message msg;
714e5b75505Sopenharmony_ci	const u8 *p2p_dev_addr;
715e5b75505Sopenharmony_ci	int wfd_changed;
716e5b75505Sopenharmony_ci	int dev_name_changed;
717e5b75505Sopenharmony_ci	int i;
718e5b75505Sopenharmony_ci	struct os_reltime time_now;
719e5b75505Sopenharmony_ci
720e5b75505Sopenharmony_ci	os_memset(&msg, 0, sizeof(msg));
721e5b75505Sopenharmony_ci	if (p2p_parse_ies(ies, ies_len, &msg)) {
722e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Failed to parse P2P IE for a device entry");
723e5b75505Sopenharmony_ci		p2p_parse_free(&msg);
724e5b75505Sopenharmony_ci		return -1;
725e5b75505Sopenharmony_ci	}
726e5b75505Sopenharmony_ci
727e5b75505Sopenharmony_ci	if (msg.p2p_device_addr)
728e5b75505Sopenharmony_ci		p2p_dev_addr = msg.p2p_device_addr;
729e5b75505Sopenharmony_ci	else if (msg.device_id)
730e5b75505Sopenharmony_ci		p2p_dev_addr = msg.device_id;
731e5b75505Sopenharmony_ci	else {
732e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Ignore scan data without P2P Device Info or P2P Device Id");
733e5b75505Sopenharmony_ci		p2p_parse_free(&msg);
734e5b75505Sopenharmony_ci		return -1;
735e5b75505Sopenharmony_ci	}
736e5b75505Sopenharmony_ci
737e5b75505Sopenharmony_ci	if (!is_zero_ether_addr(p2p->peer_filter) &&
738e5b75505Sopenharmony_ci	    os_memcmp(p2p_dev_addr, p2p->peer_filter, ETH_ALEN) != 0) {
739e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Do not add peer filter for " MACSTR
740e5b75505Sopenharmony_ci			" due to peer filter", MAC2STR(p2p_dev_addr));
741e5b75505Sopenharmony_ci		p2p_parse_free(&msg);
742e5b75505Sopenharmony_ci		return 0;
743e5b75505Sopenharmony_ci	}
744e5b75505Sopenharmony_ci
745e5b75505Sopenharmony_ci	dev = p2p_create_device(p2p, p2p_dev_addr);
746e5b75505Sopenharmony_ci	if (dev == NULL) {
747e5b75505Sopenharmony_ci		p2p_parse_free(&msg);
748e5b75505Sopenharmony_ci		return -1;
749e5b75505Sopenharmony_ci	}
750e5b75505Sopenharmony_ci
751e5b75505Sopenharmony_ci	if (rx_time == NULL) {
752e5b75505Sopenharmony_ci		os_get_reltime(&time_now);
753e5b75505Sopenharmony_ci		rx_time = &time_now;
754e5b75505Sopenharmony_ci	}
755e5b75505Sopenharmony_ci
756e5b75505Sopenharmony_ci	/*
757e5b75505Sopenharmony_ci	 * Update the device entry only if the new peer
758e5b75505Sopenharmony_ci	 * entry is newer than the one previously stored, or if
759e5b75505Sopenharmony_ci	 * the device was previously seen as a P2P Client in a group
760e5b75505Sopenharmony_ci	 * and the new entry isn't older than a threshold.
761e5b75505Sopenharmony_ci	 */
762e5b75505Sopenharmony_ci	if (dev->last_seen.sec > 0 &&
763e5b75505Sopenharmony_ci	    os_reltime_before(rx_time, &dev->last_seen) &&
764e5b75505Sopenharmony_ci	    (!(dev->flags & P2P_DEV_LAST_SEEN_AS_GROUP_CLIENT) ||
765e5b75505Sopenharmony_ci	     os_reltime_expired(&dev->last_seen, rx_time,
766e5b75505Sopenharmony_ci				P2P_DEV_GROUP_CLIENT_RESP_THRESHOLD))) {
767e5b75505Sopenharmony_ci		p2p_dbg(p2p,
768e5b75505Sopenharmony_ci			"Do not update peer entry based on old frame (rx_time=%u.%06u last_seen=%u.%06u flags=0x%x)",
769e5b75505Sopenharmony_ci			(unsigned int) rx_time->sec,
770e5b75505Sopenharmony_ci			(unsigned int) rx_time->usec,
771e5b75505Sopenharmony_ci			(unsigned int) dev->last_seen.sec,
772e5b75505Sopenharmony_ci			(unsigned int) dev->last_seen.usec,
773e5b75505Sopenharmony_ci			dev->flags);
774e5b75505Sopenharmony_ci		p2p_parse_free(&msg);
775e5b75505Sopenharmony_ci		return -1;
776e5b75505Sopenharmony_ci	}
777e5b75505Sopenharmony_ci
778e5b75505Sopenharmony_ci	os_memcpy(&dev->last_seen, rx_time, sizeof(struct os_reltime));
779e5b75505Sopenharmony_ci
780e5b75505Sopenharmony_ci	dev->flags &= ~(P2P_DEV_PROBE_REQ_ONLY | P2P_DEV_GROUP_CLIENT_ONLY |
781e5b75505Sopenharmony_ci			P2P_DEV_LAST_SEEN_AS_GROUP_CLIENT);
782e5b75505Sopenharmony_ci
783e5b75505Sopenharmony_ci	if (os_memcmp(addr, p2p_dev_addr, ETH_ALEN) != 0)
784e5b75505Sopenharmony_ci		os_memcpy(dev->interface_addr, addr, ETH_ALEN);
785e5b75505Sopenharmony_ci	if (msg.ssid &&
786e5b75505Sopenharmony_ci	    msg.ssid[1] <= sizeof(dev->oper_ssid) &&
787e5b75505Sopenharmony_ci	    (msg.ssid[1] != P2P_WILDCARD_SSID_LEN ||
788e5b75505Sopenharmony_ci	     os_memcmp(msg.ssid + 2, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN)
789e5b75505Sopenharmony_ci	     != 0)) {
790e5b75505Sopenharmony_ci		os_memcpy(dev->oper_ssid, msg.ssid + 2, msg.ssid[1]);
791e5b75505Sopenharmony_ci		dev->oper_ssid_len = msg.ssid[1];
792e5b75505Sopenharmony_ci	}
793e5b75505Sopenharmony_ci
794e5b75505Sopenharmony_ci	wpabuf_free(dev->info.p2ps_instance);
795e5b75505Sopenharmony_ci	dev->info.p2ps_instance = NULL;
796e5b75505Sopenharmony_ci	if (msg.adv_service_instance && msg.adv_service_instance_len)
797e5b75505Sopenharmony_ci		dev->info.p2ps_instance = wpabuf_alloc_copy(
798e5b75505Sopenharmony_ci			msg.adv_service_instance, msg.adv_service_instance_len);
799e5b75505Sopenharmony_ci
800e5b75505Sopenharmony_ci	if (freq >= 2412 && freq <= 2484 && msg.ds_params &&
801e5b75505Sopenharmony_ci	    *msg.ds_params >= 1 && *msg.ds_params <= 14) {
802e5b75505Sopenharmony_ci		int ds_freq;
803e5b75505Sopenharmony_ci		if (*msg.ds_params == 14)
804e5b75505Sopenharmony_ci			ds_freq = 2484;
805e5b75505Sopenharmony_ci		else
806e5b75505Sopenharmony_ci			ds_freq = 2407 + *msg.ds_params * 5;
807e5b75505Sopenharmony_ci		if (freq != ds_freq) {
808e5b75505Sopenharmony_ci			p2p_dbg(p2p, "Update Listen frequency based on DS Parameter Set IE: %d -> %d MHz",
809e5b75505Sopenharmony_ci				freq, ds_freq);
810e5b75505Sopenharmony_ci			freq = ds_freq;
811e5b75505Sopenharmony_ci		}
812e5b75505Sopenharmony_ci	}
813e5b75505Sopenharmony_ci
814e5b75505Sopenharmony_ci	if (dev->listen_freq && dev->listen_freq != freq && scan_res) {
815e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Update Listen frequency based on scan results ("
816e5b75505Sopenharmony_ci			MACSTR " %d -> %d MHz (DS param %d)",
817e5b75505Sopenharmony_ci			MAC2STR(dev->info.p2p_device_addr), dev->listen_freq,
818e5b75505Sopenharmony_ci			freq, msg.ds_params ? *msg.ds_params : -1);
819e5b75505Sopenharmony_ci	}
820e5b75505Sopenharmony_ci	if (scan_res) {
821e5b75505Sopenharmony_ci		dev->listen_freq = freq;
822e5b75505Sopenharmony_ci		if (msg.group_info)
823e5b75505Sopenharmony_ci			dev->oper_freq = freq;
824e5b75505Sopenharmony_ci	}
825e5b75505Sopenharmony_ci	dev->info.level = level;
826e5b75505Sopenharmony_ci
827e5b75505Sopenharmony_ci	dev_name_changed = os_strncmp(dev->info.device_name, msg.device_name,
828e5b75505Sopenharmony_ci				      WPS_DEV_NAME_MAX_LEN) != 0;
829e5b75505Sopenharmony_ci
830e5b75505Sopenharmony_ci	p2p_copy_wps_info(p2p, dev, 0, &msg);
831e5b75505Sopenharmony_ci
832e5b75505Sopenharmony_ci	for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
833e5b75505Sopenharmony_ci		wpabuf_free(dev->info.wps_vendor_ext[i]);
834e5b75505Sopenharmony_ci		dev->info.wps_vendor_ext[i] = NULL;
835e5b75505Sopenharmony_ci	}
836e5b75505Sopenharmony_ci
837e5b75505Sopenharmony_ci	for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
838e5b75505Sopenharmony_ci		if (msg.wps_vendor_ext[i] == NULL)
839e5b75505Sopenharmony_ci			break;
840e5b75505Sopenharmony_ci		dev->info.wps_vendor_ext[i] = wpabuf_alloc_copy(
841e5b75505Sopenharmony_ci			msg.wps_vendor_ext[i], msg.wps_vendor_ext_len[i]);
842e5b75505Sopenharmony_ci		if (dev->info.wps_vendor_ext[i] == NULL)
843e5b75505Sopenharmony_ci			break;
844e5b75505Sopenharmony_ci	}
845e5b75505Sopenharmony_ci
846e5b75505Sopenharmony_ci	wfd_changed = p2p_compare_wfd_info(dev, &msg);
847e5b75505Sopenharmony_ci
848e5b75505Sopenharmony_ci	if (wfd_changed) {
849e5b75505Sopenharmony_ci		wpabuf_free(dev->info.wfd_subelems);
850e5b75505Sopenharmony_ci		if (msg.wfd_subelems)
851e5b75505Sopenharmony_ci			dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
852e5b75505Sopenharmony_ci		else
853e5b75505Sopenharmony_ci			dev->info.wfd_subelems = NULL;
854e5b75505Sopenharmony_ci	}
855e5b75505Sopenharmony_ci
856e5b75505Sopenharmony_ci	if (scan_res) {
857e5b75505Sopenharmony_ci		p2p_add_group_clients(p2p, p2p_dev_addr, addr, freq,
858e5b75505Sopenharmony_ci				      msg.group_info, msg.group_info_len,
859e5b75505Sopenharmony_ci				      rx_time);
860e5b75505Sopenharmony_ci	}
861e5b75505Sopenharmony_ci
862e5b75505Sopenharmony_ci	p2p_parse_free(&msg);
863e5b75505Sopenharmony_ci
864e5b75505Sopenharmony_ci	p2p_update_peer_vendor_elems(dev, ies, ies_len);
865e5b75505Sopenharmony_ci
866e5b75505Sopenharmony_ci	if (dev->flags & P2P_DEV_REPORTED && !wfd_changed &&
867e5b75505Sopenharmony_ci	    !dev_name_changed &&
868e5b75505Sopenharmony_ci	    (!msg.adv_service_instance ||
869e5b75505Sopenharmony_ci	     (dev->flags & P2P_DEV_P2PS_REPORTED)))
870e5b75505Sopenharmony_ci		return 0;
871e5b75505Sopenharmony_ci
872e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Peer found with Listen frequency %d MHz (rx_time=%u.%06u)",
873e5b75505Sopenharmony_ci		freq, (unsigned int) rx_time->sec,
874e5b75505Sopenharmony_ci		(unsigned int) rx_time->usec);
875e5b75505Sopenharmony_ci	if (dev->flags & P2P_DEV_USER_REJECTED) {
876e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Do not report rejected device");
877e5b75505Sopenharmony_ci		return 0;
878e5b75505Sopenharmony_ci	}
879e5b75505Sopenharmony_ci
880e5b75505Sopenharmony_ci	if (dev->info.config_methods == 0 &&
881e5b75505Sopenharmony_ci	    (freq == 2412 || freq == 2437 || freq == 2462)) {
882e5b75505Sopenharmony_ci		/*
883e5b75505Sopenharmony_ci		 * If we have only seen a Beacon frame from a GO, we do not yet
884e5b75505Sopenharmony_ci		 * know what WPS config methods it supports. Since some
885e5b75505Sopenharmony_ci		 * applications use config_methods value from P2P-DEVICE-FOUND
886e5b75505Sopenharmony_ci		 * events, postpone reporting this peer until we've fully
887e5b75505Sopenharmony_ci		 * discovered its capabilities.
888e5b75505Sopenharmony_ci		 *
889e5b75505Sopenharmony_ci		 * At least for now, do this only if the peer was detected on
890e5b75505Sopenharmony_ci		 * one of the social channels since that peer can be easily be
891e5b75505Sopenharmony_ci		 * found again and there are no limitations of having to use
892e5b75505Sopenharmony_ci		 * passive scan on this channels, so this can be done through
893e5b75505Sopenharmony_ci		 * Probe Response frame that includes the config_methods
894e5b75505Sopenharmony_ci		 * information.
895e5b75505Sopenharmony_ci		 */
896e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Do not report peer " MACSTR
897e5b75505Sopenharmony_ci			" with unknown config methods", MAC2STR(addr));
898e5b75505Sopenharmony_ci		return 0;
899e5b75505Sopenharmony_ci	}
900e5b75505Sopenharmony_ci
901e5b75505Sopenharmony_ci	p2p->cfg->dev_found(p2p->cfg->cb_ctx, addr, &dev->info,
902e5b75505Sopenharmony_ci			    !(dev->flags & P2P_DEV_REPORTED_ONCE));
903e5b75505Sopenharmony_ci	dev->flags |= P2P_DEV_REPORTED | P2P_DEV_REPORTED_ONCE;
904e5b75505Sopenharmony_ci
905e5b75505Sopenharmony_ci	if (msg.adv_service_instance)
906e5b75505Sopenharmony_ci		dev->flags |= P2P_DEV_P2PS_REPORTED;
907e5b75505Sopenharmony_ci
908e5b75505Sopenharmony_ci	return 0;
909e5b75505Sopenharmony_ci}
910e5b75505Sopenharmony_ci
911e5b75505Sopenharmony_ci
912e5b75505Sopenharmony_cistatic void p2p_device_free(struct p2p_data *p2p, struct p2p_device *dev)
913e5b75505Sopenharmony_ci{
914e5b75505Sopenharmony_ci	int i;
915e5b75505Sopenharmony_ci
916e5b75505Sopenharmony_ci	if (p2p->go_neg_peer == dev) {
917e5b75505Sopenharmony_ci		/*
918e5b75505Sopenharmony_ci		 * If GO Negotiation is in progress, report that it has failed.
919e5b75505Sopenharmony_ci		 */
920e5b75505Sopenharmony_ci		p2p_go_neg_failed(p2p, -1);
921e5b75505Sopenharmony_ci	}
922e5b75505Sopenharmony_ci	if (p2p->invite_peer == dev)
923e5b75505Sopenharmony_ci		p2p->invite_peer = NULL;
924e5b75505Sopenharmony_ci	if (p2p->sd_peer == dev)
925e5b75505Sopenharmony_ci		p2p->sd_peer = NULL;
926e5b75505Sopenharmony_ci	if (p2p->pending_client_disc_go == dev)
927e5b75505Sopenharmony_ci		p2p->pending_client_disc_go = NULL;
928e5b75505Sopenharmony_ci
929e5b75505Sopenharmony_ci	/* dev_lost() device, but only if it was previously dev_found() */
930e5b75505Sopenharmony_ci	if (dev->flags & P2P_DEV_REPORTED_ONCE)
931e5b75505Sopenharmony_ci		p2p->cfg->dev_lost(p2p->cfg->cb_ctx,
932e5b75505Sopenharmony_ci				   dev->info.p2p_device_addr);
933e5b75505Sopenharmony_ci
934e5b75505Sopenharmony_ci	for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
935e5b75505Sopenharmony_ci		wpabuf_free(dev->info.wps_vendor_ext[i]);
936e5b75505Sopenharmony_ci		dev->info.wps_vendor_ext[i] = NULL;
937e5b75505Sopenharmony_ci	}
938e5b75505Sopenharmony_ci
939e5b75505Sopenharmony_ci	wpabuf_free(dev->info.wfd_subelems);
940e5b75505Sopenharmony_ci	wpabuf_free(dev->info.vendor_elems);
941e5b75505Sopenharmony_ci	wpabuf_free(dev->go_neg_conf);
942e5b75505Sopenharmony_ci	wpabuf_free(dev->info.p2ps_instance);
943e5b75505Sopenharmony_ci
944e5b75505Sopenharmony_ci	os_free(dev);
945e5b75505Sopenharmony_ci}
946e5b75505Sopenharmony_ci
947e5b75505Sopenharmony_ci
948e5b75505Sopenharmony_cistatic int p2p_get_next_prog_freq(struct p2p_data *p2p)
949e5b75505Sopenharmony_ci{
950e5b75505Sopenharmony_ci	struct p2p_channels *c;
951e5b75505Sopenharmony_ci	struct p2p_reg_class *cla;
952e5b75505Sopenharmony_ci	size_t cl, ch;
953e5b75505Sopenharmony_ci	int found = 0;
954e5b75505Sopenharmony_ci	u8 reg_class;
955e5b75505Sopenharmony_ci	u8 channel;
956e5b75505Sopenharmony_ci	int freq;
957e5b75505Sopenharmony_ci
958e5b75505Sopenharmony_ci	c = &p2p->cfg->channels;
959e5b75505Sopenharmony_ci	for (cl = 0; cl < c->reg_classes; cl++) {
960e5b75505Sopenharmony_ci		cla = &c->reg_class[cl];
961e5b75505Sopenharmony_ci		if (cla->reg_class != p2p->last_prog_scan_class)
962e5b75505Sopenharmony_ci			continue;
963e5b75505Sopenharmony_ci		for (ch = 0; ch < cla->channels; ch++) {
964e5b75505Sopenharmony_ci			if (cla->channel[ch] == p2p->last_prog_scan_chan) {
965e5b75505Sopenharmony_ci				found = 1;
966e5b75505Sopenharmony_ci				break;
967e5b75505Sopenharmony_ci			}
968e5b75505Sopenharmony_ci		}
969e5b75505Sopenharmony_ci		if (found)
970e5b75505Sopenharmony_ci			break;
971e5b75505Sopenharmony_ci	}
972e5b75505Sopenharmony_ci
973e5b75505Sopenharmony_ci	if (!found) {
974e5b75505Sopenharmony_ci		/* Start from beginning */
975e5b75505Sopenharmony_ci		reg_class = c->reg_class[0].reg_class;
976e5b75505Sopenharmony_ci		channel = c->reg_class[0].channel[0];
977e5b75505Sopenharmony_ci	} else {
978e5b75505Sopenharmony_ci		/* Pick the next channel */
979e5b75505Sopenharmony_ci		ch++;
980e5b75505Sopenharmony_ci		if (ch == cla->channels) {
981e5b75505Sopenharmony_ci			cl++;
982e5b75505Sopenharmony_ci			if (cl == c->reg_classes)
983e5b75505Sopenharmony_ci				cl = 0;
984e5b75505Sopenharmony_ci			ch = 0;
985e5b75505Sopenharmony_ci		}
986e5b75505Sopenharmony_ci		reg_class = c->reg_class[cl].reg_class;
987e5b75505Sopenharmony_ci		channel = c->reg_class[cl].channel[ch];
988e5b75505Sopenharmony_ci	}
989e5b75505Sopenharmony_ci
990e5b75505Sopenharmony_ci	freq = p2p_channel_to_freq(reg_class, channel);
991e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Next progressive search channel: reg_class %u channel %u -> %d MHz",
992e5b75505Sopenharmony_ci		reg_class, channel, freq);
993e5b75505Sopenharmony_ci	p2p->last_prog_scan_class = reg_class;
994e5b75505Sopenharmony_ci	p2p->last_prog_scan_chan = channel;
995e5b75505Sopenharmony_ci
996e5b75505Sopenharmony_ci	if (freq == 2412 || freq == 2437 || freq == 2462)
997e5b75505Sopenharmony_ci		return 0; /* No need to add social channels */
998e5b75505Sopenharmony_ci	return freq;
999e5b75505Sopenharmony_ci}
1000e5b75505Sopenharmony_ci
1001e5b75505Sopenharmony_ci
1002e5b75505Sopenharmony_cistatic void p2p_search(struct p2p_data *p2p)
1003e5b75505Sopenharmony_ci{
1004e5b75505Sopenharmony_ci	int freq = 0;
1005e5b75505Sopenharmony_ci	enum p2p_scan_type type;
1006e5b75505Sopenharmony_ci	u16 pw_id = DEV_PW_DEFAULT;
1007e5b75505Sopenharmony_ci	int res;
1008e5b75505Sopenharmony_ci
1009e5b75505Sopenharmony_ci	if (p2p->drv_in_listen) {
1010e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Driver is still in Listen state - wait for it to end before continuing");
1011e5b75505Sopenharmony_ci		return;
1012e5b75505Sopenharmony_ci	}
1013e5b75505Sopenharmony_ci	p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
1014e5b75505Sopenharmony_ci
1015e5b75505Sopenharmony_ci	if (p2p->find_pending_full &&
1016e5b75505Sopenharmony_ci	    (p2p->find_type == P2P_FIND_PROGRESSIVE ||
1017e5b75505Sopenharmony_ci	     p2p->find_type == P2P_FIND_START_WITH_FULL)) {
1018e5b75505Sopenharmony_ci		type = P2P_SCAN_FULL;
1019e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Starting search (pending full scan)");
1020e5b75505Sopenharmony_ci		p2p->find_pending_full = 0;
1021e5b75505Sopenharmony_ci	} else if ((p2p->find_type == P2P_FIND_PROGRESSIVE &&
1022e5b75505Sopenharmony_ci	    (freq = p2p_get_next_prog_freq(p2p)) > 0) ||
1023e5b75505Sopenharmony_ci	    (p2p->find_type == P2P_FIND_START_WITH_FULL &&
1024e5b75505Sopenharmony_ci	     (freq = p2p->find_specified_freq) > 0)) {
1025e5b75505Sopenharmony_ci		type = P2P_SCAN_SOCIAL_PLUS_ONE;
1026e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Starting search (+ freq %u)", freq);
1027e5b75505Sopenharmony_ci	} else {
1028e5b75505Sopenharmony_ci		type = P2P_SCAN_SOCIAL;
1029e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Starting search");
1030e5b75505Sopenharmony_ci	}
1031e5b75505Sopenharmony_ci
1032e5b75505Sopenharmony_ci	res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, type, freq,
1033e5b75505Sopenharmony_ci				 p2p->num_req_dev_types, p2p->req_dev_types,
1034e5b75505Sopenharmony_ci				 p2p->find_dev_id, pw_id);
1035e5b75505Sopenharmony_ci	if (res < 0) {
1036e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Scan request schedule failed");
1037e5b75505Sopenharmony_ci		p2p_continue_find(p2p);
1038e5b75505Sopenharmony_ci	}
1039e5b75505Sopenharmony_ci}
1040e5b75505Sopenharmony_ci
1041e5b75505Sopenharmony_ci
1042e5b75505Sopenharmony_cistatic void p2p_find_timeout(void *eloop_ctx, void *timeout_ctx)
1043e5b75505Sopenharmony_ci{
1044e5b75505Sopenharmony_ci	struct p2p_data *p2p = eloop_ctx;
1045e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Find timeout -> stop");
1046e5b75505Sopenharmony_ci	p2p_stop_find(p2p);
1047e5b75505Sopenharmony_ci}
1048e5b75505Sopenharmony_ci
1049e5b75505Sopenharmony_ci
1050e5b75505Sopenharmony_civoid p2p_notify_scan_trigger_status(struct p2p_data *p2p, int status)
1051e5b75505Sopenharmony_ci{
1052e5b75505Sopenharmony_ci	if (status != 0) {
1053e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Scan request failed");
1054e5b75505Sopenharmony_ci		/* Do continue find even for the first p2p_find_scan */
1055e5b75505Sopenharmony_ci		p2p_continue_find(p2p);
1056e5b75505Sopenharmony_ci	} else {
1057e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Running p2p_scan");
1058e5b75505Sopenharmony_ci		p2p->p2p_scan_running = 1;
1059e5b75505Sopenharmony_ci		eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
1060e5b75505Sopenharmony_ci		eloop_register_timeout(P2P_SCAN_TIMEOUT, 0, p2p_scan_timeout,
1061e5b75505Sopenharmony_ci				       p2p, NULL);
1062e5b75505Sopenharmony_ci	}
1063e5b75505Sopenharmony_ci}
1064e5b75505Sopenharmony_ci
1065e5b75505Sopenharmony_ci
1066e5b75505Sopenharmony_cistatic int p2p_run_after_scan(struct p2p_data *p2p)
1067e5b75505Sopenharmony_ci{
1068e5b75505Sopenharmony_ci	struct p2p_device *dev;
1069e5b75505Sopenharmony_ci	enum p2p_after_scan op;
1070e5b75505Sopenharmony_ci
1071e5b75505Sopenharmony_ci	op = p2p->start_after_scan;
1072e5b75505Sopenharmony_ci	p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING;
1073e5b75505Sopenharmony_ci	switch (op) {
1074e5b75505Sopenharmony_ci	case P2P_AFTER_SCAN_NOTHING:
1075e5b75505Sopenharmony_ci		break;
1076e5b75505Sopenharmony_ci	case P2P_AFTER_SCAN_LISTEN:
1077e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Start previously requested Listen state");
1078e5b75505Sopenharmony_ci		p2p_listen(p2p, p2p->pending_listen_sec * 1000 +
1079e5b75505Sopenharmony_ci			   p2p->pending_listen_usec / 1000);
1080e5b75505Sopenharmony_ci		return 1;
1081e5b75505Sopenharmony_ci	case P2P_AFTER_SCAN_CONNECT:
1082e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Start previously requested connect with " MACSTR,
1083e5b75505Sopenharmony_ci			MAC2STR(p2p->after_scan_peer));
1084e5b75505Sopenharmony_ci		dev = p2p_get_device(p2p, p2p->after_scan_peer);
1085e5b75505Sopenharmony_ci		if (dev == NULL) {
1086e5b75505Sopenharmony_ci			p2p_dbg(p2p, "Peer not known anymore");
1087e5b75505Sopenharmony_ci			break;
1088e5b75505Sopenharmony_ci		}
1089e5b75505Sopenharmony_ci		p2p_connect_send(p2p, dev);
1090e5b75505Sopenharmony_ci		return 1;
1091e5b75505Sopenharmony_ci	}
1092e5b75505Sopenharmony_ci
1093e5b75505Sopenharmony_ci	return 0;
1094e5b75505Sopenharmony_ci}
1095e5b75505Sopenharmony_ci
1096e5b75505Sopenharmony_ci
1097e5b75505Sopenharmony_cistatic void p2p_scan_timeout(void *eloop_ctx, void *timeout_ctx)
1098e5b75505Sopenharmony_ci{
1099e5b75505Sopenharmony_ci	struct p2p_data *p2p = eloop_ctx;
1100e5b75505Sopenharmony_ci	int running;
1101e5b75505Sopenharmony_ci	p2p_dbg(p2p, "p2p_scan timeout (running=%d)", p2p->p2p_scan_running);
1102e5b75505Sopenharmony_ci	running = p2p->p2p_scan_running;
1103e5b75505Sopenharmony_ci	/* Make sure we recover from missed scan results callback */
1104e5b75505Sopenharmony_ci	p2p->p2p_scan_running = 0;
1105e5b75505Sopenharmony_ci
1106e5b75505Sopenharmony_ci	if (running)
1107e5b75505Sopenharmony_ci		p2p_run_after_scan(p2p);
1108e5b75505Sopenharmony_ci}
1109e5b75505Sopenharmony_ci
1110e5b75505Sopenharmony_ci
1111e5b75505Sopenharmony_cistatic void p2p_free_req_dev_types(struct p2p_data *p2p)
1112e5b75505Sopenharmony_ci{
1113e5b75505Sopenharmony_ci	p2p->num_req_dev_types = 0;
1114e5b75505Sopenharmony_ci	os_free(p2p->req_dev_types);
1115e5b75505Sopenharmony_ci	p2p->req_dev_types = NULL;
1116e5b75505Sopenharmony_ci}
1117e5b75505Sopenharmony_ci
1118e5b75505Sopenharmony_ci
1119e5b75505Sopenharmony_cistatic int p2ps_gen_hash(struct p2p_data *p2p, const char *str, u8 *hash)
1120e5b75505Sopenharmony_ci{
1121e5b75505Sopenharmony_ci	u8 buf[SHA256_MAC_LEN];
1122e5b75505Sopenharmony_ci	char str_buf[256];
1123e5b75505Sopenharmony_ci	const u8 *adv_array;
1124e5b75505Sopenharmony_ci	size_t i, adv_len;
1125e5b75505Sopenharmony_ci
1126e5b75505Sopenharmony_ci	if (!str || !hash)
1127e5b75505Sopenharmony_ci		return 0;
1128e5b75505Sopenharmony_ci
1129e5b75505Sopenharmony_ci	if (!str[0]) {
1130e5b75505Sopenharmony_ci		os_memcpy(hash, p2p->wild_card_hash, P2PS_HASH_LEN);
1131e5b75505Sopenharmony_ci		return 1;
1132e5b75505Sopenharmony_ci	}
1133e5b75505Sopenharmony_ci
1134e5b75505Sopenharmony_ci	adv_array = (u8 *) str_buf;
1135e5b75505Sopenharmony_ci	adv_len = os_strlen(str);
1136e5b75505Sopenharmony_ci	if (adv_len >= sizeof(str_buf))
1137e5b75505Sopenharmony_ci		return 0;
1138e5b75505Sopenharmony_ci
1139e5b75505Sopenharmony_ci	for (i = 0; i < adv_len; i++) {
1140e5b75505Sopenharmony_ci		if (str[i] >= 'A' && str[i] <= 'Z')
1141e5b75505Sopenharmony_ci			str_buf[i] = str[i] - 'A' + 'a';
1142e5b75505Sopenharmony_ci		else
1143e5b75505Sopenharmony_ci			str_buf[i] = str[i];
1144e5b75505Sopenharmony_ci	}
1145e5b75505Sopenharmony_ci
1146e5b75505Sopenharmony_ci	if (sha256_vector(1, &adv_array, &adv_len, buf))
1147e5b75505Sopenharmony_ci		return 0;
1148e5b75505Sopenharmony_ci
1149e5b75505Sopenharmony_ci	os_memcpy(hash, buf, P2PS_HASH_LEN);
1150e5b75505Sopenharmony_ci	return 1;
1151e5b75505Sopenharmony_ci}
1152e5b75505Sopenharmony_ci
1153e5b75505Sopenharmony_ci
1154e5b75505Sopenharmony_ciint p2p_find(struct p2p_data *p2p, unsigned int timeout,
1155e5b75505Sopenharmony_ci	     enum p2p_discovery_type type,
1156e5b75505Sopenharmony_ci	     unsigned int num_req_dev_types, const u8 *req_dev_types,
1157e5b75505Sopenharmony_ci	     const u8 *dev_id, unsigned int search_delay,
1158e5b75505Sopenharmony_ci	     u8 seek_count, const char **seek, int freq)
1159e5b75505Sopenharmony_ci{
1160e5b75505Sopenharmony_ci	int res;
1161e5b75505Sopenharmony_ci	struct os_reltime start;
1162e5b75505Sopenharmony_ci
1163e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Starting find (type=%d)", type);
1164e5b75505Sopenharmony_ci	if (p2p->p2p_scan_running) {
1165e5b75505Sopenharmony_ci		p2p_dbg(p2p, "p2p_scan is already running");
1166e5b75505Sopenharmony_ci	}
1167e5b75505Sopenharmony_ci
1168e5b75505Sopenharmony_ci	p2p_free_req_dev_types(p2p);
1169e5b75505Sopenharmony_ci	if (req_dev_types && num_req_dev_types) {
1170e5b75505Sopenharmony_ci		p2p->req_dev_types = os_memdup(req_dev_types,
1171e5b75505Sopenharmony_ci					       num_req_dev_types *
1172e5b75505Sopenharmony_ci					       WPS_DEV_TYPE_LEN);
1173e5b75505Sopenharmony_ci		if (p2p->req_dev_types == NULL)
1174e5b75505Sopenharmony_ci			return -1;
1175e5b75505Sopenharmony_ci		p2p->num_req_dev_types = num_req_dev_types;
1176e5b75505Sopenharmony_ci	}
1177e5b75505Sopenharmony_ci
1178e5b75505Sopenharmony_ci	if (dev_id) {
1179e5b75505Sopenharmony_ci		os_memcpy(p2p->find_dev_id_buf, dev_id, ETH_ALEN);
1180e5b75505Sopenharmony_ci		p2p->find_dev_id = p2p->find_dev_id_buf;
1181e5b75505Sopenharmony_ci	} else
1182e5b75505Sopenharmony_ci		p2p->find_dev_id = NULL;
1183e5b75505Sopenharmony_ci
1184e5b75505Sopenharmony_ci	if (seek_count == 0 || !seek) {
1185e5b75505Sopenharmony_ci		/* Not an ASP search */
1186e5b75505Sopenharmony_ci		p2p->p2ps_seek = 0;
1187e5b75505Sopenharmony_ci	} else if (seek_count == 1 && seek && (!seek[0] || !seek[0][0])) {
1188e5b75505Sopenharmony_ci		/*
1189e5b75505Sopenharmony_ci		 * An empty seek string means no hash values, but still an ASP
1190e5b75505Sopenharmony_ci		 * search.
1191e5b75505Sopenharmony_ci		 */
1192e5b75505Sopenharmony_ci		p2p_dbg(p2p, "ASP search");
1193e5b75505Sopenharmony_ci		p2p->p2ps_seek_count = 0;
1194e5b75505Sopenharmony_ci		p2p->p2ps_seek = 1;
1195e5b75505Sopenharmony_ci	} else if (seek && seek_count <= P2P_MAX_QUERY_HASH) {
1196e5b75505Sopenharmony_ci		u8 buf[P2PS_HASH_LEN];
1197e5b75505Sopenharmony_ci		int i, count = 0;
1198e5b75505Sopenharmony_ci
1199e5b75505Sopenharmony_ci		for (i = 0; i < seek_count; i++) {
1200e5b75505Sopenharmony_ci			if (!p2ps_gen_hash(p2p, seek[i], buf))
1201e5b75505Sopenharmony_ci				continue;
1202e5b75505Sopenharmony_ci
1203e5b75505Sopenharmony_ci			p2p_dbg(p2p, "Seek service %s hash " MACSTR,
1204e5b75505Sopenharmony_ci				seek[i], MAC2STR(buf));
1205e5b75505Sopenharmony_ci			os_memcpy(&p2p->p2ps_seek_hash[count * P2PS_HASH_LEN],
1206e5b75505Sopenharmony_ci				  buf, P2PS_HASH_LEN);
1207e5b75505Sopenharmony_ci			count++;
1208e5b75505Sopenharmony_ci		}
1209e5b75505Sopenharmony_ci
1210e5b75505Sopenharmony_ci		p2p->p2ps_seek_count = count;
1211e5b75505Sopenharmony_ci		p2p->p2ps_seek = 1;
1212e5b75505Sopenharmony_ci	} else {
1213e5b75505Sopenharmony_ci		p2p->p2ps_seek_count = 0;
1214e5b75505Sopenharmony_ci		p2p->p2ps_seek = 1;
1215e5b75505Sopenharmony_ci	}
1216e5b75505Sopenharmony_ci
1217e5b75505Sopenharmony_ci	/* Special case to perform wildcard search */
1218e5b75505Sopenharmony_ci	if (p2p->p2ps_seek_count == 0 && p2p->p2ps_seek) {
1219e5b75505Sopenharmony_ci		p2p->p2ps_seek_count = 1;
1220e5b75505Sopenharmony_ci		os_memcpy(&p2p->p2ps_seek_hash, p2p->wild_card_hash,
1221e5b75505Sopenharmony_ci			  P2PS_HASH_LEN);
1222e5b75505Sopenharmony_ci	}
1223e5b75505Sopenharmony_ci
1224e5b75505Sopenharmony_ci	p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING;
1225e5b75505Sopenharmony_ci	p2p_clear_timeout(p2p);
1226e5b75505Sopenharmony_ci	if (p2p->pending_listen_freq) {
1227e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Clear pending_listen_freq for p2p_find");
1228e5b75505Sopenharmony_ci		p2p->pending_listen_freq = 0;
1229e5b75505Sopenharmony_ci	}
1230e5b75505Sopenharmony_ci	p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
1231e5b75505Sopenharmony_ci	p2p->find_pending_full = 0;
1232e5b75505Sopenharmony_ci	p2p->find_type = type;
1233e5b75505Sopenharmony_ci	if (freq != 2412 && freq != 2437 && freq != 2462 && freq != 60480)
1234e5b75505Sopenharmony_ci		p2p->find_specified_freq = freq;
1235e5b75505Sopenharmony_ci	else
1236e5b75505Sopenharmony_ci		p2p->find_specified_freq = 0;
1237e5b75505Sopenharmony_ci	p2p_device_clear_reported(p2p);
1238e5b75505Sopenharmony_ci	os_memset(p2p->sd_query_no_ack, 0, ETH_ALEN);
1239e5b75505Sopenharmony_ci	p2p_set_state(p2p, P2P_SEARCH);
1240e5b75505Sopenharmony_ci	p2p->search_delay = search_delay;
1241e5b75505Sopenharmony_ci	p2p->in_search_delay = 0;
1242e5b75505Sopenharmony_ci	eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
1243e5b75505Sopenharmony_ci	p2p->last_p2p_find_timeout = timeout;
1244e5b75505Sopenharmony_ci	if (timeout)
1245e5b75505Sopenharmony_ci		eloop_register_timeout(timeout, 0, p2p_find_timeout,
1246e5b75505Sopenharmony_ci				       p2p, NULL);
1247e5b75505Sopenharmony_ci	os_get_reltime(&start);
1248e5b75505Sopenharmony_ci	switch (type) {
1249e5b75505Sopenharmony_ci	case P2P_FIND_START_WITH_FULL:
1250e5b75505Sopenharmony_ci		if (freq > 0) {
1251e5b75505Sopenharmony_ci			/*
1252e5b75505Sopenharmony_ci			 * Start with the specified channel and then move to
1253e5b75505Sopenharmony_ci			 * scans for social channels and this specific channel.
1254e5b75505Sopenharmony_ci			 */
1255e5b75505Sopenharmony_ci			res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx,
1256e5b75505Sopenharmony_ci						 P2P_SCAN_SPECIFIC, freq,
1257e5b75505Sopenharmony_ci						 p2p->num_req_dev_types,
1258e5b75505Sopenharmony_ci						 p2p->req_dev_types, dev_id,
1259e5b75505Sopenharmony_ci						 DEV_PW_DEFAULT);
1260e5b75505Sopenharmony_ci			break;
1261e5b75505Sopenharmony_ci		}
1262e5b75505Sopenharmony_ci		/* fall through */
1263e5b75505Sopenharmony_ci	case P2P_FIND_PROGRESSIVE:
1264e5b75505Sopenharmony_ci		res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, P2P_SCAN_FULL, 0,
1265e5b75505Sopenharmony_ci					 p2p->num_req_dev_types,
1266e5b75505Sopenharmony_ci					 p2p->req_dev_types, dev_id,
1267e5b75505Sopenharmony_ci					 DEV_PW_DEFAULT);
1268e5b75505Sopenharmony_ci		break;
1269e5b75505Sopenharmony_ci	case P2P_FIND_ONLY_SOCIAL:
1270e5b75505Sopenharmony_ci		res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, P2P_SCAN_SOCIAL, 0,
1271e5b75505Sopenharmony_ci					 p2p->num_req_dev_types,
1272e5b75505Sopenharmony_ci					 p2p->req_dev_types, dev_id,
1273e5b75505Sopenharmony_ci					 DEV_PW_DEFAULT);
1274e5b75505Sopenharmony_ci		break;
1275e5b75505Sopenharmony_ci	default:
1276e5b75505Sopenharmony_ci		return -1;
1277e5b75505Sopenharmony_ci	}
1278e5b75505Sopenharmony_ci
1279e5b75505Sopenharmony_ci	if (!res)
1280e5b75505Sopenharmony_ci		p2p->find_start = start;
1281e5b75505Sopenharmony_ci
1282e5b75505Sopenharmony_ci	if (res != 0 && p2p->p2p_scan_running) {
1283e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Failed to start p2p_scan - another p2p_scan was already running");
1284e5b75505Sopenharmony_ci		/* wait for the previous p2p_scan to complete */
1285e5b75505Sopenharmony_ci		if (type == P2P_FIND_PROGRESSIVE ||
1286e5b75505Sopenharmony_ci		    (type == P2P_FIND_START_WITH_FULL && freq == 0))
1287e5b75505Sopenharmony_ci			p2p->find_pending_full = 1;
1288e5b75505Sopenharmony_ci		res = 0; /* do not report failure */
1289e5b75505Sopenharmony_ci	} else if (res != 0) {
1290e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Failed to start p2p_scan");
1291e5b75505Sopenharmony_ci		p2p_set_state(p2p, P2P_IDLE);
1292e5b75505Sopenharmony_ci		eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
1293e5b75505Sopenharmony_ci	}
1294e5b75505Sopenharmony_ci
1295e5b75505Sopenharmony_ci	return res;
1296e5b75505Sopenharmony_ci}
1297e5b75505Sopenharmony_ci
1298e5b75505Sopenharmony_ci
1299e5b75505Sopenharmony_civoid p2p_stop_find_for_freq(struct p2p_data *p2p, int freq)
1300e5b75505Sopenharmony_ci{
1301e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Stopping find");
1302e5b75505Sopenharmony_ci	eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
1303e5b75505Sopenharmony_ci	p2p_clear_timeout(p2p);
1304e5b75505Sopenharmony_ci	if (p2p->state == P2P_SEARCH || p2p->state == P2P_SD_DURING_FIND)
1305e5b75505Sopenharmony_ci		p2p->cfg->find_stopped(p2p->cfg->cb_ctx);
1306e5b75505Sopenharmony_ci
1307e5b75505Sopenharmony_ci	p2p->p2ps_seek_count = 0;
1308e5b75505Sopenharmony_ci
1309e5b75505Sopenharmony_ci	p2p_set_state(p2p, P2P_IDLE);
1310e5b75505Sopenharmony_ci	p2p_free_req_dev_types(p2p);
1311e5b75505Sopenharmony_ci	p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING;
1312e5b75505Sopenharmony_ci	if (p2p->go_neg_peer)
1313e5b75505Sopenharmony_ci		p2p->go_neg_peer->flags &= ~P2P_DEV_PEER_WAITING_RESPONSE;
1314e5b75505Sopenharmony_ci	p2p->go_neg_peer = NULL;
1315e5b75505Sopenharmony_ci	p2p->sd_peer = NULL;
1316e5b75505Sopenharmony_ci	p2p->invite_peer = NULL;
1317e5b75505Sopenharmony_ci	p2p_stop_listen_for_freq(p2p, freq);
1318e5b75505Sopenharmony_ci	p2p->send_action_in_progress = 0;
1319e5b75505Sopenharmony_ci}
1320e5b75505Sopenharmony_ci
1321e5b75505Sopenharmony_ci
1322e5b75505Sopenharmony_civoid p2p_stop_listen_for_freq(struct p2p_data *p2p, int freq)
1323e5b75505Sopenharmony_ci{
1324e5b75505Sopenharmony_ci	if (freq > 0 && p2p->drv_in_listen == freq && p2p->in_listen) {
1325e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Skip stop_listen since we are on correct channel for response");
1326e5b75505Sopenharmony_ci		return;
1327e5b75505Sopenharmony_ci	}
1328e5b75505Sopenharmony_ci	if (p2p->in_listen) {
1329e5b75505Sopenharmony_ci		p2p->in_listen = 0;
1330e5b75505Sopenharmony_ci		p2p_clear_timeout(p2p);
1331e5b75505Sopenharmony_ci	}
1332e5b75505Sopenharmony_ci	if (p2p->drv_in_listen) {
1333e5b75505Sopenharmony_ci		/*
1334e5b75505Sopenharmony_ci		 * The driver may not deliver callback to p2p_listen_end()
1335e5b75505Sopenharmony_ci		 * when the operation gets canceled, so clear the internal
1336e5b75505Sopenharmony_ci		 * variable that is tracking driver state.
1337e5b75505Sopenharmony_ci		 */
1338e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Clear drv_in_listen (%d)", p2p->drv_in_listen);
1339e5b75505Sopenharmony_ci		p2p->drv_in_listen = 0;
1340e5b75505Sopenharmony_ci	}
1341e5b75505Sopenharmony_ci	p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
1342e5b75505Sopenharmony_ci}
1343e5b75505Sopenharmony_ci
1344e5b75505Sopenharmony_ci
1345e5b75505Sopenharmony_civoid p2p_stop_listen(struct p2p_data *p2p)
1346e5b75505Sopenharmony_ci{
1347e5b75505Sopenharmony_ci	if (p2p->state != P2P_LISTEN_ONLY) {
1348e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Skip stop_listen since not in listen_only state.");
1349e5b75505Sopenharmony_ci		return;
1350e5b75505Sopenharmony_ci	}
1351e5b75505Sopenharmony_ci
1352e5b75505Sopenharmony_ci	p2p_stop_listen_for_freq(p2p, 0);
1353e5b75505Sopenharmony_ci	p2p_set_state(p2p, P2P_IDLE);
1354e5b75505Sopenharmony_ci}
1355e5b75505Sopenharmony_ci
1356e5b75505Sopenharmony_ci
1357e5b75505Sopenharmony_civoid p2p_stop_find(struct p2p_data *p2p)
1358e5b75505Sopenharmony_ci{
1359e5b75505Sopenharmony_ci	p2p->pending_listen_freq = 0;
1360e5b75505Sopenharmony_ci	p2p_stop_find_for_freq(p2p, 0);
1361e5b75505Sopenharmony_ci}
1362e5b75505Sopenharmony_ci
1363e5b75505Sopenharmony_ci
1364e5b75505Sopenharmony_cistatic int p2p_prepare_channel_pref(struct p2p_data *p2p,
1365e5b75505Sopenharmony_ci				    unsigned int force_freq,
1366e5b75505Sopenharmony_ci				    unsigned int pref_freq, int go)
1367e5b75505Sopenharmony_ci{
1368e5b75505Sopenharmony_ci	u8 op_class, op_channel;
1369e5b75505Sopenharmony_ci	unsigned int freq = force_freq ? force_freq : pref_freq;
1370e5b75505Sopenharmony_ci
1371e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Prepare channel pref - force_freq=%u pref_freq=%u go=%d",
1372e5b75505Sopenharmony_ci		force_freq, pref_freq, go);
1373e5b75505Sopenharmony_ci	if (p2p_freq_to_channel(freq, &op_class, &op_channel) < 0) {
1374e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Unsupported frequency %u MHz", freq);
1375e5b75505Sopenharmony_ci		return -1;
1376e5b75505Sopenharmony_ci	}
1377e5b75505Sopenharmony_ci
1378e5b75505Sopenharmony_ci	if (!p2p_channels_includes(&p2p->cfg->channels, op_class, op_channel) &&
1379e5b75505Sopenharmony_ci	    (go || !p2p_channels_includes(&p2p->cfg->cli_channels, op_class,
1380e5b75505Sopenharmony_ci					  op_channel))) {
1381e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Frequency %u MHz (oper_class %u channel %u) not allowed for P2P",
1382e5b75505Sopenharmony_ci			freq, op_class, op_channel);
1383e5b75505Sopenharmony_ci		return -1;
1384e5b75505Sopenharmony_ci	}
1385e5b75505Sopenharmony_ci
1386e5b75505Sopenharmony_ci	p2p->op_reg_class = op_class;
1387e5b75505Sopenharmony_ci	p2p->op_channel = op_channel;
1388e5b75505Sopenharmony_ci
1389e5b75505Sopenharmony_ci	if (force_freq) {
1390e5b75505Sopenharmony_ci		p2p->channels.reg_classes = 1;
1391e5b75505Sopenharmony_ci		p2p->channels.reg_class[0].channels = 1;
1392e5b75505Sopenharmony_ci		p2p->channels.reg_class[0].reg_class = p2p->op_reg_class;
1393e5b75505Sopenharmony_ci		p2p->channels.reg_class[0].channel[0] = p2p->op_channel;
1394e5b75505Sopenharmony_ci	} else {
1395e5b75505Sopenharmony_ci		os_memcpy(&p2p->channels, &p2p->cfg->channels,
1396e5b75505Sopenharmony_ci			  sizeof(struct p2p_channels));
1397e5b75505Sopenharmony_ci	}
1398e5b75505Sopenharmony_ci
1399e5b75505Sopenharmony_ci	return 0;
1400e5b75505Sopenharmony_ci}
1401e5b75505Sopenharmony_ci
1402e5b75505Sopenharmony_ci
1403e5b75505Sopenharmony_cistatic void p2p_prepare_channel_best(struct p2p_data *p2p)
1404e5b75505Sopenharmony_ci{
1405e5b75505Sopenharmony_ci	u8 op_class, op_channel;
1406e5b75505Sopenharmony_ci	const int op_classes_5ghz[] = { 124, 125, 115, 0 };
1407e5b75505Sopenharmony_ci	const int op_classes_ht40[] = { 126, 127, 116, 117, 0 };
1408e5b75505Sopenharmony_ci	const int op_classes_vht[] = { 128, 0 };
1409e5b75505Sopenharmony_ci
1410e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Prepare channel best");
1411e5b75505Sopenharmony_ci
1412e5b75505Sopenharmony_ci	if (!p2p->cfg->cfg_op_channel && p2p->best_freq_overall > 0 &&
1413e5b75505Sopenharmony_ci	    p2p_supported_freq(p2p, p2p->best_freq_overall) &&
1414e5b75505Sopenharmony_ci	    p2p_freq_to_channel(p2p->best_freq_overall, &op_class, &op_channel)
1415e5b75505Sopenharmony_ci	    == 0) {
1416e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Select best overall channel as operating channel preference");
1417e5b75505Sopenharmony_ci		p2p->op_reg_class = op_class;
1418e5b75505Sopenharmony_ci		p2p->op_channel = op_channel;
1419e5b75505Sopenharmony_ci	} else if (!p2p->cfg->cfg_op_channel && p2p->best_freq_5 > 0 &&
1420e5b75505Sopenharmony_ci		   p2p_supported_freq(p2p, p2p->best_freq_5) &&
1421e5b75505Sopenharmony_ci		   p2p_freq_to_channel(p2p->best_freq_5, &op_class, &op_channel)
1422e5b75505Sopenharmony_ci		   == 0) {
1423e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Select best 5 GHz channel as operating channel preference");
1424e5b75505Sopenharmony_ci		p2p->op_reg_class = op_class;
1425e5b75505Sopenharmony_ci		p2p->op_channel = op_channel;
1426e5b75505Sopenharmony_ci	} else if (!p2p->cfg->cfg_op_channel && p2p->best_freq_24 > 0 &&
1427e5b75505Sopenharmony_ci		   p2p_supported_freq(p2p, p2p->best_freq_24) &&
1428e5b75505Sopenharmony_ci		   p2p_freq_to_channel(p2p->best_freq_24, &op_class,
1429e5b75505Sopenharmony_ci				       &op_channel) == 0) {
1430e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Select best 2.4 GHz channel as operating channel preference");
1431e5b75505Sopenharmony_ci		p2p->op_reg_class = op_class;
1432e5b75505Sopenharmony_ci		p2p->op_channel = op_channel;
1433e5b75505Sopenharmony_ci	} else if (p2p->cfg->num_pref_chan > 0 &&
1434e5b75505Sopenharmony_ci		   p2p_channels_includes(&p2p->cfg->channels,
1435e5b75505Sopenharmony_ci					 p2p->cfg->pref_chan[0].op_class,
1436e5b75505Sopenharmony_ci					 p2p->cfg->pref_chan[0].chan)) {
1437e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Select first pref_chan entry as operating channel preference");
1438e5b75505Sopenharmony_ci		p2p->op_reg_class = p2p->cfg->pref_chan[0].op_class;
1439e5b75505Sopenharmony_ci		p2p->op_channel = p2p->cfg->pref_chan[0].chan;
1440e5b75505Sopenharmony_ci	} else if (p2p_channel_select(&p2p->cfg->channels, op_classes_vht,
1441e5b75505Sopenharmony_ci				      &p2p->op_reg_class, &p2p->op_channel) ==
1442e5b75505Sopenharmony_ci		   0) {
1443e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Select possible VHT channel (op_class %u channel %u) as operating channel preference",
1444e5b75505Sopenharmony_ci			p2p->op_reg_class, p2p->op_channel);
1445e5b75505Sopenharmony_ci	} else if (p2p_channel_select(&p2p->cfg->channels, op_classes_ht40,
1446e5b75505Sopenharmony_ci				      &p2p->op_reg_class, &p2p->op_channel) ==
1447e5b75505Sopenharmony_ci		   0) {
1448e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Select possible HT40 channel (op_class %u channel %u) as operating channel preference",
1449e5b75505Sopenharmony_ci			p2p->op_reg_class, p2p->op_channel);
1450e5b75505Sopenharmony_ci	} else if (p2p_channel_select(&p2p->cfg->channels, op_classes_5ghz,
1451e5b75505Sopenharmony_ci				      &p2p->op_reg_class, &p2p->op_channel) ==
1452e5b75505Sopenharmony_ci		   0) {
1453e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Select possible 5 GHz channel (op_class %u channel %u) as operating channel preference",
1454e5b75505Sopenharmony_ci			p2p->op_reg_class, p2p->op_channel);
1455e5b75505Sopenharmony_ci	} else if (p2p_channels_includes(&p2p->cfg->channels,
1456e5b75505Sopenharmony_ci					 p2p->cfg->op_reg_class,
1457e5b75505Sopenharmony_ci					 p2p->cfg->op_channel)) {
1458e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Select pre-configured channel as operating channel preference");
1459e5b75505Sopenharmony_ci		p2p->op_reg_class = p2p->cfg->op_reg_class;
1460e5b75505Sopenharmony_ci		p2p->op_channel = p2p->cfg->op_channel;
1461e5b75505Sopenharmony_ci	} else if (p2p_channel_random_social(&p2p->cfg->channels,
1462e5b75505Sopenharmony_ci					     &p2p->op_reg_class,
1463e5b75505Sopenharmony_ci					     &p2p->op_channel,
1464e5b75505Sopenharmony_ci					     NULL, NULL) == 0) {
1465e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Select random available social channel (op_class %u channel %u) as operating channel preference",
1466e5b75505Sopenharmony_ci			p2p->op_reg_class, p2p->op_channel);
1467e5b75505Sopenharmony_ci	} else {
1468e5b75505Sopenharmony_ci		/* Select any random available channel from the first available
1469e5b75505Sopenharmony_ci		 * operating class */
1470e5b75505Sopenharmony_ci		p2p_channel_select(&p2p->cfg->channels, NULL,
1471e5b75505Sopenharmony_ci				   &p2p->op_reg_class,
1472e5b75505Sopenharmony_ci				   &p2p->op_channel);
1473e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Select random available channel %d from operating class %d as operating channel preference",
1474e5b75505Sopenharmony_ci			p2p->op_channel, p2p->op_reg_class);
1475e5b75505Sopenharmony_ci	}
1476e5b75505Sopenharmony_ci
1477e5b75505Sopenharmony_ci	os_memcpy(&p2p->channels, &p2p->cfg->channels,
1478e5b75505Sopenharmony_ci		  sizeof(struct p2p_channels));
1479e5b75505Sopenharmony_ci}
1480e5b75505Sopenharmony_ci
1481e5b75505Sopenharmony_ci
1482e5b75505Sopenharmony_ci/**
1483e5b75505Sopenharmony_ci * p2p_prepare_channel - Select operating channel for GO Negotiation or P2PS PD
1484e5b75505Sopenharmony_ci * @p2p: P2P module context from p2p_init()
1485e5b75505Sopenharmony_ci * @dev: Selected peer device
1486e5b75505Sopenharmony_ci * @force_freq: Forced frequency in MHz or 0 if not forced
1487e5b75505Sopenharmony_ci * @pref_freq: Preferred frequency in MHz or 0 if no preference
1488e5b75505Sopenharmony_ci * @go: Whether the local end will be forced to be GO
1489e5b75505Sopenharmony_ci * Returns: 0 on success, -1 on failure (channel not supported for P2P)
1490e5b75505Sopenharmony_ci *
1491e5b75505Sopenharmony_ci * This function is used to do initial operating channel selection for GO
1492e5b75505Sopenharmony_ci * Negotiation prior to having received peer information or for P2PS PD
1493e5b75505Sopenharmony_ci * signalling. The selected channel may be further optimized in
1494e5b75505Sopenharmony_ci * p2p_reselect_channel() once the peer information is available.
1495e5b75505Sopenharmony_ci */
1496e5b75505Sopenharmony_ciint p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev,
1497e5b75505Sopenharmony_ci			unsigned int force_freq, unsigned int pref_freq, int go)
1498e5b75505Sopenharmony_ci{
1499e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Prepare channel - force_freq=%u pref_freq=%u go=%d",
1500e5b75505Sopenharmony_ci		force_freq, pref_freq, go);
1501e5b75505Sopenharmony_ci	if (force_freq || pref_freq) {
1502e5b75505Sopenharmony_ci		if (p2p_prepare_channel_pref(p2p, force_freq, pref_freq, go) <
1503e5b75505Sopenharmony_ci		    0)
1504e5b75505Sopenharmony_ci			return -1;
1505e5b75505Sopenharmony_ci	} else {
1506e5b75505Sopenharmony_ci		p2p_prepare_channel_best(p2p);
1507e5b75505Sopenharmony_ci	}
1508e5b75505Sopenharmony_ci	p2p_channels_dump(p2p, "prepared channels", &p2p->channels);
1509e5b75505Sopenharmony_ci	if (go)
1510e5b75505Sopenharmony_ci		p2p_channels_remove_freqs(&p2p->channels, &p2p->no_go_freq);
1511e5b75505Sopenharmony_ci	else if (!force_freq)
1512e5b75505Sopenharmony_ci		p2p_channels_union_inplace(&p2p->channels,
1513e5b75505Sopenharmony_ci					   &p2p->cfg->cli_channels);
1514e5b75505Sopenharmony_ci	p2p_channels_dump(p2p, "after go/cli filter/add", &p2p->channels);
1515e5b75505Sopenharmony_ci
1516e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Own preference for operation channel: Operating Class %u Channel %u%s",
1517e5b75505Sopenharmony_ci		p2p->op_reg_class, p2p->op_channel,
1518e5b75505Sopenharmony_ci		force_freq ? " (forced)" : "");
1519e5b75505Sopenharmony_ci
1520e5b75505Sopenharmony_ci	if (force_freq)
1521e5b75505Sopenharmony_ci		dev->flags |= P2P_DEV_FORCE_FREQ;
1522e5b75505Sopenharmony_ci	else
1523e5b75505Sopenharmony_ci		dev->flags &= ~P2P_DEV_FORCE_FREQ;
1524e5b75505Sopenharmony_ci
1525e5b75505Sopenharmony_ci	return 0;
1526e5b75505Sopenharmony_ci}
1527e5b75505Sopenharmony_ci
1528e5b75505Sopenharmony_ci
1529e5b75505Sopenharmony_cistatic void p2p_set_dev_persistent(struct p2p_device *dev,
1530e5b75505Sopenharmony_ci				   int persistent_group)
1531e5b75505Sopenharmony_ci{
1532e5b75505Sopenharmony_ci	switch (persistent_group) {
1533e5b75505Sopenharmony_ci	case 0:
1534e5b75505Sopenharmony_ci		dev->flags &= ~(P2P_DEV_PREFER_PERSISTENT_GROUP |
1535e5b75505Sopenharmony_ci				P2P_DEV_PREFER_PERSISTENT_RECONN);
1536e5b75505Sopenharmony_ci		break;
1537e5b75505Sopenharmony_ci	case 1:
1538e5b75505Sopenharmony_ci		dev->flags |= P2P_DEV_PREFER_PERSISTENT_GROUP;
1539e5b75505Sopenharmony_ci		dev->flags &= ~P2P_DEV_PREFER_PERSISTENT_RECONN;
1540e5b75505Sopenharmony_ci		break;
1541e5b75505Sopenharmony_ci	case 2:
1542e5b75505Sopenharmony_ci		dev->flags |= P2P_DEV_PREFER_PERSISTENT_GROUP |
1543e5b75505Sopenharmony_ci			P2P_DEV_PREFER_PERSISTENT_RECONN;
1544e5b75505Sopenharmony_ci		break;
1545e5b75505Sopenharmony_ci	}
1546e5b75505Sopenharmony_ci}
1547e5b75505Sopenharmony_ci
1548e5b75505Sopenharmony_ci
1549e5b75505Sopenharmony_ciint p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
1550e5b75505Sopenharmony_ci		enum p2p_wps_method wps_method,
1551e5b75505Sopenharmony_ci		int go_intent, const u8 *own_interface_addr,
1552e5b75505Sopenharmony_ci		unsigned int force_freq, int persistent_group,
1553e5b75505Sopenharmony_ci		const u8 *force_ssid, size_t force_ssid_len,
1554e5b75505Sopenharmony_ci		int pd_before_go_neg, unsigned int pref_freq, u16 oob_pw_id)
1555e5b75505Sopenharmony_ci{
1556e5b75505Sopenharmony_ci	struct p2p_device *dev;
1557e5b75505Sopenharmony_ci
1558e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Request to start group negotiation - peer=" MACSTR
1559e5b75505Sopenharmony_ci		"  GO Intent=%d  Intended Interface Address=" MACSTR
1560e5b75505Sopenharmony_ci		" wps_method=%d persistent_group=%d pd_before_go_neg=%d "
1561e5b75505Sopenharmony_ci		"oob_pw_id=%u",
1562e5b75505Sopenharmony_ci		MAC2STR(peer_addr), go_intent, MAC2STR(own_interface_addr),
1563e5b75505Sopenharmony_ci		wps_method, persistent_group, pd_before_go_neg, oob_pw_id);
1564e5b75505Sopenharmony_ci
1565e5b75505Sopenharmony_ci	dev = p2p_get_device(p2p, peer_addr);
1566e5b75505Sopenharmony_ci	if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
1567e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Cannot connect to unknown P2P Device " MACSTR,
1568e5b75505Sopenharmony_ci			MAC2STR(peer_addr));
1569e5b75505Sopenharmony_ci		return -1;
1570e5b75505Sopenharmony_ci	}
1571e5b75505Sopenharmony_ci
1572e5b75505Sopenharmony_ci	if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq,
1573e5b75505Sopenharmony_ci				go_intent == 15) < 0)
1574e5b75505Sopenharmony_ci		return -1;
1575e5b75505Sopenharmony_ci
1576e5b75505Sopenharmony_ci	if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) {
1577e5b75505Sopenharmony_ci		if (!(dev->info.dev_capab &
1578e5b75505Sopenharmony_ci		      P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) {
1579e5b75505Sopenharmony_ci			p2p_dbg(p2p, "Cannot connect to P2P Device " MACSTR
1580e5b75505Sopenharmony_ci				" that is in a group and is not discoverable",
1581e5b75505Sopenharmony_ci				MAC2STR(peer_addr));
1582e5b75505Sopenharmony_ci			return -1;
1583e5b75505Sopenharmony_ci		}
1584e5b75505Sopenharmony_ci		if (dev->oper_freq <= 0) {
1585e5b75505Sopenharmony_ci			p2p_dbg(p2p, "Cannot connect to P2P Device " MACSTR
1586e5b75505Sopenharmony_ci				" with incomplete information",
1587e5b75505Sopenharmony_ci				MAC2STR(peer_addr));
1588e5b75505Sopenharmony_ci			return -1;
1589e5b75505Sopenharmony_ci		}
1590e5b75505Sopenharmony_ci
1591e5b75505Sopenharmony_ci		/*
1592e5b75505Sopenharmony_ci		 * First, try to connect directly. If the peer does not
1593e5b75505Sopenharmony_ci		 * acknowledge frames, assume it is sleeping and use device
1594e5b75505Sopenharmony_ci		 * discoverability via the GO at that point.
1595e5b75505Sopenharmony_ci		 */
1596e5b75505Sopenharmony_ci	}
1597e5b75505Sopenharmony_ci
1598e5b75505Sopenharmony_ci	p2p->ssid_set = 0;
1599e5b75505Sopenharmony_ci	if (force_ssid) {
1600e5b75505Sopenharmony_ci		wpa_hexdump_ascii(MSG_DEBUG, "P2P: Forced SSID",
1601e5b75505Sopenharmony_ci				  force_ssid, force_ssid_len);
1602e5b75505Sopenharmony_ci		os_memcpy(p2p->ssid, force_ssid, force_ssid_len);
1603e5b75505Sopenharmony_ci		p2p->ssid_len = force_ssid_len;
1604e5b75505Sopenharmony_ci		p2p->ssid_set = 1;
1605e5b75505Sopenharmony_ci	}
1606e5b75505Sopenharmony_ci
1607e5b75505Sopenharmony_ci	dev->flags &= ~P2P_DEV_NOT_YET_READY;
1608e5b75505Sopenharmony_ci	dev->flags &= ~P2P_DEV_USER_REJECTED;
1609e5b75505Sopenharmony_ci	dev->flags &= ~P2P_DEV_WAIT_GO_NEG_RESPONSE;
1610e5b75505Sopenharmony_ci	dev->flags &= ~P2P_DEV_WAIT_GO_NEG_CONFIRM;
1611e5b75505Sopenharmony_ci	if (pd_before_go_neg)
1612e5b75505Sopenharmony_ci		dev->flags |= P2P_DEV_PD_BEFORE_GO_NEG;
1613e5b75505Sopenharmony_ci	else {
1614e5b75505Sopenharmony_ci		dev->flags &= ~P2P_DEV_PD_BEFORE_GO_NEG;
1615e5b75505Sopenharmony_ci		/*
1616e5b75505Sopenharmony_ci		 * Assign dialog token and tie breaker here to use the same
1617e5b75505Sopenharmony_ci		 * values in each retry within the same GO Negotiation exchange.
1618e5b75505Sopenharmony_ci		 */
1619e5b75505Sopenharmony_ci		dev->dialog_token++;
1620e5b75505Sopenharmony_ci		if (dev->dialog_token == 0)
1621e5b75505Sopenharmony_ci			dev->dialog_token = 1;
1622e5b75505Sopenharmony_ci		dev->tie_breaker = p2p->next_tie_breaker;
1623e5b75505Sopenharmony_ci		p2p->next_tie_breaker = !p2p->next_tie_breaker;
1624e5b75505Sopenharmony_ci	}
1625e5b75505Sopenharmony_ci	dev->connect_reqs = 0;
1626e5b75505Sopenharmony_ci	dev->go_neg_req_sent = 0;
1627e5b75505Sopenharmony_ci	dev->go_state = UNKNOWN_GO;
1628e5b75505Sopenharmony_ci	p2p_set_dev_persistent(dev, persistent_group);
1629e5b75505Sopenharmony_ci	p2p->go_intent = go_intent;
1630e5b75505Sopenharmony_ci	os_memcpy(p2p->intended_addr, own_interface_addr, ETH_ALEN);
1631e5b75505Sopenharmony_ci
1632e5b75505Sopenharmony_ci	if (p2p->state != P2P_IDLE)
1633e5b75505Sopenharmony_ci		p2p_stop_find(p2p);
1634e5b75505Sopenharmony_ci
1635e5b75505Sopenharmony_ci	dev->wps_method = wps_method;
1636e5b75505Sopenharmony_ci	dev->oob_pw_id = oob_pw_id;
1637e5b75505Sopenharmony_ci	dev->status = P2P_SC_SUCCESS;
1638e5b75505Sopenharmony_ci
1639e5b75505Sopenharmony_ci	if (p2p->p2p_scan_running) {
1640e5b75505Sopenharmony_ci		p2p_dbg(p2p, "p2p_scan running - delay connect send");
1641e5b75505Sopenharmony_ci		p2p->start_after_scan = P2P_AFTER_SCAN_CONNECT;
1642e5b75505Sopenharmony_ci		os_memcpy(p2p->after_scan_peer, peer_addr, ETH_ALEN);
1643e5b75505Sopenharmony_ci		return 0;
1644e5b75505Sopenharmony_ci	}
1645e5b75505Sopenharmony_ci
1646e5b75505Sopenharmony_ci	return p2p_connect_send(p2p, dev);
1647e5b75505Sopenharmony_ci}
1648e5b75505Sopenharmony_ci
1649e5b75505Sopenharmony_ci
1650e5b75505Sopenharmony_ciint p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr,
1651e5b75505Sopenharmony_ci		  enum p2p_wps_method wps_method,
1652e5b75505Sopenharmony_ci		  int go_intent, const u8 *own_interface_addr,
1653e5b75505Sopenharmony_ci		  unsigned int force_freq, int persistent_group,
1654e5b75505Sopenharmony_ci		  const u8 *force_ssid, size_t force_ssid_len,
1655e5b75505Sopenharmony_ci		  unsigned int pref_freq, u16 oob_pw_id)
1656e5b75505Sopenharmony_ci{
1657e5b75505Sopenharmony_ci	struct p2p_device *dev;
1658e5b75505Sopenharmony_ci
1659e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Request to authorize group negotiation - peer=" MACSTR
1660e5b75505Sopenharmony_ci		"  GO Intent=%d  Intended Interface Address=" MACSTR
1661e5b75505Sopenharmony_ci		" wps_method=%d  persistent_group=%d oob_pw_id=%u",
1662e5b75505Sopenharmony_ci		MAC2STR(peer_addr), go_intent, MAC2STR(own_interface_addr),
1663e5b75505Sopenharmony_ci		wps_method, persistent_group, oob_pw_id);
1664e5b75505Sopenharmony_ci
1665e5b75505Sopenharmony_ci	dev = p2p_get_device(p2p, peer_addr);
1666e5b75505Sopenharmony_ci	if (dev == NULL) {
1667e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Cannot authorize unknown P2P Device " MACSTR,
1668e5b75505Sopenharmony_ci			MAC2STR(peer_addr));
1669e5b75505Sopenharmony_ci		return -1;
1670e5b75505Sopenharmony_ci	}
1671e5b75505Sopenharmony_ci
1672e5b75505Sopenharmony_ci	if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq, go_intent ==
1673e5b75505Sopenharmony_ci				15) < 0)
1674e5b75505Sopenharmony_ci		return -1;
1675e5b75505Sopenharmony_ci
1676e5b75505Sopenharmony_ci	p2p->ssid_set = 0;
1677e5b75505Sopenharmony_ci	if (force_ssid) {
1678e5b75505Sopenharmony_ci		wpa_hexdump_ascii(MSG_DEBUG, "P2P: Forced SSID",
1679e5b75505Sopenharmony_ci				  force_ssid, force_ssid_len);
1680e5b75505Sopenharmony_ci		os_memcpy(p2p->ssid, force_ssid, force_ssid_len);
1681e5b75505Sopenharmony_ci		p2p->ssid_len = force_ssid_len;
1682e5b75505Sopenharmony_ci		p2p->ssid_set = 1;
1683e5b75505Sopenharmony_ci	}
1684e5b75505Sopenharmony_ci
1685e5b75505Sopenharmony_ci	dev->flags &= ~P2P_DEV_NOT_YET_READY;
1686e5b75505Sopenharmony_ci	dev->flags &= ~P2P_DEV_USER_REJECTED;
1687e5b75505Sopenharmony_ci	dev->go_neg_req_sent = 0;
1688e5b75505Sopenharmony_ci	dev->go_state = UNKNOWN_GO;
1689e5b75505Sopenharmony_ci	p2p_set_dev_persistent(dev, persistent_group);
1690e5b75505Sopenharmony_ci	p2p->go_intent = go_intent;
1691e5b75505Sopenharmony_ci	os_memcpy(p2p->intended_addr, own_interface_addr, ETH_ALEN);
1692e5b75505Sopenharmony_ci
1693e5b75505Sopenharmony_ci	dev->wps_method = wps_method;
1694e5b75505Sopenharmony_ci	dev->oob_pw_id = oob_pw_id;
1695e5b75505Sopenharmony_ci	dev->status = P2P_SC_SUCCESS;
1696e5b75505Sopenharmony_ci
1697e5b75505Sopenharmony_ci	return 0;
1698e5b75505Sopenharmony_ci}
1699e5b75505Sopenharmony_ci
1700e5b75505Sopenharmony_ci
1701e5b75505Sopenharmony_civoid p2p_add_dev_info(struct p2p_data *p2p, const u8 *addr,
1702e5b75505Sopenharmony_ci		      struct p2p_device *dev, struct p2p_message *msg)
1703e5b75505Sopenharmony_ci{
1704e5b75505Sopenharmony_ci	os_get_reltime(&dev->last_seen);
1705e5b75505Sopenharmony_ci
1706e5b75505Sopenharmony_ci	p2p_copy_wps_info(p2p, dev, 0, msg);
1707e5b75505Sopenharmony_ci
1708e5b75505Sopenharmony_ci	if (msg->listen_channel) {
1709e5b75505Sopenharmony_ci		int freq;
1710e5b75505Sopenharmony_ci		freq = p2p_channel_to_freq(msg->listen_channel[3],
1711e5b75505Sopenharmony_ci					   msg->listen_channel[4]);
1712e5b75505Sopenharmony_ci		if (freq < 0) {
1713e5b75505Sopenharmony_ci			p2p_dbg(p2p, "Unknown peer Listen channel: "
1714e5b75505Sopenharmony_ci				"country=%c%c(0x%02x) reg_class=%u channel=%u",
1715e5b75505Sopenharmony_ci				msg->listen_channel[0],
1716e5b75505Sopenharmony_ci				msg->listen_channel[1],
1717e5b75505Sopenharmony_ci				msg->listen_channel[2],
1718e5b75505Sopenharmony_ci				msg->listen_channel[3],
1719e5b75505Sopenharmony_ci				msg->listen_channel[4]);
1720e5b75505Sopenharmony_ci		} else {
1721e5b75505Sopenharmony_ci			p2p_dbg(p2p, "Update peer " MACSTR
1722e5b75505Sopenharmony_ci				" Listen channel: %u -> %u MHz",
1723e5b75505Sopenharmony_ci				MAC2STR(dev->info.p2p_device_addr),
1724e5b75505Sopenharmony_ci				dev->listen_freq, freq);
1725e5b75505Sopenharmony_ci			dev->listen_freq = freq;
1726e5b75505Sopenharmony_ci		}
1727e5b75505Sopenharmony_ci	}
1728e5b75505Sopenharmony_ci
1729e5b75505Sopenharmony_ci	if (msg->wfd_subelems) {
1730e5b75505Sopenharmony_ci		wpabuf_free(dev->info.wfd_subelems);
1731e5b75505Sopenharmony_ci		dev->info.wfd_subelems = wpabuf_dup(msg->wfd_subelems);
1732e5b75505Sopenharmony_ci	}
1733e5b75505Sopenharmony_ci
1734e5b75505Sopenharmony_ci	if (dev->flags & P2P_DEV_PROBE_REQ_ONLY) {
1735e5b75505Sopenharmony_ci		dev->flags &= ~P2P_DEV_PROBE_REQ_ONLY;
1736e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Completed device entry based on data from GO Negotiation Request");
1737e5b75505Sopenharmony_ci	} else {
1738e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Created device entry based on GO Neg Req: "
1739e5b75505Sopenharmony_ci			MACSTR " dev_capab=0x%x group_capab=0x%x name='%s' "
1740e5b75505Sopenharmony_ci			"listen_freq=%d",
1741e5b75505Sopenharmony_ci			MAC2STR(dev->info.p2p_device_addr),
1742e5b75505Sopenharmony_ci			dev->info.dev_capab, dev->info.group_capab,
1743e5b75505Sopenharmony_ci			dev->info.device_name, dev->listen_freq);
1744e5b75505Sopenharmony_ci	}
1745e5b75505Sopenharmony_ci
1746e5b75505Sopenharmony_ci	dev->flags &= ~P2P_DEV_GROUP_CLIENT_ONLY;
1747e5b75505Sopenharmony_ci
1748e5b75505Sopenharmony_ci	if (dev->flags & P2P_DEV_USER_REJECTED) {
1749e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Do not report rejected device");
1750e5b75505Sopenharmony_ci		return;
1751e5b75505Sopenharmony_ci	}
1752e5b75505Sopenharmony_ci
1753e5b75505Sopenharmony_ci	p2p->cfg->dev_found(p2p->cfg->cb_ctx, addr, &dev->info,
1754e5b75505Sopenharmony_ci			    !(dev->flags & P2P_DEV_REPORTED_ONCE));
1755e5b75505Sopenharmony_ci	dev->flags |= P2P_DEV_REPORTED | P2P_DEV_REPORTED_ONCE;
1756e5b75505Sopenharmony_ci}
1757e5b75505Sopenharmony_ci
1758e5b75505Sopenharmony_ci
1759e5b75505Sopenharmony_civoid p2p_build_ssid(struct p2p_data *p2p, u8 *ssid, size_t *ssid_len)
1760e5b75505Sopenharmony_ci{
1761e5b75505Sopenharmony_ci	os_memcpy(ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN);
1762e5b75505Sopenharmony_ci	p2p_random((char *) &ssid[P2P_WILDCARD_SSID_LEN], 2);
1763e5b75505Sopenharmony_ci	os_memcpy(&ssid[P2P_WILDCARD_SSID_LEN + 2],
1764e5b75505Sopenharmony_ci		  p2p->cfg->ssid_postfix, p2p->cfg->ssid_postfix_len);
1765e5b75505Sopenharmony_ci	*ssid_len = P2P_WILDCARD_SSID_LEN + 2 + p2p->cfg->ssid_postfix_len;
1766e5b75505Sopenharmony_ci}
1767e5b75505Sopenharmony_ci
1768e5b75505Sopenharmony_ci
1769e5b75505Sopenharmony_ciint p2p_go_params(struct p2p_data *p2p, struct p2p_go_neg_results *params)
1770e5b75505Sopenharmony_ci{
1771e5b75505Sopenharmony_ci	if (p2p->ssid_set) {
1772e5b75505Sopenharmony_ci		os_memcpy(params->ssid, p2p->ssid, p2p->ssid_len);
1773e5b75505Sopenharmony_ci		params->ssid_len = p2p->ssid_len;
1774e5b75505Sopenharmony_ci	} else {
1775e5b75505Sopenharmony_ci		p2p_build_ssid(p2p, params->ssid, &params->ssid_len);
1776e5b75505Sopenharmony_ci	}
1777e5b75505Sopenharmony_ci	p2p->ssid_set = 0;
1778e5b75505Sopenharmony_ci
1779e5b75505Sopenharmony_ci	p2p_random(params->passphrase, p2p->cfg->passphrase_len);
1780e5b75505Sopenharmony_ci	return 0;
1781e5b75505Sopenharmony_ci}
1782e5b75505Sopenharmony_ci
1783e5b75505Sopenharmony_ci
1784e5b75505Sopenharmony_civoid p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer)
1785e5b75505Sopenharmony_ci{
1786e5b75505Sopenharmony_ci	struct p2p_go_neg_results res;
1787e5b75505Sopenharmony_ci	int go = peer->go_state == LOCAL_GO;
1788e5b75505Sopenharmony_ci	struct p2p_channels intersection;
1789e5b75505Sopenharmony_ci
1790e5b75505Sopenharmony_ci	p2p_dbg(p2p, "GO Negotiation with " MACSTR " completed (%s will be GO)",
1791e5b75505Sopenharmony_ci		MAC2STR(peer->info.p2p_device_addr), go ? "local end" : "peer");
1792e5b75505Sopenharmony_ci
1793e5b75505Sopenharmony_ci	os_memset(&res, 0, sizeof(res));
1794e5b75505Sopenharmony_ci	res.role_go = go;
1795e5b75505Sopenharmony_ci	os_memcpy(res.peer_device_addr, peer->info.p2p_device_addr, ETH_ALEN);
1796e5b75505Sopenharmony_ci	os_memcpy(res.peer_interface_addr, peer->intended_addr, ETH_ALEN);
1797e5b75505Sopenharmony_ci	res.wps_method = peer->wps_method;
1798e5b75505Sopenharmony_ci	if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) {
1799e5b75505Sopenharmony_ci		if (peer->flags & P2P_DEV_PREFER_PERSISTENT_RECONN)
1800e5b75505Sopenharmony_ci			res.persistent_group = 2;
1801e5b75505Sopenharmony_ci		else
1802e5b75505Sopenharmony_ci			res.persistent_group = 1;
1803e5b75505Sopenharmony_ci	}
1804e5b75505Sopenharmony_ci
1805e5b75505Sopenharmony_ci	if (go) {
1806e5b75505Sopenharmony_ci		/* Setup AP mode for WPS provisioning */
1807e5b75505Sopenharmony_ci		res.freq = p2p_channel_to_freq(p2p->op_reg_class,
1808e5b75505Sopenharmony_ci					       p2p->op_channel);
1809e5b75505Sopenharmony_ci		os_memcpy(res.ssid, p2p->ssid, p2p->ssid_len);
1810e5b75505Sopenharmony_ci		res.ssid_len = p2p->ssid_len;
1811e5b75505Sopenharmony_ci		p2p_random(res.passphrase, p2p->cfg->passphrase_len);
1812e5b75505Sopenharmony_ci	} else {
1813e5b75505Sopenharmony_ci		res.freq = peer->oper_freq;
1814e5b75505Sopenharmony_ci		if (p2p->ssid_len) {
1815e5b75505Sopenharmony_ci			os_memcpy(res.ssid, p2p->ssid, p2p->ssid_len);
1816e5b75505Sopenharmony_ci			res.ssid_len = p2p->ssid_len;
1817e5b75505Sopenharmony_ci		}
1818e5b75505Sopenharmony_ci	}
1819e5b75505Sopenharmony_ci
1820e5b75505Sopenharmony_ci	p2p_channels_dump(p2p, "own channels", &p2p->channels);
1821e5b75505Sopenharmony_ci	p2p_channels_dump(p2p, "peer channels", &peer->channels);
1822e5b75505Sopenharmony_ci	p2p_channels_intersect(&p2p->channels, &peer->channels,
1823e5b75505Sopenharmony_ci			       &intersection);
1824e5b75505Sopenharmony_ci	if (go) {
1825e5b75505Sopenharmony_ci		p2p_channels_remove_freqs(&intersection, &p2p->no_go_freq);
1826e5b75505Sopenharmony_ci		p2p_channels_dump(p2p, "intersection after no-GO removal",
1827e5b75505Sopenharmony_ci				  &intersection);
1828e5b75505Sopenharmony_ci	}
1829e5b75505Sopenharmony_ci
1830e5b75505Sopenharmony_ci	p2p_channels_to_freqs(&intersection, res.freq_list,
1831e5b75505Sopenharmony_ci			      P2P_MAX_CHANNELS);
1832e5b75505Sopenharmony_ci
1833e5b75505Sopenharmony_ci	res.peer_config_timeout = go ? peer->client_timeout : peer->go_timeout;
1834e5b75505Sopenharmony_ci
1835e5b75505Sopenharmony_ci	p2p_clear_timeout(p2p);
1836e5b75505Sopenharmony_ci	p2p->ssid_set = 0;
1837e5b75505Sopenharmony_ci	peer->go_neg_req_sent = 0;
1838e5b75505Sopenharmony_ci	peer->flags &= ~P2P_DEV_PEER_WAITING_RESPONSE;
1839e5b75505Sopenharmony_ci	peer->wps_method = WPS_NOT_READY;
1840e5b75505Sopenharmony_ci	peer->oob_pw_id = 0;
1841e5b75505Sopenharmony_ci	wpabuf_free(peer->go_neg_conf);
1842e5b75505Sopenharmony_ci	peer->go_neg_conf = NULL;
1843e5b75505Sopenharmony_ci
1844e5b75505Sopenharmony_ci	p2p_set_state(p2p, P2P_PROVISIONING);
1845e5b75505Sopenharmony_ci	p2p->cfg->go_neg_completed(p2p->cfg->cb_ctx, &res);
1846e5b75505Sopenharmony_ci}
1847e5b75505Sopenharmony_ci
1848e5b75505Sopenharmony_ci
1849e5b75505Sopenharmony_cistatic void p2p_rx_p2p_action(struct p2p_data *p2p, const u8 *sa,
1850e5b75505Sopenharmony_ci			      const u8 *data, size_t len, int rx_freq)
1851e5b75505Sopenharmony_ci{
1852e5b75505Sopenharmony_ci	p2p_dbg(p2p, "RX P2P Public Action from " MACSTR, MAC2STR(sa));
1853e5b75505Sopenharmony_ci	wpa_hexdump(MSG_MSGDUMP, "P2P: P2P Public Action contents", data, len);
1854e5b75505Sopenharmony_ci
1855e5b75505Sopenharmony_ci	if (len < 1)
1856e5b75505Sopenharmony_ci		return;
1857e5b75505Sopenharmony_ci
1858e5b75505Sopenharmony_ci	switch (data[0]) {
1859e5b75505Sopenharmony_ci	case P2P_GO_NEG_REQ:
1860e5b75505Sopenharmony_ci		p2p_process_go_neg_req(p2p, sa, data + 1, len - 1, rx_freq);
1861e5b75505Sopenharmony_ci		break;
1862e5b75505Sopenharmony_ci	case P2P_GO_NEG_RESP:
1863e5b75505Sopenharmony_ci		p2p_process_go_neg_resp(p2p, sa, data + 1, len - 1, rx_freq);
1864e5b75505Sopenharmony_ci		break;
1865e5b75505Sopenharmony_ci	case P2P_GO_NEG_CONF:
1866e5b75505Sopenharmony_ci		p2p_process_go_neg_conf(p2p, sa, data + 1, len - 1);
1867e5b75505Sopenharmony_ci		break;
1868e5b75505Sopenharmony_ci	case P2P_INVITATION_REQ:
1869e5b75505Sopenharmony_ci		p2p_process_invitation_req(p2p, sa, data + 1, len - 1,
1870e5b75505Sopenharmony_ci					   rx_freq);
1871e5b75505Sopenharmony_ci		break;
1872e5b75505Sopenharmony_ci	case P2P_INVITATION_RESP:
1873e5b75505Sopenharmony_ci		p2p_process_invitation_resp(p2p, sa, data + 1, len - 1);
1874e5b75505Sopenharmony_ci		break;
1875e5b75505Sopenharmony_ci	case P2P_PROV_DISC_REQ:
1876e5b75505Sopenharmony_ci		p2p_process_prov_disc_req(p2p, sa, data + 1, len - 1, rx_freq);
1877e5b75505Sopenharmony_ci		break;
1878e5b75505Sopenharmony_ci	case P2P_PROV_DISC_RESP:
1879e5b75505Sopenharmony_ci		p2p_process_prov_disc_resp(p2p, sa, data + 1, len - 1);
1880e5b75505Sopenharmony_ci		break;
1881e5b75505Sopenharmony_ci	case P2P_DEV_DISC_REQ:
1882e5b75505Sopenharmony_ci		p2p_process_dev_disc_req(p2p, sa, data + 1, len - 1, rx_freq);
1883e5b75505Sopenharmony_ci		break;
1884e5b75505Sopenharmony_ci	case P2P_DEV_DISC_RESP:
1885e5b75505Sopenharmony_ci		p2p_process_dev_disc_resp(p2p, sa, data + 1, len - 1);
1886e5b75505Sopenharmony_ci		break;
1887e5b75505Sopenharmony_ci	default:
1888e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Unsupported P2P Public Action frame type %d",
1889e5b75505Sopenharmony_ci			data[0]);
1890e5b75505Sopenharmony_ci		break;
1891e5b75505Sopenharmony_ci	}
1892e5b75505Sopenharmony_ci}
1893e5b75505Sopenharmony_ci
1894e5b75505Sopenharmony_ci
1895e5b75505Sopenharmony_cistatic void p2p_rx_action_public(struct p2p_data *p2p, const u8 *da,
1896e5b75505Sopenharmony_ci				 const u8 *sa, const u8 *bssid, const u8 *data,
1897e5b75505Sopenharmony_ci				 size_t len, int freq)
1898e5b75505Sopenharmony_ci{
1899e5b75505Sopenharmony_ci	if (len < 1)
1900e5b75505Sopenharmony_ci		return;
1901e5b75505Sopenharmony_ci
1902e5b75505Sopenharmony_ci	switch (data[0]) {
1903e5b75505Sopenharmony_ci	case WLAN_PA_VENDOR_SPECIFIC:
1904e5b75505Sopenharmony_ci		data++;
1905e5b75505Sopenharmony_ci		len--;
1906e5b75505Sopenharmony_ci		if (len < 4)
1907e5b75505Sopenharmony_ci			return;
1908e5b75505Sopenharmony_ci		if (WPA_GET_BE32(data) != P2P_IE_VENDOR_TYPE)
1909e5b75505Sopenharmony_ci			return;
1910e5b75505Sopenharmony_ci
1911e5b75505Sopenharmony_ci		data += 4;
1912e5b75505Sopenharmony_ci		len -= 4;
1913e5b75505Sopenharmony_ci
1914e5b75505Sopenharmony_ci		p2p_rx_p2p_action(p2p, sa, data, len, freq);
1915e5b75505Sopenharmony_ci		break;
1916e5b75505Sopenharmony_ci	case WLAN_PA_GAS_INITIAL_REQ:
1917e5b75505Sopenharmony_ci		p2p_rx_gas_initial_req(p2p, sa, data + 1, len - 1, freq);
1918e5b75505Sopenharmony_ci		break;
1919e5b75505Sopenharmony_ci	case WLAN_PA_GAS_INITIAL_RESP:
1920e5b75505Sopenharmony_ci		p2p_rx_gas_initial_resp(p2p, sa, data + 1, len - 1, freq);
1921e5b75505Sopenharmony_ci		break;
1922e5b75505Sopenharmony_ci	case WLAN_PA_GAS_COMEBACK_REQ:
1923e5b75505Sopenharmony_ci		p2p_rx_gas_comeback_req(p2p, sa, data + 1, len - 1, freq);
1924e5b75505Sopenharmony_ci		break;
1925e5b75505Sopenharmony_ci	case WLAN_PA_GAS_COMEBACK_RESP:
1926e5b75505Sopenharmony_ci		p2p_rx_gas_comeback_resp(p2p, sa, data + 1, len - 1, freq);
1927e5b75505Sopenharmony_ci		break;
1928e5b75505Sopenharmony_ci	}
1929e5b75505Sopenharmony_ci}
1930e5b75505Sopenharmony_ci
1931e5b75505Sopenharmony_ci
1932e5b75505Sopenharmony_civoid p2p_rx_action(struct p2p_data *p2p, const u8 *da, const u8 *sa,
1933e5b75505Sopenharmony_ci		   const u8 *bssid, u8 category,
1934e5b75505Sopenharmony_ci		   const u8 *data, size_t len, int freq)
1935e5b75505Sopenharmony_ci{
1936e5b75505Sopenharmony_ci	if (category == WLAN_ACTION_PUBLIC) {
1937e5b75505Sopenharmony_ci		p2p_rx_action_public(p2p, da, sa, bssid, data, len, freq);
1938e5b75505Sopenharmony_ci		return;
1939e5b75505Sopenharmony_ci	}
1940e5b75505Sopenharmony_ci
1941e5b75505Sopenharmony_ci	if (category != WLAN_ACTION_VENDOR_SPECIFIC)
1942e5b75505Sopenharmony_ci		return;
1943e5b75505Sopenharmony_ci
1944e5b75505Sopenharmony_ci	if (len < 4)
1945e5b75505Sopenharmony_ci		return;
1946e5b75505Sopenharmony_ci
1947e5b75505Sopenharmony_ci	if (WPA_GET_BE32(data) != P2P_IE_VENDOR_TYPE)
1948e5b75505Sopenharmony_ci		return;
1949e5b75505Sopenharmony_ci	data += 4;
1950e5b75505Sopenharmony_ci	len -= 4;
1951e5b75505Sopenharmony_ci
1952e5b75505Sopenharmony_ci	/* P2P action frame */
1953e5b75505Sopenharmony_ci	p2p_dbg(p2p, "RX P2P Action from " MACSTR, MAC2STR(sa));
1954e5b75505Sopenharmony_ci	wpa_hexdump(MSG_MSGDUMP, "P2P: P2P Action contents", data, len);
1955e5b75505Sopenharmony_ci
1956e5b75505Sopenharmony_ci	if (len < 1)
1957e5b75505Sopenharmony_ci		return;
1958e5b75505Sopenharmony_ci	switch (data[0]) {
1959e5b75505Sopenharmony_ci	case P2P_NOA:
1960e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Received P2P Action - Notice of Absence");
1961e5b75505Sopenharmony_ci		/* TODO */
1962e5b75505Sopenharmony_ci		break;
1963e5b75505Sopenharmony_ci	case P2P_PRESENCE_REQ:
1964e5b75505Sopenharmony_ci		p2p_process_presence_req(p2p, da, sa, data + 1, len - 1, freq);
1965e5b75505Sopenharmony_ci		break;
1966e5b75505Sopenharmony_ci	case P2P_PRESENCE_RESP:
1967e5b75505Sopenharmony_ci		p2p_process_presence_resp(p2p, da, sa, data + 1, len - 1);
1968e5b75505Sopenharmony_ci		break;
1969e5b75505Sopenharmony_ci	case P2P_GO_DISC_REQ:
1970e5b75505Sopenharmony_ci		p2p_process_go_disc_req(p2p, da, sa, data + 1, len - 1, freq);
1971e5b75505Sopenharmony_ci		break;
1972e5b75505Sopenharmony_ci	default:
1973e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Received P2P Action - unknown type %u", data[0]);
1974e5b75505Sopenharmony_ci		break;
1975e5b75505Sopenharmony_ci	}
1976e5b75505Sopenharmony_ci}
1977e5b75505Sopenharmony_ci
1978e5b75505Sopenharmony_ci
1979e5b75505Sopenharmony_cistatic void p2p_go_neg_start(void *eloop_ctx, void *timeout_ctx)
1980e5b75505Sopenharmony_ci{
1981e5b75505Sopenharmony_ci	struct p2p_data *p2p = eloop_ctx;
1982e5b75505Sopenharmony_ci	if (p2p->go_neg_peer == NULL)
1983e5b75505Sopenharmony_ci		return;
1984e5b75505Sopenharmony_ci	if (p2p->pending_listen_freq) {
1985e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Clear pending_listen_freq for p2p_go_neg_start");
1986e5b75505Sopenharmony_ci		p2p->pending_listen_freq = 0;
1987e5b75505Sopenharmony_ci	}
1988e5b75505Sopenharmony_ci	p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
1989e5b75505Sopenharmony_ci	p2p->go_neg_peer->status = P2P_SC_SUCCESS;
1990e5b75505Sopenharmony_ci	/*
1991e5b75505Sopenharmony_ci	 * Set new timeout to make sure a previously set one does not expire
1992e5b75505Sopenharmony_ci	 * too quickly while waiting for the GO Negotiation to complete.
1993e5b75505Sopenharmony_ci	 */
1994e5b75505Sopenharmony_ci	p2p_set_timeout(p2p, 0, 500000);
1995e5b75505Sopenharmony_ci	p2p_connect_send(p2p, p2p->go_neg_peer);
1996e5b75505Sopenharmony_ci}
1997e5b75505Sopenharmony_ci
1998e5b75505Sopenharmony_ci
1999e5b75505Sopenharmony_cistatic void p2p_invite_start(void *eloop_ctx, void *timeout_ctx)
2000e5b75505Sopenharmony_ci{
2001e5b75505Sopenharmony_ci	struct p2p_data *p2p = eloop_ctx;
2002e5b75505Sopenharmony_ci	if (p2p->invite_peer == NULL)
2003e5b75505Sopenharmony_ci		return;
2004e5b75505Sopenharmony_ci	if (p2p->pending_listen_freq) {
2005e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Clear pending_listen_freq for p2p_invite_start");
2006e5b75505Sopenharmony_ci		p2p->pending_listen_freq = 0;
2007e5b75505Sopenharmony_ci	}
2008e5b75505Sopenharmony_ci	p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
2009e5b75505Sopenharmony_ci	p2p_invite_send(p2p, p2p->invite_peer, p2p->invite_go_dev_addr,
2010e5b75505Sopenharmony_ci			p2p->invite_dev_pw_id);
2011e5b75505Sopenharmony_ci}
2012e5b75505Sopenharmony_ci
2013e5b75505Sopenharmony_ci
2014e5b75505Sopenharmony_cistatic void p2p_add_dev_from_probe_req(struct p2p_data *p2p, const u8 *addr,
2015e5b75505Sopenharmony_ci				       const u8 *ie, size_t ie_len)
2016e5b75505Sopenharmony_ci{
2017e5b75505Sopenharmony_ci	struct p2p_message msg;
2018e5b75505Sopenharmony_ci	struct p2p_device *dev;
2019e5b75505Sopenharmony_ci
2020e5b75505Sopenharmony_ci	os_memset(&msg, 0, sizeof(msg));
2021e5b75505Sopenharmony_ci	if (p2p_parse_ies(ie, ie_len, &msg) < 0 || msg.p2p_attributes == NULL)
2022e5b75505Sopenharmony_ci	{
2023e5b75505Sopenharmony_ci		p2p_parse_free(&msg);
2024e5b75505Sopenharmony_ci		return; /* not a P2P probe */
2025e5b75505Sopenharmony_ci	}
2026e5b75505Sopenharmony_ci
2027e5b75505Sopenharmony_ci	if (msg.ssid == NULL || msg.ssid[1] != P2P_WILDCARD_SSID_LEN ||
2028e5b75505Sopenharmony_ci	    os_memcmp(msg.ssid + 2, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN)
2029e5b75505Sopenharmony_ci	    != 0) {
2030e5b75505Sopenharmony_ci		/* The Probe Request is not part of P2P Device Discovery. It is
2031e5b75505Sopenharmony_ci		 * not known whether the source address of the frame is the P2P
2032e5b75505Sopenharmony_ci		 * Device Address or P2P Interface Address. Do not add a new
2033e5b75505Sopenharmony_ci		 * peer entry based on this frames.
2034e5b75505Sopenharmony_ci		 */
2035e5b75505Sopenharmony_ci		p2p_parse_free(&msg);
2036e5b75505Sopenharmony_ci		return;
2037e5b75505Sopenharmony_ci	}
2038e5b75505Sopenharmony_ci
2039e5b75505Sopenharmony_ci	dev = p2p_get_device(p2p, addr);
2040e5b75505Sopenharmony_ci	if (dev) {
2041e5b75505Sopenharmony_ci		if (msg.listen_channel) {
2042e5b75505Sopenharmony_ci			int freq;
2043e5b75505Sopenharmony_ci
2044e5b75505Sopenharmony_ci			if (dev->country[0] == 0)
2045e5b75505Sopenharmony_ci				os_memcpy(dev->country, msg.listen_channel, 3);
2046e5b75505Sopenharmony_ci
2047e5b75505Sopenharmony_ci			freq = p2p_channel_to_freq(msg.listen_channel[3],
2048e5b75505Sopenharmony_ci						   msg.listen_channel[4]);
2049e5b75505Sopenharmony_ci
2050e5b75505Sopenharmony_ci			if (freq > 0 && dev->listen_freq != freq) {
2051e5b75505Sopenharmony_ci				p2p_dbg(p2p,
2052e5b75505Sopenharmony_ci					"Updated peer " MACSTR " Listen channel (Probe Request): %d -> %d MHz",
2053e5b75505Sopenharmony_ci					MAC2STR(addr), dev->listen_freq, freq);
2054e5b75505Sopenharmony_ci				dev->listen_freq = freq;
2055e5b75505Sopenharmony_ci			}
2056e5b75505Sopenharmony_ci		}
2057e5b75505Sopenharmony_ci
2058e5b75505Sopenharmony_ci		os_get_reltime(&dev->last_seen);
2059e5b75505Sopenharmony_ci		p2p_parse_free(&msg);
2060e5b75505Sopenharmony_ci		return; /* already known */
2061e5b75505Sopenharmony_ci	}
2062e5b75505Sopenharmony_ci
2063e5b75505Sopenharmony_ci	dev = p2p_create_device(p2p, addr);
2064e5b75505Sopenharmony_ci	if (dev == NULL) {
2065e5b75505Sopenharmony_ci		p2p_parse_free(&msg);
2066e5b75505Sopenharmony_ci		return;
2067e5b75505Sopenharmony_ci	}
2068e5b75505Sopenharmony_ci
2069e5b75505Sopenharmony_ci	os_get_reltime(&dev->last_seen);
2070e5b75505Sopenharmony_ci	dev->flags |= P2P_DEV_PROBE_REQ_ONLY;
2071e5b75505Sopenharmony_ci
2072e5b75505Sopenharmony_ci	if (msg.listen_channel) {
2073e5b75505Sopenharmony_ci		os_memcpy(dev->country, msg.listen_channel, 3);
2074e5b75505Sopenharmony_ci		dev->listen_freq = p2p_channel_to_freq(msg.listen_channel[3],
2075e5b75505Sopenharmony_ci						       msg.listen_channel[4]);
2076e5b75505Sopenharmony_ci	}
2077e5b75505Sopenharmony_ci
2078e5b75505Sopenharmony_ci	p2p_copy_wps_info(p2p, dev, 1, &msg);
2079e5b75505Sopenharmony_ci
2080e5b75505Sopenharmony_ci	if (msg.wfd_subelems) {
2081e5b75505Sopenharmony_ci		wpabuf_free(dev->info.wfd_subelems);
2082e5b75505Sopenharmony_ci		dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
2083e5b75505Sopenharmony_ci	}
2084e5b75505Sopenharmony_ci
2085e5b75505Sopenharmony_ci	p2p_parse_free(&msg);
2086e5b75505Sopenharmony_ci
2087e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Created device entry based on Probe Req: " MACSTR
2088e5b75505Sopenharmony_ci		" dev_capab=0x%x group_capab=0x%x name='%s' listen_freq=%d",
2089e5b75505Sopenharmony_ci		MAC2STR(dev->info.p2p_device_addr), dev->info.dev_capab,
2090e5b75505Sopenharmony_ci		dev->info.group_capab, dev->info.device_name,
2091e5b75505Sopenharmony_ci		dev->listen_freq);
2092e5b75505Sopenharmony_ci}
2093e5b75505Sopenharmony_ci
2094e5b75505Sopenharmony_ci
2095e5b75505Sopenharmony_cistruct p2p_device * p2p_add_dev_from_go_neg_req(struct p2p_data *p2p,
2096e5b75505Sopenharmony_ci						const u8 *addr,
2097e5b75505Sopenharmony_ci						struct p2p_message *msg)
2098e5b75505Sopenharmony_ci{
2099e5b75505Sopenharmony_ci	struct p2p_device *dev;
2100e5b75505Sopenharmony_ci
2101e5b75505Sopenharmony_ci	dev = p2p_get_device(p2p, addr);
2102e5b75505Sopenharmony_ci	if (dev) {
2103e5b75505Sopenharmony_ci		os_get_reltime(&dev->last_seen);
2104e5b75505Sopenharmony_ci		return dev; /* already known */
2105e5b75505Sopenharmony_ci	}
2106e5b75505Sopenharmony_ci
2107e5b75505Sopenharmony_ci	dev = p2p_create_device(p2p, addr);
2108e5b75505Sopenharmony_ci	if (dev == NULL)
2109e5b75505Sopenharmony_ci		return NULL;
2110e5b75505Sopenharmony_ci
2111e5b75505Sopenharmony_ci	p2p_add_dev_info(p2p, addr, dev, msg);
2112e5b75505Sopenharmony_ci
2113e5b75505Sopenharmony_ci	return dev;
2114e5b75505Sopenharmony_ci}
2115e5b75505Sopenharmony_ci
2116e5b75505Sopenharmony_ci
2117e5b75505Sopenharmony_cistatic int dev_type_match(const u8 *dev_type, const u8 *req_dev_type)
2118e5b75505Sopenharmony_ci{
2119e5b75505Sopenharmony_ci	if (os_memcmp(dev_type, req_dev_type, WPS_DEV_TYPE_LEN) == 0)
2120e5b75505Sopenharmony_ci		return 1;
2121e5b75505Sopenharmony_ci	if (os_memcmp(dev_type, req_dev_type, 2) == 0 &&
2122e5b75505Sopenharmony_ci	    WPA_GET_BE32(&req_dev_type[2]) == 0 &&
2123e5b75505Sopenharmony_ci	    WPA_GET_BE16(&req_dev_type[6]) == 0)
2124e5b75505Sopenharmony_ci		return 1; /* Category match with wildcard OUI/sub-category */
2125e5b75505Sopenharmony_ci	return 0;
2126e5b75505Sopenharmony_ci}
2127e5b75505Sopenharmony_ci
2128e5b75505Sopenharmony_ci
2129e5b75505Sopenharmony_ciint dev_type_list_match(const u8 *dev_type, const u8 *req_dev_type[],
2130e5b75505Sopenharmony_ci			size_t num_req_dev_type)
2131e5b75505Sopenharmony_ci{
2132e5b75505Sopenharmony_ci	size_t i;
2133e5b75505Sopenharmony_ci	for (i = 0; i < num_req_dev_type; i++) {
2134e5b75505Sopenharmony_ci		if (dev_type_match(dev_type, req_dev_type[i]))
2135e5b75505Sopenharmony_ci			return 1;
2136e5b75505Sopenharmony_ci	}
2137e5b75505Sopenharmony_ci	return 0;
2138e5b75505Sopenharmony_ci}
2139e5b75505Sopenharmony_ci
2140e5b75505Sopenharmony_ci
2141e5b75505Sopenharmony_ci/**
2142e5b75505Sopenharmony_ci * p2p_match_dev_type - Match local device type with requested type
2143e5b75505Sopenharmony_ci * @p2p: P2P module context from p2p_init()
2144e5b75505Sopenharmony_ci * @wps: WPS TLVs from Probe Request frame (concatenated WPS IEs)
2145e5b75505Sopenharmony_ci * Returns: 1 on match, 0 on mismatch
2146e5b75505Sopenharmony_ci *
2147e5b75505Sopenharmony_ci * This function can be used to match the Requested Device Type attribute in
2148e5b75505Sopenharmony_ci * WPS IE with the local device types for deciding whether to reply to a Probe
2149e5b75505Sopenharmony_ci * Request frame.
2150e5b75505Sopenharmony_ci */
2151e5b75505Sopenharmony_ciint p2p_match_dev_type(struct p2p_data *p2p, struct wpabuf *wps)
2152e5b75505Sopenharmony_ci{
2153e5b75505Sopenharmony_ci	struct wps_parse_attr attr;
2154e5b75505Sopenharmony_ci	size_t i;
2155e5b75505Sopenharmony_ci
2156e5b75505Sopenharmony_ci	if (wps_parse_msg(wps, &attr))
2157e5b75505Sopenharmony_ci		return 1; /* assume no Requested Device Type attributes */
2158e5b75505Sopenharmony_ci
2159e5b75505Sopenharmony_ci	if (attr.num_req_dev_type == 0)
2160e5b75505Sopenharmony_ci		return 1; /* no Requested Device Type attributes -> match */
2161e5b75505Sopenharmony_ci
2162e5b75505Sopenharmony_ci	if (dev_type_list_match(p2p->cfg->pri_dev_type, attr.req_dev_type,
2163e5b75505Sopenharmony_ci				attr.num_req_dev_type))
2164e5b75505Sopenharmony_ci		return 1; /* Own Primary Device Type matches */
2165e5b75505Sopenharmony_ci
2166e5b75505Sopenharmony_ci	for (i = 0; i < p2p->cfg->num_sec_dev_types; i++) {
2167e5b75505Sopenharmony_ci		if (dev_type_list_match(p2p->cfg->sec_dev_type[i],
2168e5b75505Sopenharmony_ci					attr.req_dev_type,
2169e5b75505Sopenharmony_ci					attr.num_req_dev_type))
2170e5b75505Sopenharmony_ci			return 1; /* Own Secondary Device Type matches */
2171e5b75505Sopenharmony_ci	}
2172e5b75505Sopenharmony_ci
2173e5b75505Sopenharmony_ci	/* No matching device type found */
2174e5b75505Sopenharmony_ci	return 0;
2175e5b75505Sopenharmony_ci}
2176e5b75505Sopenharmony_ci
2177e5b75505Sopenharmony_ci
2178e5b75505Sopenharmony_cistruct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p,
2179e5b75505Sopenharmony_ci					 const u8 *query_hash,
2180e5b75505Sopenharmony_ci					 u8 query_count)
2181e5b75505Sopenharmony_ci{
2182e5b75505Sopenharmony_ci	struct wpabuf *buf;
2183e5b75505Sopenharmony_ci	u8 *len;
2184e5b75505Sopenharmony_ci	int pw_id = -1;
2185e5b75505Sopenharmony_ci	size_t extra = 0;
2186e5b75505Sopenharmony_ci
2187e5b75505Sopenharmony_ci#ifdef CONFIG_WIFI_DISPLAY
2188e5b75505Sopenharmony_ci	if (p2p->wfd_ie_probe_resp)
2189e5b75505Sopenharmony_ci		extra = wpabuf_len(p2p->wfd_ie_probe_resp);
2190e5b75505Sopenharmony_ci#endif /* CONFIG_WIFI_DISPLAY */
2191e5b75505Sopenharmony_ci
2192e5b75505Sopenharmony_ci	if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P])
2193e5b75505Sopenharmony_ci		extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P]);
2194e5b75505Sopenharmony_ci
2195e5b75505Sopenharmony_ci	if (query_count)
2196e5b75505Sopenharmony_ci		extra += MAX_SVC_ADV_IE_LEN;
2197e5b75505Sopenharmony_ci
2198e5b75505Sopenharmony_ci	buf = wpabuf_alloc(1000 + extra);
2199e5b75505Sopenharmony_ci	if (buf == NULL)
2200e5b75505Sopenharmony_ci		return NULL;
2201e5b75505Sopenharmony_ci
2202e5b75505Sopenharmony_ci	if (p2p->go_neg_peer) {
2203e5b75505Sopenharmony_ci		/* Advertise immediate availability of WPS credential */
2204e5b75505Sopenharmony_ci		pw_id = p2p_wps_method_pw_id(p2p->go_neg_peer->wps_method);
2205e5b75505Sopenharmony_ci	}
2206e5b75505Sopenharmony_ci
2207e5b75505Sopenharmony_ci	if (p2p_build_wps_ie(p2p, buf, pw_id, 1) < 0) {
2208e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Failed to build WPS IE for Probe Response");
2209e5b75505Sopenharmony_ci		wpabuf_free(buf);
2210e5b75505Sopenharmony_ci		return NULL;
2211e5b75505Sopenharmony_ci	}
2212e5b75505Sopenharmony_ci
2213e5b75505Sopenharmony_ci#ifdef CONFIG_WIFI_DISPLAY
2214e5b75505Sopenharmony_ci	if (p2p->wfd_ie_probe_resp)
2215e5b75505Sopenharmony_ci		wpabuf_put_buf(buf, p2p->wfd_ie_probe_resp);
2216e5b75505Sopenharmony_ci#endif /* CONFIG_WIFI_DISPLAY */
2217e5b75505Sopenharmony_ci
2218e5b75505Sopenharmony_ci	if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P])
2219e5b75505Sopenharmony_ci		wpabuf_put_buf(buf,
2220e5b75505Sopenharmony_ci			       p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P]);
2221e5b75505Sopenharmony_ci
2222e5b75505Sopenharmony_ci	/* P2P IE */
2223e5b75505Sopenharmony_ci	len = p2p_buf_add_ie_hdr(buf);
2224e5b75505Sopenharmony_ci	p2p_buf_add_capability(buf, p2p->dev_capab &
2225e5b75505Sopenharmony_ci			       ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, 0);
2226e5b75505Sopenharmony_ci	if (p2p->ext_listen_interval)
2227e5b75505Sopenharmony_ci		p2p_buf_add_ext_listen_timing(buf, p2p->ext_listen_period,
2228e5b75505Sopenharmony_ci					      p2p->ext_listen_interval);
2229e5b75505Sopenharmony_ci	p2p_buf_add_device_info(buf, p2p, NULL);
2230e5b75505Sopenharmony_ci	p2p_buf_update_ie_hdr(buf, len);
2231e5b75505Sopenharmony_ci
2232e5b75505Sopenharmony_ci	if (query_count) {
2233e5b75505Sopenharmony_ci		p2p_buf_add_service_instance(buf, p2p, query_count, query_hash,
2234e5b75505Sopenharmony_ci					     p2p->p2ps_adv_list);
2235e5b75505Sopenharmony_ci	}
2236e5b75505Sopenharmony_ci
2237e5b75505Sopenharmony_ci	return buf;
2238e5b75505Sopenharmony_ci}
2239e5b75505Sopenharmony_ci
2240e5b75505Sopenharmony_cistatic int p2p_build_probe_resp_buf(struct p2p_data *p2p, struct wpabuf *buf,
2241e5b75505Sopenharmony_ci				    struct wpabuf *ies,
2242e5b75505Sopenharmony_ci				    const u8 *addr, int rx_freq)
2243e5b75505Sopenharmony_ci{
2244e5b75505Sopenharmony_ci	struct ieee80211_mgmt *resp;
2245e5b75505Sopenharmony_ci	u8 channel, op_class;
2246e5b75505Sopenharmony_ci
2247e5b75505Sopenharmony_ci	resp = wpabuf_put(buf, offsetof(struct ieee80211_mgmt,
2248e5b75505Sopenharmony_ci					u.probe_resp.variable));
2249e5b75505Sopenharmony_ci
2250e5b75505Sopenharmony_ci	resp->frame_control = host_to_le16((WLAN_FC_TYPE_MGMT << 2) |
2251e5b75505Sopenharmony_ci					   (WLAN_FC_STYPE_PROBE_RESP << 4));
2252e5b75505Sopenharmony_ci	os_memcpy(resp->da, addr, ETH_ALEN);
2253e5b75505Sopenharmony_ci	os_memcpy(resp->sa, p2p->cfg->dev_addr, ETH_ALEN);
2254e5b75505Sopenharmony_ci	os_memcpy(resp->bssid, p2p->cfg->dev_addr, ETH_ALEN);
2255e5b75505Sopenharmony_ci	resp->u.probe_resp.beacon_int = host_to_le16(100);
2256e5b75505Sopenharmony_ci	/* hardware or low-level driver will setup seq_ctrl and timestamp */
2257e5b75505Sopenharmony_ci	resp->u.probe_resp.capab_info =
2258e5b75505Sopenharmony_ci	    host_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE |
2259e5b75505Sopenharmony_ci		     WLAN_CAPABILITY_PRIVACY |
2260e5b75505Sopenharmony_ci		     WLAN_CAPABILITY_SHORT_SLOT_TIME);
2261e5b75505Sopenharmony_ci
2262e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, WLAN_EID_SSID);
2263e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, P2P_WILDCARD_SSID_LEN);
2264e5b75505Sopenharmony_ci	wpabuf_put_data(buf, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN);
2265e5b75505Sopenharmony_ci
2266e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, WLAN_EID_SUPP_RATES);
2267e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, 8);
2268e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, (60 / 5) | 0x80);
2269e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, 90 / 5);
2270e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, (120 / 5) | 0x80);
2271e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, 180 / 5);
2272e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, (240 / 5) | 0x80);
2273e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, 360 / 5);
2274e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, 480 / 5);
2275e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, 540 / 5);
2276e5b75505Sopenharmony_ci
2277e5b75505Sopenharmony_ci	if (!rx_freq) {
2278e5b75505Sopenharmony_ci		channel = p2p->cfg->channel;
2279e5b75505Sopenharmony_ci	} else if (p2p_freq_to_channel(rx_freq, &op_class, &channel)) {
2280e5b75505Sopenharmony_ci		p2p_err(p2p, "Failed to convert freq to channel");
2281e5b75505Sopenharmony_ci		return -1;
2282e5b75505Sopenharmony_ci	}
2283e5b75505Sopenharmony_ci
2284e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, WLAN_EID_DS_PARAMS);
2285e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, 1);
2286e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, channel);
2287e5b75505Sopenharmony_ci
2288e5b75505Sopenharmony_ci	wpabuf_put_buf(buf, ies);
2289e5b75505Sopenharmony_ci
2290e5b75505Sopenharmony_ci	return 0;
2291e5b75505Sopenharmony_ci}
2292e5b75505Sopenharmony_ci
2293e5b75505Sopenharmony_cistatic int p2p_service_find_asp(struct p2p_data *p2p, const u8 *hash)
2294e5b75505Sopenharmony_ci{
2295e5b75505Sopenharmony_ci	struct p2ps_advertisement *adv_data;
2296e5b75505Sopenharmony_ci	int any_wfa;
2297e5b75505Sopenharmony_ci
2298e5b75505Sopenharmony_ci	p2p_dbg(p2p, "ASP find - ASP list: %p", p2p->p2ps_adv_list);
2299e5b75505Sopenharmony_ci
2300e5b75505Sopenharmony_ci	/* Wildcard org.wi-fi.wfds matches any WFA spec defined service */
2301e5b75505Sopenharmony_ci	any_wfa = os_memcmp(hash, p2p->wild_card_hash, P2PS_HASH_LEN) == 0;
2302e5b75505Sopenharmony_ci
2303e5b75505Sopenharmony_ci	adv_data = p2p->p2ps_adv_list;
2304e5b75505Sopenharmony_ci	while (adv_data) {
2305e5b75505Sopenharmony_ci		if (os_memcmp(hash, adv_data->hash, P2PS_HASH_LEN) == 0)
2306e5b75505Sopenharmony_ci			return 1; /* exact hash match */
2307e5b75505Sopenharmony_ci		if (any_wfa &&
2308e5b75505Sopenharmony_ci		    os_strncmp(adv_data->svc_name, P2PS_WILD_HASH_STR,
2309e5b75505Sopenharmony_ci			       os_strlen(P2PS_WILD_HASH_STR)) == 0)
2310e5b75505Sopenharmony_ci			return 1; /* WFA service match */
2311e5b75505Sopenharmony_ci		adv_data = adv_data->next;
2312e5b75505Sopenharmony_ci	}
2313e5b75505Sopenharmony_ci
2314e5b75505Sopenharmony_ci	return 0;
2315e5b75505Sopenharmony_ci}
2316e5b75505Sopenharmony_ci
2317e5b75505Sopenharmony_ci
2318e5b75505Sopenharmony_cistatic enum p2p_probe_req_status
2319e5b75505Sopenharmony_cip2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
2320e5b75505Sopenharmony_ci		const u8 *bssid, const u8 *ie, size_t ie_len,
2321e5b75505Sopenharmony_ci		unsigned int rx_freq)
2322e5b75505Sopenharmony_ci{
2323e5b75505Sopenharmony_ci	struct ieee802_11_elems elems;
2324e5b75505Sopenharmony_ci	struct wpabuf *buf;
2325e5b75505Sopenharmony_ci	struct p2p_message msg;
2326e5b75505Sopenharmony_ci	struct wpabuf *ies;
2327e5b75505Sopenharmony_ci
2328e5b75505Sopenharmony_ci	if (ieee802_11_parse_elems((u8 *) ie, ie_len, &elems, 0) ==
2329e5b75505Sopenharmony_ci	    ParseFailed) {
2330e5b75505Sopenharmony_ci		/* Ignore invalid Probe Request frames */
2331e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Could not parse Probe Request frame - ignore it");
2332e5b75505Sopenharmony_ci		return P2P_PREQ_MALFORMED;
2333e5b75505Sopenharmony_ci	}
2334e5b75505Sopenharmony_ci
2335e5b75505Sopenharmony_ci	if (elems.p2p == NULL) {
2336e5b75505Sopenharmony_ci		/* not a P2P probe - ignore it */
2337e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Not a P2P probe - ignore it");
2338e5b75505Sopenharmony_ci		return P2P_PREQ_NOT_P2P;
2339e5b75505Sopenharmony_ci	}
2340e5b75505Sopenharmony_ci
2341e5b75505Sopenharmony_ci	if (dst && !is_broadcast_ether_addr(dst) &&
2342e5b75505Sopenharmony_ci	    os_memcmp(dst, p2p->cfg->dev_addr, ETH_ALEN) != 0) {
2343e5b75505Sopenharmony_ci		/* Not sent to the broadcast address or our P2P Device Address
2344e5b75505Sopenharmony_ci		 */
2345e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Probe Req DA " MACSTR " not ours - ignore it",
2346e5b75505Sopenharmony_ci			MAC2STR(dst));
2347e5b75505Sopenharmony_ci		return P2P_PREQ_NOT_PROCESSED;
2348e5b75505Sopenharmony_ci	}
2349e5b75505Sopenharmony_ci
2350e5b75505Sopenharmony_ci	if (bssid && !is_broadcast_ether_addr(bssid)) {
2351e5b75505Sopenharmony_ci		/* Not sent to the Wildcard BSSID */
2352e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Probe Req BSSID " MACSTR " not wildcard - ignore it",
2353e5b75505Sopenharmony_ci			MAC2STR(bssid));
2354e5b75505Sopenharmony_ci		return P2P_PREQ_NOT_PROCESSED;
2355e5b75505Sopenharmony_ci	}
2356e5b75505Sopenharmony_ci
2357e5b75505Sopenharmony_ci	if (elems.ssid == NULL || elems.ssid_len != P2P_WILDCARD_SSID_LEN ||
2358e5b75505Sopenharmony_ci	    os_memcmp(elems.ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) !=
2359e5b75505Sopenharmony_ci	    0) {
2360e5b75505Sopenharmony_ci		/* not using P2P Wildcard SSID - ignore */
2361e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Probe Req not using P2P Wildcard SSID - ignore it");
2362e5b75505Sopenharmony_ci		return P2P_PREQ_NOT_PROCESSED;
2363e5b75505Sopenharmony_ci	}
2364e5b75505Sopenharmony_ci
2365e5b75505Sopenharmony_ci	if (supp_rates_11b_only(&elems)) {
2366e5b75505Sopenharmony_ci		/* Indicates support for 11b rates only */
2367e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Probe Req with 11b rates only supported - ignore it");
2368e5b75505Sopenharmony_ci		return P2P_PREQ_NOT_P2P;
2369e5b75505Sopenharmony_ci	}
2370e5b75505Sopenharmony_ci
2371e5b75505Sopenharmony_ci	os_memset(&msg, 0, sizeof(msg));
2372e5b75505Sopenharmony_ci	if (p2p_parse_ies(ie, ie_len, &msg) < 0) {
2373e5b75505Sopenharmony_ci		/* Could not parse P2P attributes */
2374e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Could not parse P2P attributes in Probe Req - ignore it");
2375e5b75505Sopenharmony_ci		return P2P_PREQ_NOT_P2P;
2376e5b75505Sopenharmony_ci	}
2377e5b75505Sopenharmony_ci
2378e5b75505Sopenharmony_ci	if (msg.service_hash && msg.service_hash_count) {
2379e5b75505Sopenharmony_ci		const u8 *hash = msg.service_hash;
2380e5b75505Sopenharmony_ci		u8 i;
2381e5b75505Sopenharmony_ci		int p2ps_svc_found = 0;
2382e5b75505Sopenharmony_ci
2383e5b75505Sopenharmony_ci		p2p_dbg(p2p, "in_listen=%d drv_in_listen=%d when received P2PS Probe Request at %u MHz; own Listen channel %u, pending listen freq %u MHz",
2384e5b75505Sopenharmony_ci			p2p->in_listen, p2p->drv_in_listen, rx_freq,
2385e5b75505Sopenharmony_ci			p2p->cfg->channel, p2p->pending_listen_freq);
2386e5b75505Sopenharmony_ci
2387e5b75505Sopenharmony_ci		if (!p2p->in_listen && !p2p->drv_in_listen &&
2388e5b75505Sopenharmony_ci		    p2p->pending_listen_freq && rx_freq &&
2389e5b75505Sopenharmony_ci		    rx_freq != p2p->pending_listen_freq) {
2390e5b75505Sopenharmony_ci			p2p_dbg(p2p, "Do not reply to Probe Request frame that was received on %u MHz while waiting to start Listen state on %u MHz",
2391e5b75505Sopenharmony_ci				rx_freq, p2p->pending_listen_freq);
2392e5b75505Sopenharmony_ci			p2p_parse_free(&msg);
2393e5b75505Sopenharmony_ci			return P2P_PREQ_NOT_LISTEN;
2394e5b75505Sopenharmony_ci		}
2395e5b75505Sopenharmony_ci
2396e5b75505Sopenharmony_ci		for (i = 0; i < msg.service_hash_count; i++) {
2397e5b75505Sopenharmony_ci			if (p2p_service_find_asp(p2p, hash)) {
2398e5b75505Sopenharmony_ci				p2p_dbg(p2p, "Service Hash match found: "
2399e5b75505Sopenharmony_ci					MACSTR, MAC2STR(hash));
2400e5b75505Sopenharmony_ci				p2ps_svc_found = 1;
2401e5b75505Sopenharmony_ci				break;
2402e5b75505Sopenharmony_ci			}
2403e5b75505Sopenharmony_ci			hash += P2PS_HASH_LEN;
2404e5b75505Sopenharmony_ci		}
2405e5b75505Sopenharmony_ci
2406e5b75505Sopenharmony_ci		/* Probed hash unknown */
2407e5b75505Sopenharmony_ci		if (!p2ps_svc_found) {
2408e5b75505Sopenharmony_ci			p2p_dbg(p2p, "No Service Hash match found");
2409e5b75505Sopenharmony_ci			p2p_parse_free(&msg);
2410e5b75505Sopenharmony_ci			return P2P_PREQ_NOT_PROCESSED;
2411e5b75505Sopenharmony_ci		}
2412e5b75505Sopenharmony_ci	} else {
2413e5b75505Sopenharmony_ci		/* This is not a P2PS Probe Request */
2414e5b75505Sopenharmony_ci		p2p_dbg(p2p, "No P2PS Hash in Probe Request");
2415e5b75505Sopenharmony_ci
2416e5b75505Sopenharmony_ci		if (!p2p->in_listen || !p2p->drv_in_listen) {
2417e5b75505Sopenharmony_ci			/* not in Listen state - ignore Probe Request */
2418e5b75505Sopenharmony_ci			p2p_dbg(p2p, "Not in Listen state (in_listen=%d drv_in_listen=%d) - ignore Probe Request",
2419e5b75505Sopenharmony_ci				p2p->in_listen, p2p->drv_in_listen);
2420e5b75505Sopenharmony_ci			p2p_parse_free(&msg);
2421e5b75505Sopenharmony_ci			return P2P_PREQ_NOT_LISTEN;
2422e5b75505Sopenharmony_ci		}
2423e5b75505Sopenharmony_ci	}
2424e5b75505Sopenharmony_ci
2425e5b75505Sopenharmony_ci	if (msg.device_id &&
2426e5b75505Sopenharmony_ci	    os_memcmp(msg.device_id, p2p->cfg->dev_addr, ETH_ALEN) != 0) {
2427e5b75505Sopenharmony_ci		/* Device ID did not match */
2428e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Probe Req requested Device ID " MACSTR " did not match - ignore it",
2429e5b75505Sopenharmony_ci			MAC2STR(msg.device_id));
2430e5b75505Sopenharmony_ci		p2p_parse_free(&msg);
2431e5b75505Sopenharmony_ci		return P2P_PREQ_NOT_PROCESSED;
2432e5b75505Sopenharmony_ci	}
2433e5b75505Sopenharmony_ci
2434e5b75505Sopenharmony_ci	/* Check Requested Device Type match */
2435e5b75505Sopenharmony_ci	if (msg.wps_attributes &&
2436e5b75505Sopenharmony_ci	    !p2p_match_dev_type(p2p, msg.wps_attributes)) {
2437e5b75505Sopenharmony_ci		/* No match with Requested Device Type */
2438e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Probe Req requested Device Type did not match - ignore it");
2439e5b75505Sopenharmony_ci		p2p_parse_free(&msg);
2440e5b75505Sopenharmony_ci		return P2P_PREQ_NOT_PROCESSED;
2441e5b75505Sopenharmony_ci	}
2442e5b75505Sopenharmony_ci
2443e5b75505Sopenharmony_ci	if (!p2p->cfg->send_probe_resp) {
2444e5b75505Sopenharmony_ci		/* Response generated elsewhere */
2445e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Probe Resp generated elsewhere - do not generate additional response");
2446e5b75505Sopenharmony_ci		p2p_parse_free(&msg);
2447e5b75505Sopenharmony_ci		return P2P_PREQ_NOT_PROCESSED;
2448e5b75505Sopenharmony_ci	}
2449e5b75505Sopenharmony_ci
2450e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Reply to P2P Probe Request in Listen state");
2451e5b75505Sopenharmony_ci
2452e5b75505Sopenharmony_ci	/*
2453e5b75505Sopenharmony_ci	 * We do not really have a specific BSS that this frame is advertising,
2454e5b75505Sopenharmony_ci	 * so build a frame that has some information in valid format. This is
2455e5b75505Sopenharmony_ci	 * really only used for discovery purposes, not to learn exact BSS
2456e5b75505Sopenharmony_ci	 * parameters.
2457e5b75505Sopenharmony_ci	 */
2458e5b75505Sopenharmony_ci	ies = p2p_build_probe_resp_ies(p2p, msg.service_hash,
2459e5b75505Sopenharmony_ci				       msg.service_hash_count);
2460e5b75505Sopenharmony_ci	p2p_parse_free(&msg);
2461e5b75505Sopenharmony_ci	if (ies == NULL)
2462e5b75505Sopenharmony_ci		return P2P_PREQ_NOT_PROCESSED;
2463e5b75505Sopenharmony_ci
2464e5b75505Sopenharmony_ci	buf = wpabuf_alloc(200 + wpabuf_len(ies));
2465e5b75505Sopenharmony_ci	if (buf == NULL) {
2466e5b75505Sopenharmony_ci		wpabuf_free(ies);
2467e5b75505Sopenharmony_ci		return P2P_PREQ_NOT_PROCESSED;
2468e5b75505Sopenharmony_ci	}
2469e5b75505Sopenharmony_ci
2470e5b75505Sopenharmony_ci	if (p2p_build_probe_resp_buf(p2p, buf, ies, addr, rx_freq)) {
2471e5b75505Sopenharmony_ci		wpabuf_free(ies);
2472e5b75505Sopenharmony_ci		wpabuf_free(buf);
2473e5b75505Sopenharmony_ci		return P2P_PREQ_NOT_PROCESSED;
2474e5b75505Sopenharmony_ci	}
2475e5b75505Sopenharmony_ci
2476e5b75505Sopenharmony_ci	wpabuf_free(ies);
2477e5b75505Sopenharmony_ci
2478e5b75505Sopenharmony_ci	p2p->cfg->send_probe_resp(p2p->cfg->cb_ctx, buf, rx_freq);
2479e5b75505Sopenharmony_ci
2480e5b75505Sopenharmony_ci	wpabuf_free(buf);
2481e5b75505Sopenharmony_ci
2482e5b75505Sopenharmony_ci	return P2P_PREQ_PROCESSED;
2483e5b75505Sopenharmony_ci}
2484e5b75505Sopenharmony_ci
2485e5b75505Sopenharmony_ci
2486e5b75505Sopenharmony_cienum p2p_probe_req_status
2487e5b75505Sopenharmony_cip2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
2488e5b75505Sopenharmony_ci		 const u8 *bssid, const u8 *ie, size_t ie_len,
2489e5b75505Sopenharmony_ci		 unsigned int rx_freq, int p2p_lo_started)
2490e5b75505Sopenharmony_ci{
2491e5b75505Sopenharmony_ci	enum p2p_probe_req_status res;
2492e5b75505Sopenharmony_ci
2493e5b75505Sopenharmony_ci	p2p_add_dev_from_probe_req(p2p, addr, ie, ie_len);
2494e5b75505Sopenharmony_ci
2495e5b75505Sopenharmony_ci	if (p2p_lo_started) {
2496e5b75505Sopenharmony_ci		p2p_dbg(p2p,
2497e5b75505Sopenharmony_ci			"Probe Response is offloaded, do not reply Probe Request");
2498e5b75505Sopenharmony_ci		return P2P_PREQ_PROCESSED;
2499e5b75505Sopenharmony_ci	}
2500e5b75505Sopenharmony_ci
2501e5b75505Sopenharmony_ci	res = p2p_reply_probe(p2p, addr, dst, bssid, ie, ie_len, rx_freq);
2502e5b75505Sopenharmony_ci	if (res != P2P_PREQ_PROCESSED && res != P2P_PREQ_NOT_PROCESSED)
2503e5b75505Sopenharmony_ci		return res;
2504e5b75505Sopenharmony_ci
2505e5b75505Sopenharmony_ci	/*
2506e5b75505Sopenharmony_ci	 * Activate a pending GO Negotiation/Invite flow if a received Probe
2507e5b75505Sopenharmony_ci	 * Request frame is from an expected peer. Some devices may share the
2508e5b75505Sopenharmony_ci	 * same address for P2P and non-P2P STA running simultaneously. The
2509e5b75505Sopenharmony_ci	 * P2P_PREQ_PROCESSED and P2P_PREQ_NOT_PROCESSED p2p_reply_probe()
2510e5b75505Sopenharmony_ci	 * return values verified above ensure we are handling a Probe Request
2511e5b75505Sopenharmony_ci	 * frame from a P2P peer.
2512e5b75505Sopenharmony_ci	 */
2513e5b75505Sopenharmony_ci	if ((p2p->state == P2P_CONNECT || p2p->state == P2P_CONNECT_LISTEN) &&
2514e5b75505Sopenharmony_ci	    p2p->go_neg_peer &&
2515e5b75505Sopenharmony_ci	    os_memcmp(addr, p2p->go_neg_peer->info.p2p_device_addr, ETH_ALEN)
2516e5b75505Sopenharmony_ci	    == 0 &&
2517e5b75505Sopenharmony_ci	    !(p2p->go_neg_peer->flags & P2P_DEV_WAIT_GO_NEG_CONFIRM)) {
2518e5b75505Sopenharmony_ci		/* Received a Probe Request from GO Negotiation peer */
2519e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Found GO Negotiation peer - try to start GO negotiation from timeout");
2520e5b75505Sopenharmony_ci		eloop_cancel_timeout(p2p_go_neg_start, p2p, NULL);
2521e5b75505Sopenharmony_ci		eloop_register_timeout(0, 0, p2p_go_neg_start, p2p, NULL);
2522e5b75505Sopenharmony_ci		return res;
2523e5b75505Sopenharmony_ci	}
2524e5b75505Sopenharmony_ci
2525e5b75505Sopenharmony_ci	if ((p2p->state == P2P_INVITE || p2p->state == P2P_INVITE_LISTEN) &&
2526e5b75505Sopenharmony_ci	    p2p->invite_peer &&
2527e5b75505Sopenharmony_ci	    (p2p->invite_peer->flags & P2P_DEV_WAIT_INV_REQ_ACK) &&
2528e5b75505Sopenharmony_ci	    os_memcmp(addr, p2p->invite_peer->info.p2p_device_addr, ETH_ALEN)
2529e5b75505Sopenharmony_ci	    == 0) {
2530e5b75505Sopenharmony_ci		/* Received a Probe Request from Invite peer */
2531e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Found Invite peer - try to start Invite from timeout");
2532e5b75505Sopenharmony_ci		eloop_cancel_timeout(p2p_invite_start, p2p, NULL);
2533e5b75505Sopenharmony_ci		eloop_register_timeout(0, 0, p2p_invite_start, p2p, NULL);
2534e5b75505Sopenharmony_ci		return res;
2535e5b75505Sopenharmony_ci	}
2536e5b75505Sopenharmony_ci
2537e5b75505Sopenharmony_ci	return res;
2538e5b75505Sopenharmony_ci}
2539e5b75505Sopenharmony_ci
2540e5b75505Sopenharmony_ci
2541e5b75505Sopenharmony_cistatic int p2p_assoc_req_ie_wlan_ap(struct p2p_data *p2p, const u8 *bssid,
2542e5b75505Sopenharmony_ci				    u8 *buf, size_t len, struct wpabuf *p2p_ie)
2543e5b75505Sopenharmony_ci{
2544e5b75505Sopenharmony_ci	struct wpabuf *tmp;
2545e5b75505Sopenharmony_ci	u8 *lpos;
2546e5b75505Sopenharmony_ci	size_t tmplen;
2547e5b75505Sopenharmony_ci	int res;
2548e5b75505Sopenharmony_ci	u8 group_capab;
2549e5b75505Sopenharmony_ci	struct p2p_message msg;
2550e5b75505Sopenharmony_ci
2551e5b75505Sopenharmony_ci	if (p2p_ie == NULL)
2552e5b75505Sopenharmony_ci		return 0; /* WLAN AP is not a P2P manager */
2553e5b75505Sopenharmony_ci
2554e5b75505Sopenharmony_ci	os_memset(&msg, 0, sizeof(msg));
2555e5b75505Sopenharmony_ci	if (p2p_parse_p2p_ie(p2p_ie, &msg) < 0)
2556e5b75505Sopenharmony_ci		return 0;
2557e5b75505Sopenharmony_ci
2558e5b75505Sopenharmony_ci	p2p_dbg(p2p, "BSS P2P manageability %s",
2559e5b75505Sopenharmony_ci		msg.manageability ? "enabled" : "disabled");
2560e5b75505Sopenharmony_ci
2561e5b75505Sopenharmony_ci	if (!msg.manageability)
2562e5b75505Sopenharmony_ci		return 0;
2563e5b75505Sopenharmony_ci
2564e5b75505Sopenharmony_ci	/*
2565e5b75505Sopenharmony_ci	 * (Re)Association Request - P2P IE
2566e5b75505Sopenharmony_ci	 * P2P Capability attribute (shall be present)
2567e5b75505Sopenharmony_ci	 * P2P Interface attribute (present if concurrent device and
2568e5b75505Sopenharmony_ci	 *	P2P Management is enabled)
2569e5b75505Sopenharmony_ci	 */
2570e5b75505Sopenharmony_ci	tmp = wpabuf_alloc(200);
2571e5b75505Sopenharmony_ci	if (tmp == NULL)
2572e5b75505Sopenharmony_ci		return -1;
2573e5b75505Sopenharmony_ci
2574e5b75505Sopenharmony_ci	lpos = p2p_buf_add_ie_hdr(tmp);
2575e5b75505Sopenharmony_ci	group_capab = 0;
2576e5b75505Sopenharmony_ci	if (p2p->num_groups > 0) {
2577e5b75505Sopenharmony_ci		group_capab |= P2P_GROUP_CAPAB_GROUP_OWNER;
2578e5b75505Sopenharmony_ci		if ((p2p->dev_capab & P2P_DEV_CAPAB_CONCURRENT_OPER) &&
2579e5b75505Sopenharmony_ci		    (p2p->dev_capab & P2P_DEV_CAPAB_INFRA_MANAGED) &&
2580e5b75505Sopenharmony_ci		    p2p->cross_connect)
2581e5b75505Sopenharmony_ci			group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
2582e5b75505Sopenharmony_ci	}
2583e5b75505Sopenharmony_ci	p2p_buf_add_capability(tmp, p2p->dev_capab, group_capab);
2584e5b75505Sopenharmony_ci	if ((p2p->dev_capab & P2P_DEV_CAPAB_CONCURRENT_OPER) &&
2585e5b75505Sopenharmony_ci	    (p2p->dev_capab & P2P_DEV_CAPAB_INFRA_MANAGED))
2586e5b75505Sopenharmony_ci		p2p_buf_add_p2p_interface(tmp, p2p);
2587e5b75505Sopenharmony_ci	p2p_buf_update_ie_hdr(tmp, lpos);
2588e5b75505Sopenharmony_ci
2589e5b75505Sopenharmony_ci	tmplen = wpabuf_len(tmp);
2590e5b75505Sopenharmony_ci	if (tmplen > len)
2591e5b75505Sopenharmony_ci		res = -1;
2592e5b75505Sopenharmony_ci	else {
2593e5b75505Sopenharmony_ci		os_memcpy(buf, wpabuf_head(tmp), tmplen);
2594e5b75505Sopenharmony_ci		res = tmplen;
2595e5b75505Sopenharmony_ci	}
2596e5b75505Sopenharmony_ci	wpabuf_free(tmp);
2597e5b75505Sopenharmony_ci
2598e5b75505Sopenharmony_ci	return res;
2599e5b75505Sopenharmony_ci}
2600e5b75505Sopenharmony_ci
2601e5b75505Sopenharmony_ci
2602e5b75505Sopenharmony_ciint p2p_assoc_req_ie(struct p2p_data *p2p, const u8 *bssid, u8 *buf,
2603e5b75505Sopenharmony_ci		     size_t len, int p2p_group, struct wpabuf *p2p_ie)
2604e5b75505Sopenharmony_ci{
2605e5b75505Sopenharmony_ci	struct wpabuf *tmp;
2606e5b75505Sopenharmony_ci	u8 *lpos;
2607e5b75505Sopenharmony_ci	struct p2p_device *peer;
2608e5b75505Sopenharmony_ci	size_t tmplen;
2609e5b75505Sopenharmony_ci	int res;
2610e5b75505Sopenharmony_ci	size_t extra = 0;
2611e5b75505Sopenharmony_ci
2612e5b75505Sopenharmony_ci	if (!p2p_group)
2613e5b75505Sopenharmony_ci		return p2p_assoc_req_ie_wlan_ap(p2p, bssid, buf, len, p2p_ie);
2614e5b75505Sopenharmony_ci
2615e5b75505Sopenharmony_ci#ifdef CONFIG_WIFI_DISPLAY
2616e5b75505Sopenharmony_ci	if (p2p->wfd_ie_assoc_req)
2617e5b75505Sopenharmony_ci		extra = wpabuf_len(p2p->wfd_ie_assoc_req);
2618e5b75505Sopenharmony_ci#endif /* CONFIG_WIFI_DISPLAY */
2619e5b75505Sopenharmony_ci
2620e5b75505Sopenharmony_ci	if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_REQ])
2621e5b75505Sopenharmony_ci		extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_REQ]);
2622e5b75505Sopenharmony_ci
2623e5b75505Sopenharmony_ci	/*
2624e5b75505Sopenharmony_ci	 * (Re)Association Request - P2P IE
2625e5b75505Sopenharmony_ci	 * P2P Capability attribute (shall be present)
2626e5b75505Sopenharmony_ci	 * Extended Listen Timing (may be present)
2627e5b75505Sopenharmony_ci	 * P2P Device Info attribute (shall be present)
2628e5b75505Sopenharmony_ci	 */
2629e5b75505Sopenharmony_ci	tmp = wpabuf_alloc(200 + extra);
2630e5b75505Sopenharmony_ci	if (tmp == NULL)
2631e5b75505Sopenharmony_ci		return -1;
2632e5b75505Sopenharmony_ci
2633e5b75505Sopenharmony_ci#ifdef CONFIG_WIFI_DISPLAY
2634e5b75505Sopenharmony_ci	if (p2p->wfd_ie_assoc_req)
2635e5b75505Sopenharmony_ci		wpabuf_put_buf(tmp, p2p->wfd_ie_assoc_req);
2636e5b75505Sopenharmony_ci#endif /* CONFIG_WIFI_DISPLAY */
2637e5b75505Sopenharmony_ci
2638e5b75505Sopenharmony_ci	if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_REQ])
2639e5b75505Sopenharmony_ci		wpabuf_put_buf(tmp,
2640e5b75505Sopenharmony_ci			       p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_REQ]);
2641e5b75505Sopenharmony_ci
2642e5b75505Sopenharmony_ci	peer = bssid ? p2p_get_device(p2p, bssid) : NULL;
2643e5b75505Sopenharmony_ci
2644e5b75505Sopenharmony_ci	lpos = p2p_buf_add_ie_hdr(tmp);
2645e5b75505Sopenharmony_ci	p2p_buf_add_capability(tmp, p2p->dev_capab, 0);
2646e5b75505Sopenharmony_ci	if (p2p->ext_listen_interval)
2647e5b75505Sopenharmony_ci		p2p_buf_add_ext_listen_timing(tmp, p2p->ext_listen_period,
2648e5b75505Sopenharmony_ci					      p2p->ext_listen_interval);
2649e5b75505Sopenharmony_ci	p2p_buf_add_device_info(tmp, p2p, peer);
2650e5b75505Sopenharmony_ci	p2p_buf_update_ie_hdr(tmp, lpos);
2651e5b75505Sopenharmony_ci
2652e5b75505Sopenharmony_ci	tmplen = wpabuf_len(tmp);
2653e5b75505Sopenharmony_ci	if (tmplen > len)
2654e5b75505Sopenharmony_ci		res = -1;
2655e5b75505Sopenharmony_ci	else {
2656e5b75505Sopenharmony_ci		os_memcpy(buf, wpabuf_head(tmp), tmplen);
2657e5b75505Sopenharmony_ci		res = tmplen;
2658e5b75505Sopenharmony_ci	}
2659e5b75505Sopenharmony_ci	wpabuf_free(tmp);
2660e5b75505Sopenharmony_ci
2661e5b75505Sopenharmony_ci	return res;
2662e5b75505Sopenharmony_ci}
2663e5b75505Sopenharmony_ci
2664e5b75505Sopenharmony_ci
2665e5b75505Sopenharmony_ciint p2p_scan_result_text(const u8 *ies, size_t ies_len, char *buf, char *end)
2666e5b75505Sopenharmony_ci{
2667e5b75505Sopenharmony_ci	struct wpabuf *p2p_ie;
2668e5b75505Sopenharmony_ci	int ret;
2669e5b75505Sopenharmony_ci
2670e5b75505Sopenharmony_ci	p2p_ie = ieee802_11_vendor_ie_concat(ies, ies_len, P2P_IE_VENDOR_TYPE);
2671e5b75505Sopenharmony_ci	if (p2p_ie == NULL)
2672e5b75505Sopenharmony_ci		return 0;
2673e5b75505Sopenharmony_ci
2674e5b75505Sopenharmony_ci	ret = p2p_attr_text(p2p_ie, buf, end);
2675e5b75505Sopenharmony_ci	wpabuf_free(p2p_ie);
2676e5b75505Sopenharmony_ci	return ret;
2677e5b75505Sopenharmony_ci}
2678e5b75505Sopenharmony_ci
2679e5b75505Sopenharmony_ci
2680e5b75505Sopenharmony_cistruct p2ps_advertisement *
2681e5b75505Sopenharmony_cip2p_service_p2ps_id(struct p2p_data *p2p, u32 adv_id)
2682e5b75505Sopenharmony_ci{
2683e5b75505Sopenharmony_ci	struct p2ps_advertisement *adv_data;
2684e5b75505Sopenharmony_ci
2685e5b75505Sopenharmony_ci	if (!p2p)
2686e5b75505Sopenharmony_ci		return NULL;
2687e5b75505Sopenharmony_ci
2688e5b75505Sopenharmony_ci	adv_data = p2p->p2ps_adv_list;
2689e5b75505Sopenharmony_ci	while (adv_data) {
2690e5b75505Sopenharmony_ci		if (adv_data->id == adv_id)
2691e5b75505Sopenharmony_ci			return adv_data;
2692e5b75505Sopenharmony_ci		adv_data = adv_data->next;
2693e5b75505Sopenharmony_ci	}
2694e5b75505Sopenharmony_ci
2695e5b75505Sopenharmony_ci	return NULL;
2696e5b75505Sopenharmony_ci}
2697e5b75505Sopenharmony_ci
2698e5b75505Sopenharmony_ci
2699e5b75505Sopenharmony_ciint p2p_service_del_asp(struct p2p_data *p2p, u32 adv_id)
2700e5b75505Sopenharmony_ci{
2701e5b75505Sopenharmony_ci	struct p2ps_advertisement *adv_data;
2702e5b75505Sopenharmony_ci	struct p2ps_advertisement **prior;
2703e5b75505Sopenharmony_ci
2704e5b75505Sopenharmony_ci	if (!p2p)
2705e5b75505Sopenharmony_ci		return -1;
2706e5b75505Sopenharmony_ci
2707e5b75505Sopenharmony_ci	adv_data = p2p->p2ps_adv_list;
2708e5b75505Sopenharmony_ci	prior = &p2p->p2ps_adv_list;
2709e5b75505Sopenharmony_ci	while (adv_data) {
2710e5b75505Sopenharmony_ci		if (adv_data->id == adv_id) {
2711e5b75505Sopenharmony_ci			p2p_dbg(p2p, "Delete ASP adv_id=0x%x", adv_id);
2712e5b75505Sopenharmony_ci			*prior = adv_data->next;
2713e5b75505Sopenharmony_ci			os_free(adv_data);
2714e5b75505Sopenharmony_ci			return 0;
2715e5b75505Sopenharmony_ci		}
2716e5b75505Sopenharmony_ci		prior = &adv_data->next;
2717e5b75505Sopenharmony_ci		adv_data = adv_data->next;
2718e5b75505Sopenharmony_ci	}
2719e5b75505Sopenharmony_ci
2720e5b75505Sopenharmony_ci	return -1;
2721e5b75505Sopenharmony_ci}
2722e5b75505Sopenharmony_ci
2723e5b75505Sopenharmony_ci
2724e5b75505Sopenharmony_ciint p2p_service_add_asp(struct p2p_data *p2p, int auto_accept, u32 adv_id,
2725e5b75505Sopenharmony_ci			const char *adv_str, u8 svc_state, u16 config_methods,
2726e5b75505Sopenharmony_ci			const char *svc_info, const u8 *cpt_priority)
2727e5b75505Sopenharmony_ci{
2728e5b75505Sopenharmony_ci	struct p2ps_advertisement *adv_data, *tmp, **prev;
2729e5b75505Sopenharmony_ci	u8 buf[P2PS_HASH_LEN];
2730e5b75505Sopenharmony_ci	size_t adv_data_len, adv_len, info_len = 0;
2731e5b75505Sopenharmony_ci	int i;
2732e5b75505Sopenharmony_ci
2733e5b75505Sopenharmony_ci	if (!p2p || !adv_str || !adv_str[0] || !cpt_priority)
2734e5b75505Sopenharmony_ci		return -1;
2735e5b75505Sopenharmony_ci
2736e5b75505Sopenharmony_ci	if (!(config_methods & p2p->cfg->config_methods)) {
2737e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Config methods not supported svc: 0x%x dev: 0x%x",
2738e5b75505Sopenharmony_ci			config_methods, p2p->cfg->config_methods);
2739e5b75505Sopenharmony_ci		return -1;
2740e5b75505Sopenharmony_ci	}
2741e5b75505Sopenharmony_ci
2742e5b75505Sopenharmony_ci	if (!p2ps_gen_hash(p2p, adv_str, buf))
2743e5b75505Sopenharmony_ci		return -1;
2744e5b75505Sopenharmony_ci
2745e5b75505Sopenharmony_ci	if (svc_info)
2746e5b75505Sopenharmony_ci		info_len = os_strlen(svc_info);
2747e5b75505Sopenharmony_ci	adv_len = os_strlen(adv_str);
2748e5b75505Sopenharmony_ci	adv_data_len = sizeof(struct p2ps_advertisement) + adv_len + 1 +
2749e5b75505Sopenharmony_ci		info_len + 1;
2750e5b75505Sopenharmony_ci
2751e5b75505Sopenharmony_ci	adv_data = os_zalloc(adv_data_len);
2752e5b75505Sopenharmony_ci	if (!adv_data)
2753e5b75505Sopenharmony_ci		return -1;
2754e5b75505Sopenharmony_ci
2755e5b75505Sopenharmony_ci	os_memcpy(adv_data->hash, buf, P2PS_HASH_LEN);
2756e5b75505Sopenharmony_ci	adv_data->id = adv_id;
2757e5b75505Sopenharmony_ci	adv_data->state = svc_state;
2758e5b75505Sopenharmony_ci	adv_data->config_methods = config_methods & p2p->cfg->config_methods;
2759e5b75505Sopenharmony_ci	adv_data->auto_accept = (u8) auto_accept;
2760e5b75505Sopenharmony_ci	os_memcpy(adv_data->svc_name, adv_str, adv_len);
2761e5b75505Sopenharmony_ci
2762e5b75505Sopenharmony_ci	for (i = 0; cpt_priority[i] && i < P2PS_FEATURE_CAPAB_CPT_MAX; i++) {
2763e5b75505Sopenharmony_ci		adv_data->cpt_priority[i] = cpt_priority[i];
2764e5b75505Sopenharmony_ci		adv_data->cpt_mask |= cpt_priority[i];
2765e5b75505Sopenharmony_ci	}
2766e5b75505Sopenharmony_ci
2767e5b75505Sopenharmony_ci	if (svc_info && info_len) {
2768e5b75505Sopenharmony_ci		adv_data->svc_info = &adv_data->svc_name[adv_len + 1];
2769e5b75505Sopenharmony_ci		os_memcpy(adv_data->svc_info, svc_info, info_len);
2770e5b75505Sopenharmony_ci	}
2771e5b75505Sopenharmony_ci
2772e5b75505Sopenharmony_ci	/*
2773e5b75505Sopenharmony_ci	 * Group Advertisements by service string. They do not need to be
2774e5b75505Sopenharmony_ci	 * sorted, but groups allow easier Probe Response instance grouping
2775e5b75505Sopenharmony_ci	 */
2776e5b75505Sopenharmony_ci	tmp = p2p->p2ps_adv_list;
2777e5b75505Sopenharmony_ci	prev = &p2p->p2ps_adv_list;
2778e5b75505Sopenharmony_ci	while (tmp) {
2779e5b75505Sopenharmony_ci		if (tmp->id == adv_data->id) {
2780e5b75505Sopenharmony_ci			if (os_strcmp(tmp->svc_name, adv_data->svc_name) != 0) {
2781e5b75505Sopenharmony_ci				os_free(adv_data);
2782e5b75505Sopenharmony_ci				return -1;
2783e5b75505Sopenharmony_ci			}
2784e5b75505Sopenharmony_ci			adv_data->next = tmp->next;
2785e5b75505Sopenharmony_ci			*prev = adv_data;
2786e5b75505Sopenharmony_ci			os_free(tmp);
2787e5b75505Sopenharmony_ci			goto inserted;
2788e5b75505Sopenharmony_ci		} else {
2789e5b75505Sopenharmony_ci			if (os_strcmp(tmp->svc_name, adv_data->svc_name) == 0) {
2790e5b75505Sopenharmony_ci				adv_data->next = tmp->next;
2791e5b75505Sopenharmony_ci				tmp->next = adv_data;
2792e5b75505Sopenharmony_ci				goto inserted;
2793e5b75505Sopenharmony_ci			}
2794e5b75505Sopenharmony_ci		}
2795e5b75505Sopenharmony_ci		prev = &tmp->next;
2796e5b75505Sopenharmony_ci		tmp = tmp->next;
2797e5b75505Sopenharmony_ci	}
2798e5b75505Sopenharmony_ci
2799e5b75505Sopenharmony_ci	/* No svc_name match found */
2800e5b75505Sopenharmony_ci	adv_data->next = p2p->p2ps_adv_list;
2801e5b75505Sopenharmony_ci	p2p->p2ps_adv_list = adv_data;
2802e5b75505Sopenharmony_ci
2803e5b75505Sopenharmony_ciinserted:
2804e5b75505Sopenharmony_ci	p2p_dbg(p2p,
2805e5b75505Sopenharmony_ci		"Added ASP advertisement adv_id=0x%x config_methods=0x%x svc_state=0x%x adv_str='%s' cpt_mask=0x%x",
2806e5b75505Sopenharmony_ci		adv_id, adv_data->config_methods, svc_state, adv_str,
2807e5b75505Sopenharmony_ci		adv_data->cpt_mask);
2808e5b75505Sopenharmony_ci
2809e5b75505Sopenharmony_ci	return 0;
2810e5b75505Sopenharmony_ci}
2811e5b75505Sopenharmony_ci
2812e5b75505Sopenharmony_ci
2813e5b75505Sopenharmony_civoid p2p_service_flush_asp(struct p2p_data *p2p)
2814e5b75505Sopenharmony_ci{
2815e5b75505Sopenharmony_ci	struct p2ps_advertisement *adv, *prev;
2816e5b75505Sopenharmony_ci
2817e5b75505Sopenharmony_ci	if (!p2p)
2818e5b75505Sopenharmony_ci		return;
2819e5b75505Sopenharmony_ci
2820e5b75505Sopenharmony_ci	adv = p2p->p2ps_adv_list;
2821e5b75505Sopenharmony_ci	while (adv) {
2822e5b75505Sopenharmony_ci		prev = adv;
2823e5b75505Sopenharmony_ci		adv = adv->next;
2824e5b75505Sopenharmony_ci		os_free(prev);
2825e5b75505Sopenharmony_ci	}
2826e5b75505Sopenharmony_ci
2827e5b75505Sopenharmony_ci	p2p->p2ps_adv_list = NULL;
2828e5b75505Sopenharmony_ci	p2ps_prov_free(p2p);
2829e5b75505Sopenharmony_ci	p2p_dbg(p2p, "All ASP advertisements flushed");
2830e5b75505Sopenharmony_ci}
2831e5b75505Sopenharmony_ci
2832e5b75505Sopenharmony_ci
2833e5b75505Sopenharmony_ciint p2p_parse_dev_addr_in_p2p_ie(struct wpabuf *p2p_ie, u8 *dev_addr)
2834e5b75505Sopenharmony_ci{
2835e5b75505Sopenharmony_ci	struct p2p_message msg;
2836e5b75505Sopenharmony_ci
2837e5b75505Sopenharmony_ci	os_memset(&msg, 0, sizeof(msg));
2838e5b75505Sopenharmony_ci	if (p2p_parse_p2p_ie(p2p_ie, &msg))
2839e5b75505Sopenharmony_ci		return -1;
2840e5b75505Sopenharmony_ci
2841e5b75505Sopenharmony_ci	if (msg.p2p_device_addr) {
2842e5b75505Sopenharmony_ci		os_memcpy(dev_addr, msg.p2p_device_addr, ETH_ALEN);
2843e5b75505Sopenharmony_ci		return 0;
2844e5b75505Sopenharmony_ci	} else if (msg.device_id) {
2845e5b75505Sopenharmony_ci		os_memcpy(dev_addr, msg.device_id, ETH_ALEN);
2846e5b75505Sopenharmony_ci		return 0;
2847e5b75505Sopenharmony_ci	}
2848e5b75505Sopenharmony_ci	return -1;
2849e5b75505Sopenharmony_ci}
2850e5b75505Sopenharmony_ci
2851e5b75505Sopenharmony_ci
2852e5b75505Sopenharmony_ciint p2p_parse_dev_addr(const u8 *ies, size_t ies_len, u8 *dev_addr)
2853e5b75505Sopenharmony_ci{
2854e5b75505Sopenharmony_ci	struct wpabuf *p2p_ie;
2855e5b75505Sopenharmony_ci	int ret;
2856e5b75505Sopenharmony_ci
2857e5b75505Sopenharmony_ci	p2p_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
2858e5b75505Sopenharmony_ci					     P2P_IE_VENDOR_TYPE);
2859e5b75505Sopenharmony_ci	if (p2p_ie == NULL)
2860e5b75505Sopenharmony_ci		return -1;
2861e5b75505Sopenharmony_ci	ret = p2p_parse_dev_addr_in_p2p_ie(p2p_ie, dev_addr);
2862e5b75505Sopenharmony_ci	wpabuf_free(p2p_ie);
2863e5b75505Sopenharmony_ci	return ret;
2864e5b75505Sopenharmony_ci}
2865e5b75505Sopenharmony_ci
2866e5b75505Sopenharmony_ci
2867e5b75505Sopenharmony_cistatic void p2p_clear_go_neg(struct p2p_data *p2p)
2868e5b75505Sopenharmony_ci{
2869e5b75505Sopenharmony_ci	p2p->go_neg_peer = NULL;
2870e5b75505Sopenharmony_ci	p2p_clear_timeout(p2p);
2871e5b75505Sopenharmony_ci	p2p_set_state(p2p, P2P_IDLE);
2872e5b75505Sopenharmony_ci}
2873e5b75505Sopenharmony_ci
2874e5b75505Sopenharmony_ci
2875e5b75505Sopenharmony_civoid p2p_wps_success_cb(struct p2p_data *p2p, const u8 *mac_addr)
2876e5b75505Sopenharmony_ci{
2877e5b75505Sopenharmony_ci	if (p2p->go_neg_peer == NULL) {
2878e5b75505Sopenharmony_ci		p2p_dbg(p2p, "No pending Group Formation - ignore WPS registration success notification");
2879e5b75505Sopenharmony_ci		return; /* No pending Group Formation */
2880e5b75505Sopenharmony_ci	}
2881e5b75505Sopenharmony_ci
2882e5b75505Sopenharmony_ci	if (os_memcmp(mac_addr, p2p->go_neg_peer->intended_addr, ETH_ALEN) !=
2883e5b75505Sopenharmony_ci	    0) {
2884e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Ignore WPS registration success notification for "
2885e5b75505Sopenharmony_ci			MACSTR " (GO Negotiation peer " MACSTR ")",
2886e5b75505Sopenharmony_ci			MAC2STR(mac_addr),
2887e5b75505Sopenharmony_ci			MAC2STR(p2p->go_neg_peer->intended_addr));
2888e5b75505Sopenharmony_ci		return; /* Ignore unexpected peer address */
2889e5b75505Sopenharmony_ci	}
2890e5b75505Sopenharmony_ci
2891e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Group Formation completed successfully with " MACSTR,
2892e5b75505Sopenharmony_ci		MAC2STR(mac_addr));
2893e5b75505Sopenharmony_ci
2894e5b75505Sopenharmony_ci	p2p_clear_go_neg(p2p);
2895e5b75505Sopenharmony_ci}
2896e5b75505Sopenharmony_ci
2897e5b75505Sopenharmony_ci
2898e5b75505Sopenharmony_civoid p2p_group_formation_failed(struct p2p_data *p2p)
2899e5b75505Sopenharmony_ci{
2900e5b75505Sopenharmony_ci	if (p2p->go_neg_peer == NULL) {
2901e5b75505Sopenharmony_ci		p2p_dbg(p2p, "No pending Group Formation - ignore group formation failure notification");
2902e5b75505Sopenharmony_ci		return; /* No pending Group Formation */
2903e5b75505Sopenharmony_ci	}
2904e5b75505Sopenharmony_ci
2905e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Group Formation failed with " MACSTR,
2906e5b75505Sopenharmony_ci		MAC2STR(p2p->go_neg_peer->intended_addr));
2907e5b75505Sopenharmony_ci
2908e5b75505Sopenharmony_ci	p2p_clear_go_neg(p2p);
2909e5b75505Sopenharmony_ci}
2910e5b75505Sopenharmony_ci
2911e5b75505Sopenharmony_ci
2912e5b75505Sopenharmony_cistruct p2p_data * p2p_init(const struct p2p_config *cfg)
2913e5b75505Sopenharmony_ci{
2914e5b75505Sopenharmony_ci	struct p2p_data *p2p;
2915e5b75505Sopenharmony_ci
2916e5b75505Sopenharmony_ci	if (cfg->max_peers < 1 ||
2917e5b75505Sopenharmony_ci	    cfg->passphrase_len < 8 || cfg->passphrase_len > 63)
2918e5b75505Sopenharmony_ci		return NULL;
2919e5b75505Sopenharmony_ci
2920e5b75505Sopenharmony_ci	p2p = os_zalloc(sizeof(*p2p) + sizeof(*cfg));
2921e5b75505Sopenharmony_ci	if (p2p == NULL)
2922e5b75505Sopenharmony_ci		return NULL;
2923e5b75505Sopenharmony_ci	p2p->cfg = (struct p2p_config *) (p2p + 1);
2924e5b75505Sopenharmony_ci	os_memcpy(p2p->cfg, cfg, sizeof(*cfg));
2925e5b75505Sopenharmony_ci	if (cfg->dev_name)
2926e5b75505Sopenharmony_ci		p2p->cfg->dev_name = os_strdup(cfg->dev_name);
2927e5b75505Sopenharmony_ci	if (cfg->manufacturer)
2928e5b75505Sopenharmony_ci		p2p->cfg->manufacturer = os_strdup(cfg->manufacturer);
2929e5b75505Sopenharmony_ci	if (cfg->model_name)
2930e5b75505Sopenharmony_ci		p2p->cfg->model_name = os_strdup(cfg->model_name);
2931e5b75505Sopenharmony_ci	if (cfg->model_number)
2932e5b75505Sopenharmony_ci		p2p->cfg->model_number = os_strdup(cfg->model_number);
2933e5b75505Sopenharmony_ci	if (cfg->serial_number)
2934e5b75505Sopenharmony_ci		p2p->cfg->serial_number = os_strdup(cfg->serial_number);
2935e5b75505Sopenharmony_ci	if (cfg->pref_chan) {
2936e5b75505Sopenharmony_ci		p2p->cfg->pref_chan = os_malloc(cfg->num_pref_chan *
2937e5b75505Sopenharmony_ci						sizeof(struct p2p_channel));
2938e5b75505Sopenharmony_ci		if (p2p->cfg->pref_chan) {
2939e5b75505Sopenharmony_ci			os_memcpy(p2p->cfg->pref_chan, cfg->pref_chan,
2940e5b75505Sopenharmony_ci				  cfg->num_pref_chan *
2941e5b75505Sopenharmony_ci				  sizeof(struct p2p_channel));
2942e5b75505Sopenharmony_ci		} else
2943e5b75505Sopenharmony_ci			p2p->cfg->num_pref_chan = 0;
2944e5b75505Sopenharmony_ci	}
2945e5b75505Sopenharmony_ci
2946e5b75505Sopenharmony_ci	p2ps_gen_hash(p2p, P2PS_WILD_HASH_STR, p2p->wild_card_hash);
2947e5b75505Sopenharmony_ci
2948e5b75505Sopenharmony_ci	p2p->min_disc_int = 1;
2949e5b75505Sopenharmony_ci	p2p->max_disc_int = 3;
2950e5b75505Sopenharmony_ci	p2p->max_disc_tu = -1;
2951e5b75505Sopenharmony_ci
2952e5b75505Sopenharmony_ci	if (os_get_random(&p2p->next_tie_breaker, 1) < 0)
2953e5b75505Sopenharmony_ci		p2p->next_tie_breaker = 0;
2954e5b75505Sopenharmony_ci	p2p->next_tie_breaker &= 0x01;
2955e5b75505Sopenharmony_ci	if (cfg->sd_request)
2956e5b75505Sopenharmony_ci		p2p->dev_capab |= P2P_DEV_CAPAB_SERVICE_DISCOVERY;
2957e5b75505Sopenharmony_ci	p2p->dev_capab |= P2P_DEV_CAPAB_INVITATION_PROCEDURE;
2958e5b75505Sopenharmony_ci	if (cfg->concurrent_operations)
2959e5b75505Sopenharmony_ci		p2p->dev_capab |= P2P_DEV_CAPAB_CONCURRENT_OPER;
2960e5b75505Sopenharmony_ci	p2p->dev_capab |= P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
2961e5b75505Sopenharmony_ci
2962e5b75505Sopenharmony_ci	dl_list_init(&p2p->devices);
2963e5b75505Sopenharmony_ci
2964e5b75505Sopenharmony_ci	p2p->go_timeout = 100;
2965e5b75505Sopenharmony_ci	p2p->client_timeout = 20;
2966e5b75505Sopenharmony_ci	p2p->num_p2p_sd_queries = 0;
2967e5b75505Sopenharmony_ci
2968e5b75505Sopenharmony_ci	p2p_dbg(p2p, "initialized");
2969e5b75505Sopenharmony_ci	p2p_channels_dump(p2p, "channels", &p2p->cfg->channels);
2970e5b75505Sopenharmony_ci	p2p_channels_dump(p2p, "cli_channels", &p2p->cfg->cli_channels);
2971e5b75505Sopenharmony_ci
2972e5b75505Sopenharmony_ci	return p2p;
2973e5b75505Sopenharmony_ci}
2974e5b75505Sopenharmony_ci
2975e5b75505Sopenharmony_ci
2976e5b75505Sopenharmony_civoid p2p_deinit(struct p2p_data *p2p)
2977e5b75505Sopenharmony_ci{
2978e5b75505Sopenharmony_ci#ifdef CONFIG_WIFI_DISPLAY
2979e5b75505Sopenharmony_ci	wpabuf_free(p2p->wfd_ie_beacon);
2980e5b75505Sopenharmony_ci	wpabuf_free(p2p->wfd_ie_probe_req);
2981e5b75505Sopenharmony_ci	wpabuf_free(p2p->wfd_ie_probe_resp);
2982e5b75505Sopenharmony_ci	wpabuf_free(p2p->wfd_ie_assoc_req);
2983e5b75505Sopenharmony_ci	wpabuf_free(p2p->wfd_ie_invitation);
2984e5b75505Sopenharmony_ci	wpabuf_free(p2p->wfd_ie_prov_disc_req);
2985e5b75505Sopenharmony_ci	wpabuf_free(p2p->wfd_ie_prov_disc_resp);
2986e5b75505Sopenharmony_ci	wpabuf_free(p2p->wfd_ie_go_neg);
2987e5b75505Sopenharmony_ci	wpabuf_free(p2p->wfd_dev_info);
2988e5b75505Sopenharmony_ci	wpabuf_free(p2p->wfd_assoc_bssid);
2989e5b75505Sopenharmony_ci	wpabuf_free(p2p->wfd_coupled_sink_info);
2990e5b75505Sopenharmony_ci	wpabuf_free(p2p->wfd_r2_dev_info);
2991e5b75505Sopenharmony_ci#endif /* CONFIG_WIFI_DISPLAY */
2992e5b75505Sopenharmony_ci
2993e5b75505Sopenharmony_ci	eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
2994e5b75505Sopenharmony_ci	eloop_cancel_timeout(p2p_go_neg_start, p2p, NULL);
2995e5b75505Sopenharmony_ci	eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p, NULL);
2996e5b75505Sopenharmony_ci	p2p_flush(p2p);
2997e5b75505Sopenharmony_ci	p2p_free_req_dev_types(p2p);
2998e5b75505Sopenharmony_ci	os_free(p2p->cfg->dev_name);
2999e5b75505Sopenharmony_ci	os_free(p2p->cfg->manufacturer);
3000e5b75505Sopenharmony_ci	os_free(p2p->cfg->model_name);
3001e5b75505Sopenharmony_ci	os_free(p2p->cfg->model_number);
3002e5b75505Sopenharmony_ci	os_free(p2p->cfg->serial_number);
3003e5b75505Sopenharmony_ci	os_free(p2p->cfg->pref_chan);
3004e5b75505Sopenharmony_ci	os_free(p2p->groups);
3005e5b75505Sopenharmony_ci	p2ps_prov_free(p2p);
3006e5b75505Sopenharmony_ci	wpabuf_free(p2p->sd_resp);
3007e5b75505Sopenharmony_ci	p2p_remove_wps_vendor_extensions(p2p);
3008e5b75505Sopenharmony_ci	os_free(p2p->no_go_freq.range);
3009e5b75505Sopenharmony_ci	p2p_service_flush_asp(p2p);
3010e5b75505Sopenharmony_ci
3011e5b75505Sopenharmony_ci	os_free(p2p);
3012e5b75505Sopenharmony_ci}
3013e5b75505Sopenharmony_ci
3014e5b75505Sopenharmony_ci
3015e5b75505Sopenharmony_civoid p2p_flush(struct p2p_data *p2p)
3016e5b75505Sopenharmony_ci{
3017e5b75505Sopenharmony_ci	struct p2p_device *dev, *prev;
3018e5b75505Sopenharmony_ci
3019e5b75505Sopenharmony_ci	p2p_ext_listen(p2p, 0, 0);
3020e5b75505Sopenharmony_ci	p2p_stop_find(p2p);
3021e5b75505Sopenharmony_ci	dl_list_for_each_safe(dev, prev, &p2p->devices, struct p2p_device,
3022e5b75505Sopenharmony_ci			      list) {
3023e5b75505Sopenharmony_ci		dl_list_del(&dev->list);
3024e5b75505Sopenharmony_ci		p2p_device_free(p2p, dev);
3025e5b75505Sopenharmony_ci	}
3026e5b75505Sopenharmony_ci	p2p_free_sd_queries(p2p);
3027e5b75505Sopenharmony_ci	p2p->ssid_set = 0;
3028e5b75505Sopenharmony_ci	p2ps_prov_free(p2p);
3029e5b75505Sopenharmony_ci	p2p_reset_pending_pd(p2p);
3030e5b75505Sopenharmony_ci	p2p->override_pref_op_class = 0;
3031e5b75505Sopenharmony_ci	p2p->override_pref_channel = 0;
3032e5b75505Sopenharmony_ci}
3033e5b75505Sopenharmony_ci
3034e5b75505Sopenharmony_ci
3035e5b75505Sopenharmony_ciint p2p_unauthorize(struct p2p_data *p2p, const u8 *addr)
3036e5b75505Sopenharmony_ci{
3037e5b75505Sopenharmony_ci	struct p2p_device *dev;
3038e5b75505Sopenharmony_ci
3039e5b75505Sopenharmony_ci	dev = p2p_get_device(p2p, addr);
3040e5b75505Sopenharmony_ci	if (dev == NULL)
3041e5b75505Sopenharmony_ci		return -1;
3042e5b75505Sopenharmony_ci
3043e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Unauthorizing " MACSTR, MAC2STR(addr));
3044e5b75505Sopenharmony_ci
3045e5b75505Sopenharmony_ci	if (p2p->go_neg_peer == dev) {
3046e5b75505Sopenharmony_ci		eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p, NULL);
3047e5b75505Sopenharmony_ci		p2p->go_neg_peer = NULL;
3048e5b75505Sopenharmony_ci	}
3049e5b75505Sopenharmony_ci
3050e5b75505Sopenharmony_ci	dev->wps_method = WPS_NOT_READY;
3051e5b75505Sopenharmony_ci	dev->oob_pw_id = 0;
3052e5b75505Sopenharmony_ci	dev->flags &= ~P2P_DEV_WAIT_GO_NEG_RESPONSE;
3053e5b75505Sopenharmony_ci	dev->flags &= ~P2P_DEV_WAIT_GO_NEG_CONFIRM;
3054e5b75505Sopenharmony_ci
3055e5b75505Sopenharmony_ci	return 0;
3056e5b75505Sopenharmony_ci}
3057e5b75505Sopenharmony_ci
3058e5b75505Sopenharmony_ci
3059e5b75505Sopenharmony_ciint p2p_set_dev_name(struct p2p_data *p2p, const char *dev_name)
3060e5b75505Sopenharmony_ci{
3061e5b75505Sopenharmony_ci	os_free(p2p->cfg->dev_name);
3062e5b75505Sopenharmony_ci	if (dev_name) {
3063e5b75505Sopenharmony_ci		p2p->cfg->dev_name = os_strdup(dev_name);
3064e5b75505Sopenharmony_ci		if (p2p->cfg->dev_name == NULL)
3065e5b75505Sopenharmony_ci			return -1;
3066e5b75505Sopenharmony_ci	} else
3067e5b75505Sopenharmony_ci		p2p->cfg->dev_name = NULL;
3068e5b75505Sopenharmony_ci	return 0;
3069e5b75505Sopenharmony_ci}
3070e5b75505Sopenharmony_ci
3071e5b75505Sopenharmony_ci
3072e5b75505Sopenharmony_ciint p2p_set_manufacturer(struct p2p_data *p2p, const char *manufacturer)
3073e5b75505Sopenharmony_ci{
3074e5b75505Sopenharmony_ci	os_free(p2p->cfg->manufacturer);
3075e5b75505Sopenharmony_ci	p2p->cfg->manufacturer = NULL;
3076e5b75505Sopenharmony_ci	if (manufacturer) {
3077e5b75505Sopenharmony_ci		p2p->cfg->manufacturer = os_strdup(manufacturer);
3078e5b75505Sopenharmony_ci		if (p2p->cfg->manufacturer == NULL)
3079e5b75505Sopenharmony_ci			return -1;
3080e5b75505Sopenharmony_ci	}
3081e5b75505Sopenharmony_ci
3082e5b75505Sopenharmony_ci	return 0;
3083e5b75505Sopenharmony_ci}
3084e5b75505Sopenharmony_ci
3085e5b75505Sopenharmony_ci
3086e5b75505Sopenharmony_ciint p2p_set_model_name(struct p2p_data *p2p, const char *model_name)
3087e5b75505Sopenharmony_ci{
3088e5b75505Sopenharmony_ci	os_free(p2p->cfg->model_name);
3089e5b75505Sopenharmony_ci	p2p->cfg->model_name = NULL;
3090e5b75505Sopenharmony_ci	if (model_name) {
3091e5b75505Sopenharmony_ci		p2p->cfg->model_name = os_strdup(model_name);
3092e5b75505Sopenharmony_ci		if (p2p->cfg->model_name == NULL)
3093e5b75505Sopenharmony_ci			return -1;
3094e5b75505Sopenharmony_ci	}
3095e5b75505Sopenharmony_ci
3096e5b75505Sopenharmony_ci	return 0;
3097e5b75505Sopenharmony_ci}
3098e5b75505Sopenharmony_ci
3099e5b75505Sopenharmony_ci
3100e5b75505Sopenharmony_ciint p2p_set_model_number(struct p2p_data *p2p, const char *model_number)
3101e5b75505Sopenharmony_ci{
3102e5b75505Sopenharmony_ci	os_free(p2p->cfg->model_number);
3103e5b75505Sopenharmony_ci	p2p->cfg->model_number = NULL;
3104e5b75505Sopenharmony_ci	if (model_number) {
3105e5b75505Sopenharmony_ci		p2p->cfg->model_number = os_strdup(model_number);
3106e5b75505Sopenharmony_ci		if (p2p->cfg->model_number == NULL)
3107e5b75505Sopenharmony_ci			return -1;
3108e5b75505Sopenharmony_ci	}
3109e5b75505Sopenharmony_ci
3110e5b75505Sopenharmony_ci	return 0;
3111e5b75505Sopenharmony_ci}
3112e5b75505Sopenharmony_ci
3113e5b75505Sopenharmony_ci
3114e5b75505Sopenharmony_ciint p2p_set_serial_number(struct p2p_data *p2p, const char *serial_number)
3115e5b75505Sopenharmony_ci{
3116e5b75505Sopenharmony_ci	os_free(p2p->cfg->serial_number);
3117e5b75505Sopenharmony_ci	p2p->cfg->serial_number = NULL;
3118e5b75505Sopenharmony_ci	if (serial_number) {
3119e5b75505Sopenharmony_ci		p2p->cfg->serial_number = os_strdup(serial_number);
3120e5b75505Sopenharmony_ci		if (p2p->cfg->serial_number == NULL)
3121e5b75505Sopenharmony_ci			return -1;
3122e5b75505Sopenharmony_ci	}
3123e5b75505Sopenharmony_ci
3124e5b75505Sopenharmony_ci	return 0;
3125e5b75505Sopenharmony_ci}
3126e5b75505Sopenharmony_ci
3127e5b75505Sopenharmony_ci
3128e5b75505Sopenharmony_civoid p2p_set_config_methods(struct p2p_data *p2p, u16 config_methods)
3129e5b75505Sopenharmony_ci{
3130e5b75505Sopenharmony_ci	p2p->cfg->config_methods = config_methods;
3131e5b75505Sopenharmony_ci}
3132e5b75505Sopenharmony_ci
3133e5b75505Sopenharmony_ci
3134e5b75505Sopenharmony_civoid p2p_set_uuid(struct p2p_data *p2p, const u8 *uuid)
3135e5b75505Sopenharmony_ci{
3136e5b75505Sopenharmony_ci	os_memcpy(p2p->cfg->uuid, uuid, 16);
3137e5b75505Sopenharmony_ci}
3138e5b75505Sopenharmony_ci
3139e5b75505Sopenharmony_ci
3140e5b75505Sopenharmony_ciint p2p_set_pri_dev_type(struct p2p_data *p2p, const u8 *pri_dev_type)
3141e5b75505Sopenharmony_ci{
3142e5b75505Sopenharmony_ci	os_memcpy(p2p->cfg->pri_dev_type, pri_dev_type, 8);
3143e5b75505Sopenharmony_ci	return 0;
3144e5b75505Sopenharmony_ci}
3145e5b75505Sopenharmony_ci
3146e5b75505Sopenharmony_ci
3147e5b75505Sopenharmony_ciint p2p_set_sec_dev_types(struct p2p_data *p2p, const u8 dev_types[][8],
3148e5b75505Sopenharmony_ci			  size_t num_dev_types)
3149e5b75505Sopenharmony_ci{
3150e5b75505Sopenharmony_ci	if (num_dev_types > P2P_SEC_DEVICE_TYPES)
3151e5b75505Sopenharmony_ci		num_dev_types = P2P_SEC_DEVICE_TYPES;
3152e5b75505Sopenharmony_ci	p2p->cfg->num_sec_dev_types = num_dev_types;
3153e5b75505Sopenharmony_ci	os_memcpy(p2p->cfg->sec_dev_type, dev_types, num_dev_types * 8);
3154e5b75505Sopenharmony_ci	return 0;
3155e5b75505Sopenharmony_ci}
3156e5b75505Sopenharmony_ci
3157e5b75505Sopenharmony_ci
3158e5b75505Sopenharmony_civoid p2p_remove_wps_vendor_extensions(struct p2p_data *p2p)
3159e5b75505Sopenharmony_ci{
3160e5b75505Sopenharmony_ci	int i;
3161e5b75505Sopenharmony_ci
3162e5b75505Sopenharmony_ci	for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
3163e5b75505Sopenharmony_ci		wpabuf_free(p2p->wps_vendor_ext[i]);
3164e5b75505Sopenharmony_ci		p2p->wps_vendor_ext[i] = NULL;
3165e5b75505Sopenharmony_ci	}
3166e5b75505Sopenharmony_ci}
3167e5b75505Sopenharmony_ci
3168e5b75505Sopenharmony_ci
3169e5b75505Sopenharmony_ciint p2p_add_wps_vendor_extension(struct p2p_data *p2p,
3170e5b75505Sopenharmony_ci				 const struct wpabuf *vendor_ext)
3171e5b75505Sopenharmony_ci{
3172e5b75505Sopenharmony_ci	int i;
3173e5b75505Sopenharmony_ci
3174e5b75505Sopenharmony_ci	if (vendor_ext == NULL)
3175e5b75505Sopenharmony_ci		return -1;
3176e5b75505Sopenharmony_ci
3177e5b75505Sopenharmony_ci	for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
3178e5b75505Sopenharmony_ci		if (p2p->wps_vendor_ext[i] == NULL)
3179e5b75505Sopenharmony_ci			break;
3180e5b75505Sopenharmony_ci	}
3181e5b75505Sopenharmony_ci	if (i >= P2P_MAX_WPS_VENDOR_EXT)
3182e5b75505Sopenharmony_ci		return -1;
3183e5b75505Sopenharmony_ci
3184e5b75505Sopenharmony_ci	p2p->wps_vendor_ext[i] = wpabuf_dup(vendor_ext);
3185e5b75505Sopenharmony_ci	if (p2p->wps_vendor_ext[i] == NULL)
3186e5b75505Sopenharmony_ci		return -1;
3187e5b75505Sopenharmony_ci
3188e5b75505Sopenharmony_ci	return 0;
3189e5b75505Sopenharmony_ci}
3190e5b75505Sopenharmony_ci
3191e5b75505Sopenharmony_ci
3192e5b75505Sopenharmony_ciint p2p_set_country(struct p2p_data *p2p, const char *country)
3193e5b75505Sopenharmony_ci{
3194e5b75505Sopenharmony_ci	os_memcpy(p2p->cfg->country, country, 3);
3195e5b75505Sopenharmony_ci	return 0;
3196e5b75505Sopenharmony_ci}
3197e5b75505Sopenharmony_ci
3198e5b75505Sopenharmony_ci
3199e5b75505Sopenharmony_cistatic int p2p_pre_find_operation(struct p2p_data *p2p, struct p2p_device *dev)
3200e5b75505Sopenharmony_ci{
3201e5b75505Sopenharmony_ci	int res;
3202e5b75505Sopenharmony_ci
3203e5b75505Sopenharmony_ci	if (dev->sd_pending_bcast_queries == 0) {
3204e5b75505Sopenharmony_ci		/* Initialize with total number of registered broadcast
3205e5b75505Sopenharmony_ci		 * SD queries. */
3206e5b75505Sopenharmony_ci		dev->sd_pending_bcast_queries = p2p->num_p2p_sd_queries;
3207e5b75505Sopenharmony_ci	}
3208e5b75505Sopenharmony_ci
3209e5b75505Sopenharmony_ci	res = p2p_start_sd(p2p, dev);
3210e5b75505Sopenharmony_ci	if (res == -2)
3211e5b75505Sopenharmony_ci		return -2;
3212e5b75505Sopenharmony_ci	if (res == 0)
3213e5b75505Sopenharmony_ci		return 1;
3214e5b75505Sopenharmony_ci
3215e5b75505Sopenharmony_ci	if (dev->req_config_methods &&
3216e5b75505Sopenharmony_ci	    !(dev->flags & P2P_DEV_PD_FOR_JOIN)) {
3217e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Send pending Provision Discovery Request to "
3218e5b75505Sopenharmony_ci			MACSTR " (config methods 0x%x)",
3219e5b75505Sopenharmony_ci			MAC2STR(dev->info.p2p_device_addr),
3220e5b75505Sopenharmony_ci			dev->req_config_methods);
3221e5b75505Sopenharmony_ci		if (p2p_send_prov_disc_req(p2p, dev, 0, 0) == 0)
3222e5b75505Sopenharmony_ci			return 1;
3223e5b75505Sopenharmony_ci	}
3224e5b75505Sopenharmony_ci
3225e5b75505Sopenharmony_ci	return 0;
3226e5b75505Sopenharmony_ci}
3227e5b75505Sopenharmony_ci
3228e5b75505Sopenharmony_ci
3229e5b75505Sopenharmony_civoid p2p_continue_find(struct p2p_data *p2p)
3230e5b75505Sopenharmony_ci{
3231e5b75505Sopenharmony_ci	struct p2p_device *dev;
3232e5b75505Sopenharmony_ci	int found, res;
3233e5b75505Sopenharmony_ci
3234e5b75505Sopenharmony_ci	p2p_set_state(p2p, P2P_SEARCH);
3235e5b75505Sopenharmony_ci
3236e5b75505Sopenharmony_ci	/* Continue from the device following the last iteration */
3237e5b75505Sopenharmony_ci	found = 0;
3238e5b75505Sopenharmony_ci	dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
3239e5b75505Sopenharmony_ci		if (dev == p2p->last_p2p_find_oper) {
3240e5b75505Sopenharmony_ci			found = 1;
3241e5b75505Sopenharmony_ci			continue;
3242e5b75505Sopenharmony_ci		}
3243e5b75505Sopenharmony_ci		if (!found)
3244e5b75505Sopenharmony_ci			continue;
3245e5b75505Sopenharmony_ci		res = p2p_pre_find_operation(p2p, dev);
3246e5b75505Sopenharmony_ci		if (res > 0) {
3247e5b75505Sopenharmony_ci			p2p->last_p2p_find_oper = dev;
3248e5b75505Sopenharmony_ci			return;
3249e5b75505Sopenharmony_ci		}
3250e5b75505Sopenharmony_ci		if (res == -2)
3251e5b75505Sopenharmony_ci			goto skip_sd;
3252e5b75505Sopenharmony_ci	}
3253e5b75505Sopenharmony_ci
3254e5b75505Sopenharmony_ci	/*
3255e5b75505Sopenharmony_ci	 * Wrap around to the beginning of the list and continue until the last
3256e5b75505Sopenharmony_ci	 * iteration device.
3257e5b75505Sopenharmony_ci	 */
3258e5b75505Sopenharmony_ci	dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
3259e5b75505Sopenharmony_ci		res = p2p_pre_find_operation(p2p, dev);
3260e5b75505Sopenharmony_ci		if (res > 0) {
3261e5b75505Sopenharmony_ci			p2p->last_p2p_find_oper = dev;
3262e5b75505Sopenharmony_ci			return;
3263e5b75505Sopenharmony_ci		}
3264e5b75505Sopenharmony_ci		if (res == -2)
3265e5b75505Sopenharmony_ci			goto skip_sd;
3266e5b75505Sopenharmony_ci		if (dev == p2p->last_p2p_find_oper)
3267e5b75505Sopenharmony_ci			break;
3268e5b75505Sopenharmony_ci	}
3269e5b75505Sopenharmony_ci
3270e5b75505Sopenharmony_ciskip_sd:
3271e5b75505Sopenharmony_ci	os_memset(p2p->sd_query_no_ack, 0, ETH_ALEN);
3272e5b75505Sopenharmony_ci	p2p_listen_in_find(p2p, 1);
3273e5b75505Sopenharmony_ci}
3274e5b75505Sopenharmony_ci
3275e5b75505Sopenharmony_ci
3276e5b75505Sopenharmony_cistatic void p2p_sd_cb(struct p2p_data *p2p, int success)
3277e5b75505Sopenharmony_ci{
3278e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Service Discovery Query TX callback: success=%d",
3279e5b75505Sopenharmony_ci		success);
3280e5b75505Sopenharmony_ci	p2p->pending_action_state = P2P_NO_PENDING_ACTION;
3281e5b75505Sopenharmony_ci
3282e5b75505Sopenharmony_ci	if (!success) {
3283e5b75505Sopenharmony_ci		if (p2p->sd_peer) {
3284e5b75505Sopenharmony_ci			if (is_zero_ether_addr(p2p->sd_query_no_ack)) {
3285e5b75505Sopenharmony_ci				os_memcpy(p2p->sd_query_no_ack,
3286e5b75505Sopenharmony_ci					  p2p->sd_peer->info.p2p_device_addr,
3287e5b75505Sopenharmony_ci					  ETH_ALEN);
3288e5b75505Sopenharmony_ci				p2p_dbg(p2p,
3289e5b75505Sopenharmony_ci					"First SD Query no-ACK in this search iteration: "
3290e5b75505Sopenharmony_ci					MACSTR, MAC2STR(p2p->sd_query_no_ack));
3291e5b75505Sopenharmony_ci			}
3292e5b75505Sopenharmony_ci			p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
3293e5b75505Sopenharmony_ci		}
3294e5b75505Sopenharmony_ci		p2p->sd_peer = NULL;
3295e5b75505Sopenharmony_ci		if (p2p->state != P2P_IDLE)
3296e5b75505Sopenharmony_ci			p2p_continue_find(p2p);
3297e5b75505Sopenharmony_ci		return;
3298e5b75505Sopenharmony_ci	}
3299e5b75505Sopenharmony_ci
3300e5b75505Sopenharmony_ci	if (p2p->sd_peer == NULL) {
3301e5b75505Sopenharmony_ci		p2p_dbg(p2p, "No SD peer entry known");
3302e5b75505Sopenharmony_ci		if (p2p->state != P2P_IDLE)
3303e5b75505Sopenharmony_ci			p2p_continue_find(p2p);
3304e5b75505Sopenharmony_ci		return;
3305e5b75505Sopenharmony_ci	}
3306e5b75505Sopenharmony_ci
3307e5b75505Sopenharmony_ci	if (p2p->sd_query && p2p->sd_query->for_all_peers) {
3308e5b75505Sopenharmony_ci		/* Update the pending broadcast SD query count for this device
3309e5b75505Sopenharmony_ci		 */
3310e5b75505Sopenharmony_ci		p2p->sd_peer->sd_pending_bcast_queries--;
3311e5b75505Sopenharmony_ci
3312e5b75505Sopenharmony_ci		/*
3313e5b75505Sopenharmony_ci		 * If there are no pending broadcast queries for this device,
3314e5b75505Sopenharmony_ci		 * mark it as done (-1).
3315e5b75505Sopenharmony_ci		 */
3316e5b75505Sopenharmony_ci		if (p2p->sd_peer->sd_pending_bcast_queries == 0)
3317e5b75505Sopenharmony_ci			p2p->sd_peer->sd_pending_bcast_queries = -1;
3318e5b75505Sopenharmony_ci	}
3319e5b75505Sopenharmony_ci
3320e5b75505Sopenharmony_ci	/* Wait for response from the peer */
3321e5b75505Sopenharmony_ci	p2p_set_state(p2p, P2P_SD_DURING_FIND);
3322e5b75505Sopenharmony_ci	p2p_set_timeout(p2p, 0, 200000);
3323e5b75505Sopenharmony_ci}
3324e5b75505Sopenharmony_ci
3325e5b75505Sopenharmony_ci
3326e5b75505Sopenharmony_ci/**
3327e5b75505Sopenharmony_ci * p2p_retry_pd - Retry any pending provision disc requests in IDLE state
3328e5b75505Sopenharmony_ci * @p2p: P2P module context from p2p_init()
3329e5b75505Sopenharmony_ci */
3330e5b75505Sopenharmony_cistatic void p2p_retry_pd(struct p2p_data *p2p)
3331e5b75505Sopenharmony_ci{
3332e5b75505Sopenharmony_ci	struct p2p_device *dev;
3333e5b75505Sopenharmony_ci
3334e5b75505Sopenharmony_ci	/*
3335e5b75505Sopenharmony_ci	 * Retry the prov disc req attempt only for the peer that the user had
3336e5b75505Sopenharmony_ci	 * requested.
3337e5b75505Sopenharmony_ci	 */
3338e5b75505Sopenharmony_ci
3339e5b75505Sopenharmony_ci	dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
3340e5b75505Sopenharmony_ci		if (os_memcmp(p2p->pending_pd_devaddr,
3341e5b75505Sopenharmony_ci			      dev->info.p2p_device_addr, ETH_ALEN) != 0)
3342e5b75505Sopenharmony_ci			continue;
3343e5b75505Sopenharmony_ci		if (!dev->req_config_methods)
3344e5b75505Sopenharmony_ci			continue;
3345e5b75505Sopenharmony_ci
3346e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Send pending Provision Discovery Request to "
3347e5b75505Sopenharmony_ci			MACSTR " (config methods 0x%x)",
3348e5b75505Sopenharmony_ci			MAC2STR(dev->info.p2p_device_addr),
3349e5b75505Sopenharmony_ci			dev->req_config_methods);
3350e5b75505Sopenharmony_ci		p2p_send_prov_disc_req(p2p, dev,
3351e5b75505Sopenharmony_ci				       dev->flags & P2P_DEV_PD_FOR_JOIN,
3352e5b75505Sopenharmony_ci				       p2p->pd_force_freq);
3353e5b75505Sopenharmony_ci		return;
3354e5b75505Sopenharmony_ci	}
3355e5b75505Sopenharmony_ci}
3356e5b75505Sopenharmony_ci
3357e5b75505Sopenharmony_ci
3358e5b75505Sopenharmony_cistatic void p2p_prov_disc_cb(struct p2p_data *p2p, int success)
3359e5b75505Sopenharmony_ci{
3360e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Provision Discovery Request TX callback: success=%d",
3361e5b75505Sopenharmony_ci		success);
3362e5b75505Sopenharmony_ci
3363e5b75505Sopenharmony_ci	/*
3364e5b75505Sopenharmony_ci	 * Postpone resetting the pending action state till after we actually
3365e5b75505Sopenharmony_ci	 * time out. This allows us to take some action like notifying any
3366e5b75505Sopenharmony_ci	 * interested parties about no response to the request.
3367e5b75505Sopenharmony_ci	 *
3368e5b75505Sopenharmony_ci	 * When the timer (below) goes off we check in IDLE, SEARCH, or
3369e5b75505Sopenharmony_ci	 * LISTEN_ONLY state, which are the only allowed states to issue a PD
3370e5b75505Sopenharmony_ci	 * requests in, if this was still pending and then raise notification.
3371e5b75505Sopenharmony_ci	 */
3372e5b75505Sopenharmony_ci
3373e5b75505Sopenharmony_ci	if (!success) {
3374e5b75505Sopenharmony_ci		p2p->pending_action_state = P2P_NO_PENDING_ACTION;
3375e5b75505Sopenharmony_ci
3376e5b75505Sopenharmony_ci		if (p2p->user_initiated_pd &&
3377e5b75505Sopenharmony_ci		    (p2p->state == P2P_SEARCH || p2p->state == P2P_LISTEN_ONLY))
3378e5b75505Sopenharmony_ci		{
3379e5b75505Sopenharmony_ci			/* Retry request from timeout to avoid busy loops */
3380e5b75505Sopenharmony_ci			p2p->pending_action_state = P2P_PENDING_PD;
3381e5b75505Sopenharmony_ci			p2p_set_timeout(p2p, 0, 50000);
3382e5b75505Sopenharmony_ci		} else if (p2p->state != P2P_IDLE)
3383e5b75505Sopenharmony_ci			p2p_continue_find(p2p);
3384e5b75505Sopenharmony_ci		else if (p2p->user_initiated_pd) {
3385e5b75505Sopenharmony_ci			p2p->pending_action_state = P2P_PENDING_PD;
3386e5b75505Sopenharmony_ci			p2p_set_timeout(p2p, 0, 300000);
3387e5b75505Sopenharmony_ci		}
3388e5b75505Sopenharmony_ci		return;
3389e5b75505Sopenharmony_ci	}
3390e5b75505Sopenharmony_ci
3391e5b75505Sopenharmony_ci	/*
3392e5b75505Sopenharmony_ci	 * If after PD Request the peer doesn't expect to receive PD Response
3393e5b75505Sopenharmony_ci	 * the PD Request ACK indicates a completion of the current PD. This
3394e5b75505Sopenharmony_ci	 * happens only on the advertiser side sending the follow-on PD Request
3395e5b75505Sopenharmony_ci	 * with the status different than 12 (Success: accepted by user).
3396e5b75505Sopenharmony_ci	 */
3397e5b75505Sopenharmony_ci	if (p2p->p2ps_prov && !p2p->p2ps_prov->pd_seeker &&
3398e5b75505Sopenharmony_ci	    p2p->p2ps_prov->status != P2P_SC_SUCCESS_DEFERRED) {
3399e5b75505Sopenharmony_ci		p2p_dbg(p2p, "P2PS PD completion on Follow-on PD Request ACK");
3400e5b75505Sopenharmony_ci
3401e5b75505Sopenharmony_ci		if (p2p->send_action_in_progress) {
3402e5b75505Sopenharmony_ci			p2p->send_action_in_progress = 0;
3403e5b75505Sopenharmony_ci			p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
3404e5b75505Sopenharmony_ci		}
3405e5b75505Sopenharmony_ci
3406e5b75505Sopenharmony_ci		p2p->pending_action_state = P2P_NO_PENDING_ACTION;
3407e5b75505Sopenharmony_ci
3408e5b75505Sopenharmony_ci		if (p2p->cfg->p2ps_prov_complete) {
3409e5b75505Sopenharmony_ci			p2p->cfg->p2ps_prov_complete(
3410e5b75505Sopenharmony_ci				p2p->cfg->cb_ctx,
3411e5b75505Sopenharmony_ci				p2p->p2ps_prov->status,
3412e5b75505Sopenharmony_ci				p2p->p2ps_prov->adv_mac,
3413e5b75505Sopenharmony_ci				p2p->p2ps_prov->adv_mac,
3414e5b75505Sopenharmony_ci				p2p->p2ps_prov->session_mac,
3415e5b75505Sopenharmony_ci				NULL, p2p->p2ps_prov->adv_id,
3416e5b75505Sopenharmony_ci				p2p->p2ps_prov->session_id,
3417e5b75505Sopenharmony_ci				0, 0, NULL, 0, 0, 0,
3418e5b75505Sopenharmony_ci				NULL, NULL, 0, 0, NULL, 0);
3419e5b75505Sopenharmony_ci		}
3420e5b75505Sopenharmony_ci
3421e5b75505Sopenharmony_ci		if (p2p->user_initiated_pd)
3422e5b75505Sopenharmony_ci			p2p_reset_pending_pd(p2p);
3423e5b75505Sopenharmony_ci
3424e5b75505Sopenharmony_ci		p2ps_prov_free(p2p);
3425e5b75505Sopenharmony_ci		return;
3426e5b75505Sopenharmony_ci	}
3427e5b75505Sopenharmony_ci
3428e5b75505Sopenharmony_ci	/*
3429e5b75505Sopenharmony_ci	 * This postponing, of resetting pending_action_state, needs to be
3430e5b75505Sopenharmony_ci	 * done only for user initiated PD requests and not internal ones.
3431e5b75505Sopenharmony_ci	 */
3432e5b75505Sopenharmony_ci	if (p2p->user_initiated_pd)
3433e5b75505Sopenharmony_ci		p2p->pending_action_state = P2P_PENDING_PD;
3434e5b75505Sopenharmony_ci	else
3435e5b75505Sopenharmony_ci		p2p->pending_action_state = P2P_NO_PENDING_ACTION;
3436e5b75505Sopenharmony_ci
3437e5b75505Sopenharmony_ci	/* Wait for response from the peer */
3438e5b75505Sopenharmony_ci	if (p2p->state == P2P_SEARCH)
3439e5b75505Sopenharmony_ci		p2p_set_state(p2p, P2P_PD_DURING_FIND);
3440e5b75505Sopenharmony_ci	p2p_set_timeout(p2p, 0, 200000);
3441e5b75505Sopenharmony_ci}
3442e5b75505Sopenharmony_ci
3443e5b75505Sopenharmony_ci
3444e5b75505Sopenharmony_cistatic void p2p_prov_disc_resp_cb(struct p2p_data *p2p, int success)
3445e5b75505Sopenharmony_ci{
3446e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Provision Discovery Response TX callback: success=%d",
3447e5b75505Sopenharmony_ci		success);
3448e5b75505Sopenharmony_ci
3449e5b75505Sopenharmony_ci	if (p2p->send_action_in_progress) {
3450e5b75505Sopenharmony_ci		p2p->send_action_in_progress = 0;
3451e5b75505Sopenharmony_ci		p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
3452e5b75505Sopenharmony_ci	}
3453e5b75505Sopenharmony_ci
3454e5b75505Sopenharmony_ci	p2p->pending_action_state = P2P_NO_PENDING_ACTION;
3455e5b75505Sopenharmony_ci
3456e5b75505Sopenharmony_ci	if (!success)
3457e5b75505Sopenharmony_ci		return;
3458e5b75505Sopenharmony_ci
3459e5b75505Sopenharmony_ci	if (!p2p->cfg->prov_disc_resp_cb ||
3460e5b75505Sopenharmony_ci	    p2p->cfg->prov_disc_resp_cb(p2p->cfg->cb_ctx) < 1)
3461e5b75505Sopenharmony_ci		return;
3462e5b75505Sopenharmony_ci
3463e5b75505Sopenharmony_ci	p2p_dbg(p2p,
3464e5b75505Sopenharmony_ci		"Post-Provision Discovery operations started - do not try to continue other P2P operations");
3465e5b75505Sopenharmony_ci}
3466e5b75505Sopenharmony_ci
3467e5b75505Sopenharmony_ci
3468e5b75505Sopenharmony_ciint p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq,
3469e5b75505Sopenharmony_ci			 struct os_reltime *rx_time, int level, const u8 *ies,
3470e5b75505Sopenharmony_ci			 size_t ies_len)
3471e5b75505Sopenharmony_ci{
3472e5b75505Sopenharmony_ci	if (os_reltime_before(rx_time, &p2p->find_start)) {
3473e5b75505Sopenharmony_ci		/*
3474e5b75505Sopenharmony_ci		 * The driver may have cached (e.g., in cfg80211 BSS table) the
3475e5b75505Sopenharmony_ci		 * scan results for relatively long time. To avoid reporting
3476e5b75505Sopenharmony_ci		 * stale information, update P2P peers only based on results
3477e5b75505Sopenharmony_ci		 * that have based on frames received after the last p2p_find
3478e5b75505Sopenharmony_ci		 * operation was started.
3479e5b75505Sopenharmony_ci		 */
3480e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Ignore old scan result for " MACSTR
3481e5b75505Sopenharmony_ci			" (rx_time=%u.%06u find_start=%u.%06u)",
3482e5b75505Sopenharmony_ci			MAC2STR(bssid), (unsigned int) rx_time->sec,
3483e5b75505Sopenharmony_ci			(unsigned int) rx_time->usec,
3484e5b75505Sopenharmony_ci			(unsigned int) p2p->find_start.sec,
3485e5b75505Sopenharmony_ci			(unsigned int) p2p->find_start.usec);
3486e5b75505Sopenharmony_ci		return 0;
3487e5b75505Sopenharmony_ci	}
3488e5b75505Sopenharmony_ci
3489e5b75505Sopenharmony_ci	p2p_add_device(p2p, bssid, freq, rx_time, level, ies, ies_len, 1);
3490e5b75505Sopenharmony_ci
3491e5b75505Sopenharmony_ci	return 0;
3492e5b75505Sopenharmony_ci}
3493e5b75505Sopenharmony_ci
3494e5b75505Sopenharmony_ci
3495e5b75505Sopenharmony_civoid p2p_scan_res_handled(struct p2p_data *p2p)
3496e5b75505Sopenharmony_ci{
3497e5b75505Sopenharmony_ci	if (!p2p->p2p_scan_running) {
3498e5b75505Sopenharmony_ci		p2p_dbg(p2p, "p2p_scan was not running, but scan results received");
3499e5b75505Sopenharmony_ci	}
3500e5b75505Sopenharmony_ci	p2p->p2p_scan_running = 0;
3501e5b75505Sopenharmony_ci	eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
3502e5b75505Sopenharmony_ci
3503e5b75505Sopenharmony_ci	if (p2p_run_after_scan(p2p))
3504e5b75505Sopenharmony_ci		return;
3505e5b75505Sopenharmony_ci	if (p2p->state == P2P_SEARCH)
3506e5b75505Sopenharmony_ci		p2p_continue_find(p2p);
3507e5b75505Sopenharmony_ci}
3508e5b75505Sopenharmony_ci
3509e5b75505Sopenharmony_ci
3510e5b75505Sopenharmony_civoid p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id,
3511e5b75505Sopenharmony_ci		 unsigned int bands)
3512e5b75505Sopenharmony_ci{
3513e5b75505Sopenharmony_ci	u8 dev_capab;
3514e5b75505Sopenharmony_ci	u8 *len;
3515e5b75505Sopenharmony_ci
3516e5b75505Sopenharmony_ci#ifdef CONFIG_WIFI_DISPLAY
3517e5b75505Sopenharmony_ci	if (p2p->wfd_ie_probe_req)
3518e5b75505Sopenharmony_ci		wpabuf_put_buf(ies, p2p->wfd_ie_probe_req);
3519e5b75505Sopenharmony_ci#endif /* CONFIG_WIFI_DISPLAY */
3520e5b75505Sopenharmony_ci
3521e5b75505Sopenharmony_ci	if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_PROBE_REQ_P2P])
3522e5b75505Sopenharmony_ci		wpabuf_put_buf(ies,
3523e5b75505Sopenharmony_ci			       p2p->vendor_elem[VENDOR_ELEM_PROBE_REQ_P2P]);
3524e5b75505Sopenharmony_ci
3525e5b75505Sopenharmony_ci	len = p2p_buf_add_ie_hdr(ies);
3526e5b75505Sopenharmony_ci
3527e5b75505Sopenharmony_ci	dev_capab = p2p->dev_capab & ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
3528e5b75505Sopenharmony_ci
3529e5b75505Sopenharmony_ci	/* P2PS requires Probe Request frames to include SD bit */
3530e5b75505Sopenharmony_ci	if (p2p->p2ps_seek && p2p->p2ps_seek_count)
3531e5b75505Sopenharmony_ci		dev_capab |= P2P_DEV_CAPAB_SERVICE_DISCOVERY;
3532e5b75505Sopenharmony_ci
3533e5b75505Sopenharmony_ci	p2p_buf_add_capability(ies, dev_capab, 0);
3534e5b75505Sopenharmony_ci
3535e5b75505Sopenharmony_ci	if (dev_id)
3536e5b75505Sopenharmony_ci		p2p_buf_add_device_id(ies, dev_id);
3537e5b75505Sopenharmony_ci	if (p2p->cfg->reg_class && p2p->cfg->channel)
3538e5b75505Sopenharmony_ci		p2p_buf_add_listen_channel(ies, p2p->cfg->country,
3539e5b75505Sopenharmony_ci					   p2p->cfg->reg_class,
3540e5b75505Sopenharmony_ci					   p2p->cfg->channel);
3541e5b75505Sopenharmony_ci	if (p2p->ext_listen_interval)
3542e5b75505Sopenharmony_ci		p2p_buf_add_ext_listen_timing(ies, p2p->ext_listen_period,
3543e5b75505Sopenharmony_ci					      p2p->ext_listen_interval);
3544e5b75505Sopenharmony_ci
3545e5b75505Sopenharmony_ci	if (bands & BAND_60_GHZ)
3546e5b75505Sopenharmony_ci		p2p_buf_add_device_info(ies, p2p, NULL);
3547e5b75505Sopenharmony_ci
3548e5b75505Sopenharmony_ci	if (p2p->p2ps_seek && p2p->p2ps_seek_count)
3549e5b75505Sopenharmony_ci		p2p_buf_add_service_hash(ies, p2p);
3550e5b75505Sopenharmony_ci
3551e5b75505Sopenharmony_ci	/* TODO: p2p_buf_add_operating_channel() if GO */
3552e5b75505Sopenharmony_ci	p2p_buf_update_ie_hdr(ies, len);
3553e5b75505Sopenharmony_ci}
3554e5b75505Sopenharmony_ci
3555e5b75505Sopenharmony_ci
3556e5b75505Sopenharmony_cisize_t p2p_scan_ie_buf_len(struct p2p_data *p2p)
3557e5b75505Sopenharmony_ci{
3558e5b75505Sopenharmony_ci	size_t len = 100;
3559e5b75505Sopenharmony_ci
3560e5b75505Sopenharmony_ci#ifdef CONFIG_WIFI_DISPLAY
3561e5b75505Sopenharmony_ci	if (p2p && p2p->wfd_ie_probe_req)
3562e5b75505Sopenharmony_ci		len += wpabuf_len(p2p->wfd_ie_probe_req);
3563e5b75505Sopenharmony_ci#endif /* CONFIG_WIFI_DISPLAY */
3564e5b75505Sopenharmony_ci
3565e5b75505Sopenharmony_ci	if (p2p && p2p->vendor_elem &&
3566e5b75505Sopenharmony_ci	    p2p->vendor_elem[VENDOR_ELEM_PROBE_REQ_P2P])
3567e5b75505Sopenharmony_ci		len += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_PROBE_REQ_P2P]);
3568e5b75505Sopenharmony_ci
3569e5b75505Sopenharmony_ci	return len;
3570e5b75505Sopenharmony_ci}
3571e5b75505Sopenharmony_ci
3572e5b75505Sopenharmony_ci
3573e5b75505Sopenharmony_ciint p2p_ie_text(struct wpabuf *p2p_ie, char *buf, char *end)
3574e5b75505Sopenharmony_ci{
3575e5b75505Sopenharmony_ci	return p2p_attr_text(p2p_ie, buf, end);
3576e5b75505Sopenharmony_ci}
3577e5b75505Sopenharmony_ci
3578e5b75505Sopenharmony_ci
3579e5b75505Sopenharmony_cistatic void p2p_go_neg_req_cb(struct p2p_data *p2p, int success)
3580e5b75505Sopenharmony_ci{
3581e5b75505Sopenharmony_ci	struct p2p_device *dev = p2p->go_neg_peer;
3582e5b75505Sopenharmony_ci	int timeout;
3583e5b75505Sopenharmony_ci
3584e5b75505Sopenharmony_ci	p2p_dbg(p2p, "GO Negotiation Request TX callback: success=%d", success);
3585e5b75505Sopenharmony_ci
3586e5b75505Sopenharmony_ci	if (dev == NULL) {
3587e5b75505Sopenharmony_ci		p2p_dbg(p2p, "No pending GO Negotiation");
3588e5b75505Sopenharmony_ci		return;
3589e5b75505Sopenharmony_ci	}
3590e5b75505Sopenharmony_ci
3591e5b75505Sopenharmony_ci	if (success) {
3592e5b75505Sopenharmony_ci		if (dev->flags & P2P_DEV_USER_REJECTED) {
3593e5b75505Sopenharmony_ci			p2p_set_state(p2p, P2P_IDLE);
3594e5b75505Sopenharmony_ci			return;
3595e5b75505Sopenharmony_ci		}
3596e5b75505Sopenharmony_ci	} else if (dev->go_neg_req_sent) {
3597e5b75505Sopenharmony_ci		/* Cancel the increment from p2p_connect_send() on failure */
3598e5b75505Sopenharmony_ci		dev->go_neg_req_sent--;
3599e5b75505Sopenharmony_ci	}
3600e5b75505Sopenharmony_ci
3601e5b75505Sopenharmony_ci	if (!success &&
3602e5b75505Sopenharmony_ci	    (dev->info.dev_capab & P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY) &&
3603e5b75505Sopenharmony_ci	    !is_zero_ether_addr(dev->member_in_go_dev)) {
3604e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Peer " MACSTR " did not acknowledge request - try to use device discoverability through its GO",
3605e5b75505Sopenharmony_ci			MAC2STR(dev->info.p2p_device_addr));
3606e5b75505Sopenharmony_ci		p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
3607e5b75505Sopenharmony_ci		p2p_send_dev_disc_req(p2p, dev);
3608e5b75505Sopenharmony_ci		return;
3609e5b75505Sopenharmony_ci	}
3610e5b75505Sopenharmony_ci
3611e5b75505Sopenharmony_ci	/*
3612e5b75505Sopenharmony_ci	 * Use P2P find, if needed, to find the other device from its listen
3613e5b75505Sopenharmony_ci	 * channel.
3614e5b75505Sopenharmony_ci	 */
3615e5b75505Sopenharmony_ci	p2p_set_state(p2p, P2P_CONNECT);
3616e5b75505Sopenharmony_ci	timeout = success ? 500000 : 100000;
3617e5b75505Sopenharmony_ci	if (!success && p2p->go_neg_peer &&
3618e5b75505Sopenharmony_ci	    (p2p->go_neg_peer->flags & P2P_DEV_PEER_WAITING_RESPONSE)) {
3619e5b75505Sopenharmony_ci		unsigned int r;
3620e5b75505Sopenharmony_ci		/*
3621e5b75505Sopenharmony_ci		 * Peer is expected to wait our response and we will skip the
3622e5b75505Sopenharmony_ci		 * listen phase. Add some randomness to the wait time here to
3623e5b75505Sopenharmony_ci		 * make it less likely to hit cases where we could end up in
3624e5b75505Sopenharmony_ci		 * sync with peer not listening.
3625e5b75505Sopenharmony_ci		 */
3626e5b75505Sopenharmony_ci		if (os_get_random((u8 *) &r, sizeof(r)) < 0)
3627e5b75505Sopenharmony_ci			r = 0;
3628e5b75505Sopenharmony_ci		timeout += r % 100000;
3629e5b75505Sopenharmony_ci	}
3630e5b75505Sopenharmony_ci	p2p_set_timeout(p2p, 0, timeout);
3631e5b75505Sopenharmony_ci}
3632e5b75505Sopenharmony_ci
3633e5b75505Sopenharmony_ci
3634e5b75505Sopenharmony_cistatic void p2p_go_neg_resp_cb(struct p2p_data *p2p, int success)
3635e5b75505Sopenharmony_ci{
3636e5b75505Sopenharmony_ci	p2p_dbg(p2p, "GO Negotiation Response TX callback: success=%d",
3637e5b75505Sopenharmony_ci		success);
3638e5b75505Sopenharmony_ci	if (!p2p->go_neg_peer && p2p->state == P2P_PROVISIONING) {
3639e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Ignore TX callback event - GO Negotiation is not running anymore");
3640e5b75505Sopenharmony_ci		return;
3641e5b75505Sopenharmony_ci	}
3642e5b75505Sopenharmony_ci	p2p_set_state(p2p, P2P_CONNECT);
3643e5b75505Sopenharmony_ci#ifdef CONFIG_OHOS_P2P
3644e5b75505Sopenharmony_ci	p2p_set_timeout(p2p, 0, 800000);
3645e5b75505Sopenharmony_ci#else
3646e5b75505Sopenharmony_ci	p2p_set_timeout(p2p, 0, 500000);
3647e5b75505Sopenharmony_ci#endif // CONFIG_OHOS_P2P
3648e5b75505Sopenharmony_ci}
3649e5b75505Sopenharmony_ci
3650e5b75505Sopenharmony_ci
3651e5b75505Sopenharmony_cistatic void p2p_go_neg_resp_failure_cb(struct p2p_data *p2p, int success,
3652e5b75505Sopenharmony_ci				       const u8 *addr)
3653e5b75505Sopenharmony_ci{
3654e5b75505Sopenharmony_ci	p2p_dbg(p2p, "GO Negotiation Response (failure) TX callback: success=%d", success);
3655e5b75505Sopenharmony_ci	if (p2p->go_neg_peer && p2p->go_neg_peer->status != P2P_SC_SUCCESS) {
3656e5b75505Sopenharmony_ci		p2p_go_neg_failed(p2p, p2p->go_neg_peer->status);
3657e5b75505Sopenharmony_ci		return;
3658e5b75505Sopenharmony_ci	}
3659e5b75505Sopenharmony_ci
3660e5b75505Sopenharmony_ci	if (success) {
3661e5b75505Sopenharmony_ci		struct p2p_device *dev;
3662e5b75505Sopenharmony_ci		dev = p2p_get_device(p2p, addr);
3663e5b75505Sopenharmony_ci		if (dev &&
3664e5b75505Sopenharmony_ci		    dev->status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE)
3665e5b75505Sopenharmony_ci			dev->flags |= P2P_DEV_PEER_WAITING_RESPONSE;
3666e5b75505Sopenharmony_ci	}
3667e5b75505Sopenharmony_ci
3668e5b75505Sopenharmony_ci	if (p2p->state == P2P_SEARCH || p2p->state == P2P_SD_DURING_FIND)
3669e5b75505Sopenharmony_ci		p2p_continue_find(p2p);
3670e5b75505Sopenharmony_ci}
3671e5b75505Sopenharmony_ci
3672e5b75505Sopenharmony_ci
3673e5b75505Sopenharmony_cistatic void p2p_go_neg_conf_cb(struct p2p_data *p2p,
3674e5b75505Sopenharmony_ci			       enum p2p_send_action_result result)
3675e5b75505Sopenharmony_ci{
3676e5b75505Sopenharmony_ci	struct p2p_device *dev;
3677e5b75505Sopenharmony_ci
3678e5b75505Sopenharmony_ci	p2p_dbg(p2p, "GO Negotiation Confirm TX callback: result=%d", result);
3679e5b75505Sopenharmony_ci	if (result == P2P_SEND_ACTION_FAILED) {
3680e5b75505Sopenharmony_ci		p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
3681e5b75505Sopenharmony_ci		p2p_go_neg_failed(p2p, -1);
3682e5b75505Sopenharmony_ci		return;
3683e5b75505Sopenharmony_ci	}
3684e5b75505Sopenharmony_ci
3685e5b75505Sopenharmony_ci	dev = p2p->go_neg_peer;
3686e5b75505Sopenharmony_ci
3687e5b75505Sopenharmony_ci	if (result == P2P_SEND_ACTION_NO_ACK) {
3688e5b75505Sopenharmony_ci		/*
3689e5b75505Sopenharmony_ci		 * Retry GO Negotiation Confirmation
3690e5b75505Sopenharmony_ci		 * P2P_GO_NEG_CNF_MAX_RETRY_COUNT times if we did not receive
3691e5b75505Sopenharmony_ci		 * ACK for confirmation.
3692e5b75505Sopenharmony_ci		 */
3693e5b75505Sopenharmony_ci		if (dev && dev->go_neg_conf &&
3694e5b75505Sopenharmony_ci		    dev->go_neg_conf_sent <= P2P_GO_NEG_CNF_MAX_RETRY_COUNT) {
3695e5b75505Sopenharmony_ci			p2p_dbg(p2p, "GO Negotiation Confirm retry %d",
3696e5b75505Sopenharmony_ci				dev->go_neg_conf_sent);
3697e5b75505Sopenharmony_ci			p2p->pending_action_state = P2P_PENDING_GO_NEG_CONFIRM;
3698e5b75505Sopenharmony_ci			if (p2p_send_action(p2p, dev->go_neg_conf_freq,
3699e5b75505Sopenharmony_ci					    dev->info.p2p_device_addr,
3700e5b75505Sopenharmony_ci					    p2p->cfg->dev_addr,
3701e5b75505Sopenharmony_ci					    dev->info.p2p_device_addr,
3702e5b75505Sopenharmony_ci					    wpabuf_head(dev->go_neg_conf),
3703e5b75505Sopenharmony_ci					    wpabuf_len(dev->go_neg_conf), 0) >=
3704e5b75505Sopenharmony_ci			    0) {
3705e5b75505Sopenharmony_ci				dev->go_neg_conf_sent++;
3706e5b75505Sopenharmony_ci				return;
3707e5b75505Sopenharmony_ci			}
3708e5b75505Sopenharmony_ci			p2p_dbg(p2p, "Failed to re-send Action frame");
3709e5b75505Sopenharmony_ci
3710e5b75505Sopenharmony_ci			/*
3711e5b75505Sopenharmony_ci			 * Continue with the assumption that the first attempt
3712e5b75505Sopenharmony_ci			 * went through and just the ACK frame was lost.
3713e5b75505Sopenharmony_ci			 */
3714e5b75505Sopenharmony_ci		}
3715e5b75505Sopenharmony_ci
3716e5b75505Sopenharmony_ci		/*
3717e5b75505Sopenharmony_ci		 * It looks like the TX status for GO Negotiation Confirm is
3718e5b75505Sopenharmony_ci		 * often showing failure even when the peer has actually
3719e5b75505Sopenharmony_ci		 * received the frame. Since the peer may change channels
3720e5b75505Sopenharmony_ci		 * immediately after having received the frame, we may not see
3721e5b75505Sopenharmony_ci		 * an Ack for retries, so just dropping a single frame may
3722e5b75505Sopenharmony_ci		 * trigger this. To allow the group formation to succeed if the
3723e5b75505Sopenharmony_ci		 * peer did indeed receive the frame, continue regardless of
3724e5b75505Sopenharmony_ci		 * the TX status.
3725e5b75505Sopenharmony_ci		 */
3726e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Assume GO Negotiation Confirm TX was actually received by the peer even though Ack was not reported");
3727e5b75505Sopenharmony_ci	}
3728e5b75505Sopenharmony_ci
3729e5b75505Sopenharmony_ci	p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
3730e5b75505Sopenharmony_ci
3731e5b75505Sopenharmony_ci	if (dev == NULL)
3732e5b75505Sopenharmony_ci		return;
3733e5b75505Sopenharmony_ci
3734e5b75505Sopenharmony_ci	p2p_go_complete(p2p, dev);
3735e5b75505Sopenharmony_ci}
3736e5b75505Sopenharmony_ci
3737e5b75505Sopenharmony_ci
3738e5b75505Sopenharmony_civoid p2p_send_action_cb(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
3739e5b75505Sopenharmony_ci			const u8 *src, const u8 *bssid,
3740e5b75505Sopenharmony_ci			enum p2p_send_action_result result)
3741e5b75505Sopenharmony_ci{
3742e5b75505Sopenharmony_ci	enum p2p_pending_action_state state;
3743e5b75505Sopenharmony_ci	int success;
3744e5b75505Sopenharmony_ci
3745e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Action frame TX callback (state=%d freq=%u dst=" MACSTR
3746e5b75505Sopenharmony_ci		" src=" MACSTR " bssid=" MACSTR " result=%d p2p_state=%s)",
3747e5b75505Sopenharmony_ci		p2p->pending_action_state, freq, MAC2STR(dst), MAC2STR(src),
3748e5b75505Sopenharmony_ci		MAC2STR(bssid), result, p2p_state_txt(p2p->state));
3749e5b75505Sopenharmony_ci	success = result == P2P_SEND_ACTION_SUCCESS;
3750e5b75505Sopenharmony_ci	state = p2p->pending_action_state;
3751e5b75505Sopenharmony_ci	p2p->pending_action_state = P2P_NO_PENDING_ACTION;
3752e5b75505Sopenharmony_ci	switch (state) {
3753e5b75505Sopenharmony_ci	case P2P_NO_PENDING_ACTION:
3754e5b75505Sopenharmony_ci		if (p2p->send_action_in_progress) {
3755e5b75505Sopenharmony_ci			p2p->send_action_in_progress = 0;
3756e5b75505Sopenharmony_ci			p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
3757e5b75505Sopenharmony_ci		}
3758e5b75505Sopenharmony_ci		break;
3759e5b75505Sopenharmony_ci	case P2P_PENDING_GO_NEG_REQUEST:
3760e5b75505Sopenharmony_ci		p2p_go_neg_req_cb(p2p, success);
3761e5b75505Sopenharmony_ci		break;
3762e5b75505Sopenharmony_ci	case P2P_PENDING_GO_NEG_RESPONSE:
3763e5b75505Sopenharmony_ci		p2p_go_neg_resp_cb(p2p, success);
3764e5b75505Sopenharmony_ci		break;
3765e5b75505Sopenharmony_ci	case P2P_PENDING_GO_NEG_RESPONSE_FAILURE:
3766e5b75505Sopenharmony_ci		p2p_go_neg_resp_failure_cb(p2p, success, dst);
3767e5b75505Sopenharmony_ci		break;
3768e5b75505Sopenharmony_ci	case P2P_PENDING_GO_NEG_CONFIRM:
3769e5b75505Sopenharmony_ci		p2p_go_neg_conf_cb(p2p, result);
3770e5b75505Sopenharmony_ci		break;
3771e5b75505Sopenharmony_ci	case P2P_PENDING_SD:
3772e5b75505Sopenharmony_ci		p2p_sd_cb(p2p, success);
3773e5b75505Sopenharmony_ci		break;
3774e5b75505Sopenharmony_ci	case P2P_PENDING_PD:
3775e5b75505Sopenharmony_ci		p2p_prov_disc_cb(p2p, success);
3776e5b75505Sopenharmony_ci		break;
3777e5b75505Sopenharmony_ci	case P2P_PENDING_PD_RESPONSE:
3778e5b75505Sopenharmony_ci		p2p_prov_disc_resp_cb(p2p, success);
3779e5b75505Sopenharmony_ci		break;
3780e5b75505Sopenharmony_ci	case P2P_PENDING_INVITATION_REQUEST:
3781e5b75505Sopenharmony_ci		p2p_invitation_req_cb(p2p, success);
3782e5b75505Sopenharmony_ci		break;
3783e5b75505Sopenharmony_ci	case P2P_PENDING_INVITATION_RESPONSE:
3784e5b75505Sopenharmony_ci		p2p_invitation_resp_cb(p2p, success);
3785e5b75505Sopenharmony_ci		break;
3786e5b75505Sopenharmony_ci	case P2P_PENDING_DEV_DISC_REQUEST:
3787e5b75505Sopenharmony_ci		p2p_dev_disc_req_cb(p2p, success);
3788e5b75505Sopenharmony_ci		break;
3789e5b75505Sopenharmony_ci	case P2P_PENDING_DEV_DISC_RESPONSE:
3790e5b75505Sopenharmony_ci		p2p_dev_disc_resp_cb(p2p, success);
3791e5b75505Sopenharmony_ci		break;
3792e5b75505Sopenharmony_ci	case P2P_PENDING_GO_DISC_REQ:
3793e5b75505Sopenharmony_ci		p2p_go_disc_req_cb(p2p, success);
3794e5b75505Sopenharmony_ci		break;
3795e5b75505Sopenharmony_ci	}
3796e5b75505Sopenharmony_ci}
3797e5b75505Sopenharmony_ci
3798e5b75505Sopenharmony_ci
3799e5b75505Sopenharmony_civoid p2p_listen_cb(struct p2p_data *p2p, unsigned int freq,
3800e5b75505Sopenharmony_ci		   unsigned int duration)
3801e5b75505Sopenharmony_ci{
3802e5b75505Sopenharmony_ci	if (freq == p2p->pending_client_disc_freq) {
3803e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Client discoverability remain-awake completed");
3804e5b75505Sopenharmony_ci		p2p->pending_client_disc_freq = 0;
3805e5b75505Sopenharmony_ci		return;
3806e5b75505Sopenharmony_ci	}
3807e5b75505Sopenharmony_ci
3808e5b75505Sopenharmony_ci	if (freq != p2p->pending_listen_freq) {
3809e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Unexpected listen callback for freq=%u duration=%u (pending_listen_freq=%u)",
3810e5b75505Sopenharmony_ci			freq, duration, p2p->pending_listen_freq);
3811e5b75505Sopenharmony_ci		return;
3812e5b75505Sopenharmony_ci	}
3813e5b75505Sopenharmony_ci
3814e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Starting Listen timeout(%u,%u) on freq=%u based on callback",
3815e5b75505Sopenharmony_ci		p2p->pending_listen_sec, p2p->pending_listen_usec,
3816e5b75505Sopenharmony_ci		p2p->pending_listen_freq);
3817e5b75505Sopenharmony_ci	p2p->in_listen = 1;
3818e5b75505Sopenharmony_ci	p2p->drv_in_listen = freq;
3819e5b75505Sopenharmony_ci	if (p2p->pending_listen_sec || p2p->pending_listen_usec) {
3820e5b75505Sopenharmony_ci		/*
3821e5b75505Sopenharmony_ci		 * Add 20 msec extra wait to avoid race condition with driver
3822e5b75505Sopenharmony_ci		 * remain-on-channel end event, i.e., give driver more time to
3823e5b75505Sopenharmony_ci		 * complete the operation before our timeout expires.
3824e5b75505Sopenharmony_ci		 */
3825e5b75505Sopenharmony_ci		p2p_set_timeout(p2p, p2p->pending_listen_sec,
3826e5b75505Sopenharmony_ci				p2p->pending_listen_usec + 20000);
3827e5b75505Sopenharmony_ci	}
3828e5b75505Sopenharmony_ci
3829e5b75505Sopenharmony_ci	p2p->pending_listen_freq = 0;
3830e5b75505Sopenharmony_ci}
3831e5b75505Sopenharmony_ci
3832e5b75505Sopenharmony_ci
3833e5b75505Sopenharmony_ciint p2p_listen_end(struct p2p_data *p2p, unsigned int freq)
3834e5b75505Sopenharmony_ci{
3835e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Driver ended Listen state (freq=%u)", freq);
3836e5b75505Sopenharmony_ci	p2p->drv_in_listen = 0;
3837e5b75505Sopenharmony_ci	if (p2p->in_listen)
3838e5b75505Sopenharmony_ci		return 0; /* Internal timeout will trigger the next step */
3839e5b75505Sopenharmony_ci
3840e5b75505Sopenharmony_ci	if (p2p->state == P2P_WAIT_PEER_CONNECT && p2p->go_neg_peer &&
3841e5b75505Sopenharmony_ci	    p2p->pending_listen_freq) {
3842e5b75505Sopenharmony_ci		/*
3843e5b75505Sopenharmony_ci		 * Better wait a bit if the driver is unable to start
3844e5b75505Sopenharmony_ci		 * offchannel operation for some reason to continue with
3845e5b75505Sopenharmony_ci		 * P2P_WAIT_PEER_(IDLE/CONNECT) state transitions.
3846e5b75505Sopenharmony_ci		 */
3847e5b75505Sopenharmony_ci		p2p_dbg(p2p,
3848e5b75505Sopenharmony_ci			"Listen operation did not seem to start - delay idle phase to avoid busy loop");
3849e5b75505Sopenharmony_ci		p2p_set_timeout(p2p, 0, 100000);
3850e5b75505Sopenharmony_ci		return 1;
3851e5b75505Sopenharmony_ci	}
3852e5b75505Sopenharmony_ci
3853e5b75505Sopenharmony_ci	if (p2p->state == P2P_CONNECT_LISTEN && p2p->go_neg_peer) {
3854e5b75505Sopenharmony_ci		if (p2p->go_neg_peer->connect_reqs >= 120) {
3855e5b75505Sopenharmony_ci			p2p_dbg(p2p, "Timeout on sending GO Negotiation Request without getting response");
3856e5b75505Sopenharmony_ci			p2p_go_neg_failed(p2p, -1);
3857e5b75505Sopenharmony_ci			return 0;
3858e5b75505Sopenharmony_ci		}
3859e5b75505Sopenharmony_ci
3860e5b75505Sopenharmony_ci		p2p_set_state(p2p, P2P_CONNECT);
3861e5b75505Sopenharmony_ci		p2p_connect_send(p2p, p2p->go_neg_peer);
3862e5b75505Sopenharmony_ci		return 1;
3863e5b75505Sopenharmony_ci	} else if (p2p->state == P2P_SEARCH) {
3864e5b75505Sopenharmony_ci		if (p2p->p2p_scan_running) {
3865e5b75505Sopenharmony_ci			 /*
3866e5b75505Sopenharmony_ci			  * Search is already in progress. This can happen if
3867e5b75505Sopenharmony_ci			  * an Action frame RX is reported immediately after
3868e5b75505Sopenharmony_ci			  * the end of a remain-on-channel operation and the
3869e5b75505Sopenharmony_ci			  * response frame to that is sent using an offchannel
3870e5b75505Sopenharmony_ci			  * operation while in p2p_find. Avoid an attempt to
3871e5b75505Sopenharmony_ci			  * restart a scan here.
3872e5b75505Sopenharmony_ci			  */
3873e5b75505Sopenharmony_ci			p2p_dbg(p2p, "p2p_scan already in progress - do not try to start a new one");
3874e5b75505Sopenharmony_ci			return 1;
3875e5b75505Sopenharmony_ci		}
3876e5b75505Sopenharmony_ci		if (p2p->pending_listen_freq) {
3877e5b75505Sopenharmony_ci			/*
3878e5b75505Sopenharmony_ci			 * Better wait a bit if the driver is unable to start
3879e5b75505Sopenharmony_ci			 * offchannel operation for some reason. p2p_search()
3880e5b75505Sopenharmony_ci			 * will be started from internal timeout.
3881e5b75505Sopenharmony_ci			 */
3882e5b75505Sopenharmony_ci			p2p_dbg(p2p, "Listen operation did not seem to start - delay search phase to avoid busy loop");
3883e5b75505Sopenharmony_ci			p2p_set_timeout(p2p, 0, 100000);
3884e5b75505Sopenharmony_ci			return 1;
3885e5b75505Sopenharmony_ci		}
3886e5b75505Sopenharmony_ci		if (p2p->search_delay) {
3887e5b75505Sopenharmony_ci			p2p_dbg(p2p, "Delay search operation by %u ms",
3888e5b75505Sopenharmony_ci				p2p->search_delay);
3889e5b75505Sopenharmony_ci			p2p_set_timeout(p2p, p2p->search_delay / 1000,
3890e5b75505Sopenharmony_ci					(p2p->search_delay % 1000) * 1000);
3891e5b75505Sopenharmony_ci			return 1;
3892e5b75505Sopenharmony_ci		}
3893e5b75505Sopenharmony_ci		p2p_search(p2p);
3894e5b75505Sopenharmony_ci		return 1;
3895e5b75505Sopenharmony_ci	}
3896e5b75505Sopenharmony_ci
3897e5b75505Sopenharmony_ci	return 0;
3898e5b75505Sopenharmony_ci}
3899e5b75505Sopenharmony_ci
3900e5b75505Sopenharmony_ci
3901e5b75505Sopenharmony_cistatic void p2p_timeout_connect(struct p2p_data *p2p)
3902e5b75505Sopenharmony_ci{
3903e5b75505Sopenharmony_ci	p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
3904e5b75505Sopenharmony_ci	if (p2p->go_neg_peer &&
3905e5b75505Sopenharmony_ci	    (p2p->go_neg_peer->flags & P2P_DEV_WAIT_GO_NEG_CONFIRM)) {
3906e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Wait for GO Negotiation Confirm timed out - assume GO Negotiation failed");
3907e5b75505Sopenharmony_ci		p2p_go_neg_failed(p2p, -1);
3908e5b75505Sopenharmony_ci		return;
3909e5b75505Sopenharmony_ci	}
3910e5b75505Sopenharmony_ci	if (p2p->go_neg_peer &&
3911e5b75505Sopenharmony_ci	    (p2p->go_neg_peer->flags & P2P_DEV_PEER_WAITING_RESPONSE) &&
3912e5b75505Sopenharmony_ci	    p2p->go_neg_peer->connect_reqs < 120) {
3913e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Peer expected to wait our response - skip listen");
3914e5b75505Sopenharmony_ci		p2p_connect_send(p2p, p2p->go_neg_peer);
3915e5b75505Sopenharmony_ci		return;
3916e5b75505Sopenharmony_ci	}
3917e5b75505Sopenharmony_ci	if (p2p->go_neg_peer && p2p->go_neg_peer->oob_go_neg_freq > 0) {
3918e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Skip connect-listen since GO Neg channel known (OOB)");
3919e5b75505Sopenharmony_ci		p2p_set_state(p2p, P2P_CONNECT_LISTEN);
3920e5b75505Sopenharmony_ci		p2p_set_timeout(p2p, 0, 30000);
3921e5b75505Sopenharmony_ci		return;
3922e5b75505Sopenharmony_ci	}
3923e5b75505Sopenharmony_ci	p2p_set_state(p2p, P2P_CONNECT_LISTEN);
3924e5b75505Sopenharmony_ci	p2p_listen_in_find(p2p, 0);
3925e5b75505Sopenharmony_ci}
3926e5b75505Sopenharmony_ci
3927e5b75505Sopenharmony_ci
3928e5b75505Sopenharmony_cistatic void p2p_timeout_connect_listen(struct p2p_data *p2p)
3929e5b75505Sopenharmony_ci{
3930e5b75505Sopenharmony_ci	if (p2p->go_neg_peer) {
3931e5b75505Sopenharmony_ci		if (p2p->drv_in_listen) {
3932e5b75505Sopenharmony_ci			p2p_dbg(p2p, "Driver is still in Listen state; wait for it to complete");
3933e5b75505Sopenharmony_ci			return;
3934e5b75505Sopenharmony_ci		}
3935e5b75505Sopenharmony_ci
3936e5b75505Sopenharmony_ci		if (p2p->go_neg_peer->connect_reqs >= 120) {
3937e5b75505Sopenharmony_ci			p2p_dbg(p2p, "Timeout on sending GO Negotiation Request without getting response");
3938e5b75505Sopenharmony_ci			p2p_go_neg_failed(p2p, -1);
3939e5b75505Sopenharmony_ci			return;
3940e5b75505Sopenharmony_ci		}
3941e5b75505Sopenharmony_ci
3942e5b75505Sopenharmony_ci		p2p_set_state(p2p, P2P_CONNECT);
3943e5b75505Sopenharmony_ci		p2p_connect_send(p2p, p2p->go_neg_peer);
3944e5b75505Sopenharmony_ci	} else
3945e5b75505Sopenharmony_ci		p2p_set_state(p2p, P2P_IDLE);
3946e5b75505Sopenharmony_ci}
3947e5b75505Sopenharmony_ci
3948e5b75505Sopenharmony_ci
3949e5b75505Sopenharmony_cistatic void p2p_timeout_wait_peer_connect(struct p2p_data *p2p)
3950e5b75505Sopenharmony_ci{
3951e5b75505Sopenharmony_ci	p2p_set_state(p2p, P2P_WAIT_PEER_IDLE);
3952e5b75505Sopenharmony_ci
3953e5b75505Sopenharmony_ci	if (p2p->cfg->is_concurrent_session_active &&
3954e5b75505Sopenharmony_ci	    p2p->cfg->is_concurrent_session_active(p2p->cfg->cb_ctx))
3955e5b75505Sopenharmony_ci		p2p_set_timeout(p2p, 0, 500000);
3956e5b75505Sopenharmony_ci	else
3957e5b75505Sopenharmony_ci		p2p_set_timeout(p2p, 0, 200000);
3958e5b75505Sopenharmony_ci}
3959e5b75505Sopenharmony_ci
3960e5b75505Sopenharmony_ci
3961e5b75505Sopenharmony_cistatic void p2p_timeout_wait_peer_idle(struct p2p_data *p2p)
3962e5b75505Sopenharmony_ci{
3963e5b75505Sopenharmony_ci	struct p2p_device *dev = p2p->go_neg_peer;
3964e5b75505Sopenharmony_ci
3965e5b75505Sopenharmony_ci	if (dev == NULL) {
3966e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Unknown GO Neg peer - stop GO Neg wait");
3967e5b75505Sopenharmony_ci		return;
3968e5b75505Sopenharmony_ci	}
3969e5b75505Sopenharmony_ci
3970e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Go to Listen state while waiting for the peer to become ready for GO Negotiation");
3971e5b75505Sopenharmony_ci	p2p_set_state(p2p, P2P_WAIT_PEER_CONNECT);
3972e5b75505Sopenharmony_ci	p2p_listen_in_find(p2p, 0);
3973e5b75505Sopenharmony_ci}
3974e5b75505Sopenharmony_ci
3975e5b75505Sopenharmony_ci
3976e5b75505Sopenharmony_cistatic void p2p_timeout_sd_during_find(struct p2p_data *p2p)
3977e5b75505Sopenharmony_ci{
3978e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Service Discovery Query timeout");
3979e5b75505Sopenharmony_ci	if (p2p->sd_peer) {
3980e5b75505Sopenharmony_ci		p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
3981e5b75505Sopenharmony_ci		p2p->sd_peer = NULL;
3982e5b75505Sopenharmony_ci	}
3983e5b75505Sopenharmony_ci	p2p_continue_find(p2p);
3984e5b75505Sopenharmony_ci}
3985e5b75505Sopenharmony_ci
3986e5b75505Sopenharmony_ci
3987e5b75505Sopenharmony_cistatic void p2p_timeout_prov_disc_during_find(struct p2p_data *p2p)
3988e5b75505Sopenharmony_ci{
3989e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Provision Discovery Request timeout");
3990e5b75505Sopenharmony_ci	p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
3991e5b75505Sopenharmony_ci	p2p_continue_find(p2p);
3992e5b75505Sopenharmony_ci}
3993e5b75505Sopenharmony_ci
3994e5b75505Sopenharmony_ci
3995e5b75505Sopenharmony_cistatic void p2p_timeout_prov_disc_req(struct p2p_data *p2p)
3996e5b75505Sopenharmony_ci{
3997e5b75505Sopenharmony_ci	u32 adv_id = 0;
3998e5b75505Sopenharmony_ci	u8 *adv_mac = NULL;
3999e5b75505Sopenharmony_ci
4000e5b75505Sopenharmony_ci	p2p->pending_action_state = P2P_NO_PENDING_ACTION;
4001e5b75505Sopenharmony_ci
4002e5b75505Sopenharmony_ci	/*
4003e5b75505Sopenharmony_ci	 * For user initiated PD requests that we have not gotten any responses
4004e5b75505Sopenharmony_ci	 * for while in IDLE state, we retry them a couple of times before
4005e5b75505Sopenharmony_ci	 * giving up.
4006e5b75505Sopenharmony_ci	 */
4007e5b75505Sopenharmony_ci	if (!p2p->user_initiated_pd)
4008e5b75505Sopenharmony_ci		return;
4009e5b75505Sopenharmony_ci
4010e5b75505Sopenharmony_ci	p2p_dbg(p2p, "User initiated Provision Discovery Request timeout");
4011e5b75505Sopenharmony_ci
4012e5b75505Sopenharmony_ci	if (p2p->pd_retries) {
4013e5b75505Sopenharmony_ci		p2p->pd_retries--;
4014e5b75505Sopenharmony_ci		p2p_retry_pd(p2p);
4015e5b75505Sopenharmony_ci	} else {
4016e5b75505Sopenharmony_ci		struct p2p_device *dev;
4017e5b75505Sopenharmony_ci		int for_join = 0;
4018e5b75505Sopenharmony_ci
4019e5b75505Sopenharmony_ci		dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
4020e5b75505Sopenharmony_ci			if (os_memcmp(p2p->pending_pd_devaddr,
4021e5b75505Sopenharmony_ci				      dev->info.p2p_device_addr, ETH_ALEN) != 0)
4022e5b75505Sopenharmony_ci				continue;
4023e5b75505Sopenharmony_ci			if (dev->req_config_methods &&
4024e5b75505Sopenharmony_ci			    (dev->flags & P2P_DEV_PD_FOR_JOIN))
4025e5b75505Sopenharmony_ci				for_join = 1;
4026e5b75505Sopenharmony_ci		}
4027e5b75505Sopenharmony_ci
4028e5b75505Sopenharmony_ci		if (p2p->p2ps_prov) {
4029e5b75505Sopenharmony_ci			adv_id = p2p->p2ps_prov->adv_id;
4030e5b75505Sopenharmony_ci			adv_mac = p2p->p2ps_prov->adv_mac;
4031e5b75505Sopenharmony_ci		}
4032e5b75505Sopenharmony_ci
4033e5b75505Sopenharmony_ci		if (p2p->cfg->prov_disc_fail)
4034e5b75505Sopenharmony_ci			p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx,
4035e5b75505Sopenharmony_ci						 p2p->pending_pd_devaddr,
4036e5b75505Sopenharmony_ci						 for_join ?
4037e5b75505Sopenharmony_ci						 P2P_PROV_DISC_TIMEOUT_JOIN :
4038e5b75505Sopenharmony_ci						 P2P_PROV_DISC_TIMEOUT,
4039e5b75505Sopenharmony_ci						 adv_id, adv_mac, NULL);
4040e5b75505Sopenharmony_ci		p2p_reset_pending_pd(p2p);
4041e5b75505Sopenharmony_ci	}
4042e5b75505Sopenharmony_ci}
4043e5b75505Sopenharmony_ci
4044e5b75505Sopenharmony_ci
4045e5b75505Sopenharmony_cistatic void p2p_timeout_invite(struct p2p_data *p2p)
4046e5b75505Sopenharmony_ci{
4047e5b75505Sopenharmony_ci	p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
4048e5b75505Sopenharmony_ci	p2p_set_state(p2p, P2P_INVITE_LISTEN);
4049e5b75505Sopenharmony_ci	if (p2p->inv_role == P2P_INVITE_ROLE_ACTIVE_GO) {
4050e5b75505Sopenharmony_ci		/*
4051e5b75505Sopenharmony_ci		 * Better remain on operating channel instead of listen channel
4052e5b75505Sopenharmony_ci		 * when running a group.
4053e5b75505Sopenharmony_ci		 */
4054e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Inviting in active GO role - wait on operating channel");
4055e5b75505Sopenharmony_ci		p2p_set_timeout(p2p, 0, 100000);
4056e5b75505Sopenharmony_ci		return;
4057e5b75505Sopenharmony_ci	}
4058e5b75505Sopenharmony_ci	p2p_listen_in_find(p2p, 0);
4059e5b75505Sopenharmony_ci}
4060e5b75505Sopenharmony_ci
4061e5b75505Sopenharmony_ci
4062e5b75505Sopenharmony_cistatic void p2p_timeout_invite_listen(struct p2p_data *p2p)
4063e5b75505Sopenharmony_ci{
4064e5b75505Sopenharmony_ci	if (p2p->invite_peer && p2p->invite_peer->invitation_reqs < 100) {
4065e5b75505Sopenharmony_ci		p2p_set_state(p2p, P2P_INVITE);
4066e5b75505Sopenharmony_ci		p2p_invite_send(p2p, p2p->invite_peer,
4067e5b75505Sopenharmony_ci				p2p->invite_go_dev_addr, p2p->invite_dev_pw_id);
4068e5b75505Sopenharmony_ci	} else {
4069e5b75505Sopenharmony_ci		if (p2p->invite_peer) {
4070e5b75505Sopenharmony_ci			p2p_dbg(p2p, "Invitation Request retry limit reached");
4071e5b75505Sopenharmony_ci			if (p2p->cfg->invitation_result)
4072e5b75505Sopenharmony_ci				p2p->cfg->invitation_result(
4073e5b75505Sopenharmony_ci					p2p->cfg->cb_ctx, -1, NULL, NULL,
4074e5b75505Sopenharmony_ci					p2p->invite_peer->info.p2p_device_addr,
4075e5b75505Sopenharmony_ci					0, 0);
4076e5b75505Sopenharmony_ci		}
4077e5b75505Sopenharmony_ci		p2p_set_state(p2p, P2P_IDLE);
4078e5b75505Sopenharmony_ci	}
4079e5b75505Sopenharmony_ci}
4080e5b75505Sopenharmony_ci
4081e5b75505Sopenharmony_ci
4082e5b75505Sopenharmony_cistatic void p2p_state_timeout(void *eloop_ctx, void *timeout_ctx)
4083e5b75505Sopenharmony_ci{
4084e5b75505Sopenharmony_ci	struct p2p_data *p2p = eloop_ctx;
4085e5b75505Sopenharmony_ci
4086e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Timeout (state=%s)", p2p_state_txt(p2p->state));
4087e5b75505Sopenharmony_ci
4088e5b75505Sopenharmony_ci	p2p->in_listen = 0;
4089e5b75505Sopenharmony_ci	if (p2p->drv_in_listen) {
4090e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Driver is still in listen state - stop it");
4091e5b75505Sopenharmony_ci		p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
4092e5b75505Sopenharmony_ci	}
4093e5b75505Sopenharmony_ci
4094e5b75505Sopenharmony_ci	switch (p2p->state) {
4095e5b75505Sopenharmony_ci	case P2P_IDLE:
4096e5b75505Sopenharmony_ci		/* Check if we timed out waiting for PD req */
4097e5b75505Sopenharmony_ci		if (p2p->pending_action_state == P2P_PENDING_PD)
4098e5b75505Sopenharmony_ci			p2p_timeout_prov_disc_req(p2p);
4099e5b75505Sopenharmony_ci		break;
4100e5b75505Sopenharmony_ci	case P2P_SEARCH:
4101e5b75505Sopenharmony_ci		/* Check if we timed out waiting for PD req */
4102e5b75505Sopenharmony_ci		if (p2p->pending_action_state == P2P_PENDING_PD)
4103e5b75505Sopenharmony_ci			p2p_timeout_prov_disc_req(p2p);
4104e5b75505Sopenharmony_ci		if (p2p->search_delay && !p2p->in_search_delay) {
4105e5b75505Sopenharmony_ci			p2p_dbg(p2p, "Delay search operation by %u ms",
4106e5b75505Sopenharmony_ci				p2p->search_delay);
4107e5b75505Sopenharmony_ci			p2p->in_search_delay = 1;
4108e5b75505Sopenharmony_ci			p2p_set_timeout(p2p, p2p->search_delay / 1000,
4109e5b75505Sopenharmony_ci					(p2p->search_delay % 1000) * 1000);
4110e5b75505Sopenharmony_ci			break;
4111e5b75505Sopenharmony_ci		}
4112e5b75505Sopenharmony_ci		p2p->in_search_delay = 0;
4113e5b75505Sopenharmony_ci		p2p_search(p2p);
4114e5b75505Sopenharmony_ci		break;
4115e5b75505Sopenharmony_ci	case P2P_CONNECT:
4116e5b75505Sopenharmony_ci		p2p_timeout_connect(p2p);
4117e5b75505Sopenharmony_ci		break;
4118e5b75505Sopenharmony_ci	case P2P_CONNECT_LISTEN:
4119e5b75505Sopenharmony_ci		p2p_timeout_connect_listen(p2p);
4120e5b75505Sopenharmony_ci		break;
4121e5b75505Sopenharmony_ci	case P2P_GO_NEG:
4122e5b75505Sopenharmony_ci		break;
4123e5b75505Sopenharmony_ci	case P2P_LISTEN_ONLY:
4124e5b75505Sopenharmony_ci		/* Check if we timed out waiting for PD req */
4125e5b75505Sopenharmony_ci		if (p2p->pending_action_state == P2P_PENDING_PD)
4126e5b75505Sopenharmony_ci			p2p_timeout_prov_disc_req(p2p);
4127e5b75505Sopenharmony_ci
4128e5b75505Sopenharmony_ci		if (p2p->ext_listen_only) {
4129e5b75505Sopenharmony_ci			p2p_dbg(p2p, "Extended Listen Timing - Listen State completed");
4130e5b75505Sopenharmony_ci			p2p->ext_listen_only = 0;
4131e5b75505Sopenharmony_ci			p2p_set_state(p2p, P2P_IDLE);
4132e5b75505Sopenharmony_ci		}
4133e5b75505Sopenharmony_ci		break;
4134e5b75505Sopenharmony_ci	case P2P_WAIT_PEER_CONNECT:
4135e5b75505Sopenharmony_ci		p2p_timeout_wait_peer_connect(p2p);
4136e5b75505Sopenharmony_ci		break;
4137e5b75505Sopenharmony_ci	case P2P_WAIT_PEER_IDLE:
4138e5b75505Sopenharmony_ci		p2p_timeout_wait_peer_idle(p2p);
4139e5b75505Sopenharmony_ci		break;
4140e5b75505Sopenharmony_ci	case P2P_SD_DURING_FIND:
4141e5b75505Sopenharmony_ci		p2p_timeout_sd_during_find(p2p);
4142e5b75505Sopenharmony_ci		break;
4143e5b75505Sopenharmony_ci	case P2P_PROVISIONING:
4144e5b75505Sopenharmony_ci		break;
4145e5b75505Sopenharmony_ci	case P2P_PD_DURING_FIND:
4146e5b75505Sopenharmony_ci		p2p_timeout_prov_disc_during_find(p2p);
4147e5b75505Sopenharmony_ci		break;
4148e5b75505Sopenharmony_ci	case P2P_INVITE:
4149e5b75505Sopenharmony_ci		p2p_timeout_invite(p2p);
4150e5b75505Sopenharmony_ci		break;
4151e5b75505Sopenharmony_ci	case P2P_INVITE_LISTEN:
4152e5b75505Sopenharmony_ci		p2p_timeout_invite_listen(p2p);
4153e5b75505Sopenharmony_ci		break;
4154e5b75505Sopenharmony_ci	}
4155e5b75505Sopenharmony_ci}
4156e5b75505Sopenharmony_ci
4157e5b75505Sopenharmony_ci
4158e5b75505Sopenharmony_ciint p2p_reject(struct p2p_data *p2p, const u8 *peer_addr)
4159e5b75505Sopenharmony_ci{
4160e5b75505Sopenharmony_ci	struct p2p_device *dev;
4161e5b75505Sopenharmony_ci
4162e5b75505Sopenharmony_ci	dev = p2p_get_device(p2p, peer_addr);
4163e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Local request to reject connection attempts by peer "
4164e5b75505Sopenharmony_ci		MACSTR, MAC2STR(peer_addr));
4165e5b75505Sopenharmony_ci	if (dev == NULL) {
4166e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Peer " MACSTR " unknown", MAC2STR(peer_addr));
4167e5b75505Sopenharmony_ci		return -1;
4168e5b75505Sopenharmony_ci	}
4169e5b75505Sopenharmony_ci	dev->status = P2P_SC_FAIL_REJECTED_BY_USER;
4170e5b75505Sopenharmony_ci	dev->flags |= P2P_DEV_USER_REJECTED;
4171e5b75505Sopenharmony_ci	return 0;
4172e5b75505Sopenharmony_ci}
4173e5b75505Sopenharmony_ci
4174e5b75505Sopenharmony_ci
4175e5b75505Sopenharmony_ciconst char * p2p_wps_method_text(enum p2p_wps_method method)
4176e5b75505Sopenharmony_ci{
4177e5b75505Sopenharmony_ci	switch (method) {
4178e5b75505Sopenharmony_ci	case WPS_NOT_READY:
4179e5b75505Sopenharmony_ci		return "not-ready";
4180e5b75505Sopenharmony_ci	case WPS_PIN_DISPLAY:
4181e5b75505Sopenharmony_ci		return "Display";
4182e5b75505Sopenharmony_ci	case WPS_PIN_KEYPAD:
4183e5b75505Sopenharmony_ci		return "Keypad";
4184e5b75505Sopenharmony_ci	case WPS_PBC:
4185e5b75505Sopenharmony_ci		return "PBC";
4186e5b75505Sopenharmony_ci	case WPS_NFC:
4187e5b75505Sopenharmony_ci		return "NFC";
4188e5b75505Sopenharmony_ci	case WPS_P2PS:
4189e5b75505Sopenharmony_ci		return "P2PS";
4190e5b75505Sopenharmony_ci	}
4191e5b75505Sopenharmony_ci
4192e5b75505Sopenharmony_ci	return "??";
4193e5b75505Sopenharmony_ci}
4194e5b75505Sopenharmony_ci
4195e5b75505Sopenharmony_ci
4196e5b75505Sopenharmony_cistatic const char * p2p_go_state_text(enum p2p_go_state go_state)
4197e5b75505Sopenharmony_ci{
4198e5b75505Sopenharmony_ci	switch (go_state) {
4199e5b75505Sopenharmony_ci	case UNKNOWN_GO:
4200e5b75505Sopenharmony_ci		return "unknown";
4201e5b75505Sopenharmony_ci	case LOCAL_GO:
4202e5b75505Sopenharmony_ci		return "local";
4203e5b75505Sopenharmony_ci	case  REMOTE_GO:
4204e5b75505Sopenharmony_ci		return "remote";
4205e5b75505Sopenharmony_ci	}
4206e5b75505Sopenharmony_ci
4207e5b75505Sopenharmony_ci	return "??";
4208e5b75505Sopenharmony_ci}
4209e5b75505Sopenharmony_ci
4210e5b75505Sopenharmony_ci
4211e5b75505Sopenharmony_ciconst struct p2p_peer_info * p2p_get_peer_info(struct p2p_data *p2p,
4212e5b75505Sopenharmony_ci					       const u8 *addr, int next)
4213e5b75505Sopenharmony_ci{
4214e5b75505Sopenharmony_ci	struct p2p_device *dev;
4215e5b75505Sopenharmony_ci
4216e5b75505Sopenharmony_ci	if (addr)
4217e5b75505Sopenharmony_ci		dev = p2p_get_device(p2p, addr);
4218e5b75505Sopenharmony_ci	else
4219e5b75505Sopenharmony_ci		dev = dl_list_first(&p2p->devices, struct p2p_device, list);
4220e5b75505Sopenharmony_ci
4221e5b75505Sopenharmony_ci	if (dev && next) {
4222e5b75505Sopenharmony_ci		dev = dl_list_first(&dev->list, struct p2p_device, list);
4223e5b75505Sopenharmony_ci		if (&dev->list == &p2p->devices)
4224e5b75505Sopenharmony_ci			dev = NULL;
4225e5b75505Sopenharmony_ci	}
4226e5b75505Sopenharmony_ci
4227e5b75505Sopenharmony_ci	if (dev == NULL)
4228e5b75505Sopenharmony_ci		return NULL;
4229e5b75505Sopenharmony_ci
4230e5b75505Sopenharmony_ci	return &dev->info;
4231e5b75505Sopenharmony_ci}
4232e5b75505Sopenharmony_ci
4233e5b75505Sopenharmony_ci
4234e5b75505Sopenharmony_ciint p2p_get_peer_info_txt(const struct p2p_peer_info *info,
4235e5b75505Sopenharmony_ci			  char *buf, size_t buflen)
4236e5b75505Sopenharmony_ci{
4237e5b75505Sopenharmony_ci	struct p2p_device *dev;
4238e5b75505Sopenharmony_ci	int res;
4239e5b75505Sopenharmony_ci	char *pos, *end;
4240e5b75505Sopenharmony_ci	struct os_reltime now;
4241e5b75505Sopenharmony_ci
4242e5b75505Sopenharmony_ci	if (info == NULL)
4243e5b75505Sopenharmony_ci		return -1;
4244e5b75505Sopenharmony_ci
4245e5b75505Sopenharmony_ci	dev = (struct p2p_device *) (((u8 *) info) -
4246e5b75505Sopenharmony_ci				     offsetof(struct p2p_device, info));
4247e5b75505Sopenharmony_ci
4248e5b75505Sopenharmony_ci	pos = buf;
4249e5b75505Sopenharmony_ci	end = buf + buflen;
4250e5b75505Sopenharmony_ci
4251e5b75505Sopenharmony_ci	os_get_reltime(&now);
4252e5b75505Sopenharmony_ci	res = os_snprintf(pos, end - pos,
4253e5b75505Sopenharmony_ci			  "age=%d\n"
4254e5b75505Sopenharmony_ci			  "listen_freq=%d\n"
4255e5b75505Sopenharmony_ci			  "wps_method=%s\n"
4256e5b75505Sopenharmony_ci			  "interface_addr=" MACSTR "\n"
4257e5b75505Sopenharmony_ci			  "member_in_go_dev=" MACSTR "\n"
4258e5b75505Sopenharmony_ci			  "member_in_go_iface=" MACSTR "\n"
4259e5b75505Sopenharmony_ci			  "go_neg_req_sent=%d\n"
4260e5b75505Sopenharmony_ci			  "go_state=%s\n"
4261e5b75505Sopenharmony_ci			  "dialog_token=%u\n"
4262e5b75505Sopenharmony_ci			  "intended_addr=" MACSTR "\n"
4263e5b75505Sopenharmony_ci			  "country=%c%c\n"
4264e5b75505Sopenharmony_ci			  "oper_freq=%d\n"
4265e5b75505Sopenharmony_ci			  "req_config_methods=0x%x\n"
4266e5b75505Sopenharmony_ci			  "flags=%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n"
4267e5b75505Sopenharmony_ci			  "status=%d\n"
4268e5b75505Sopenharmony_ci			  "invitation_reqs=%u\n",
4269e5b75505Sopenharmony_ci			  (int) (now.sec - dev->last_seen.sec),
4270e5b75505Sopenharmony_ci			  dev->listen_freq,
4271e5b75505Sopenharmony_ci			  p2p_wps_method_text(dev->wps_method),
4272e5b75505Sopenharmony_ci			  MAC2STR(dev->interface_addr),
4273e5b75505Sopenharmony_ci			  MAC2STR(dev->member_in_go_dev),
4274e5b75505Sopenharmony_ci			  MAC2STR(dev->member_in_go_iface),
4275e5b75505Sopenharmony_ci			  dev->go_neg_req_sent,
4276e5b75505Sopenharmony_ci			  p2p_go_state_text(dev->go_state),
4277e5b75505Sopenharmony_ci			  dev->dialog_token,
4278e5b75505Sopenharmony_ci			  MAC2STR(dev->intended_addr),
4279e5b75505Sopenharmony_ci			  dev->country[0] ? dev->country[0] : '_',
4280e5b75505Sopenharmony_ci			  dev->country[1] ? dev->country[1] : '_',
4281e5b75505Sopenharmony_ci			  dev->oper_freq,
4282e5b75505Sopenharmony_ci			  dev->req_config_methods,
4283e5b75505Sopenharmony_ci			  dev->flags & P2P_DEV_PROBE_REQ_ONLY ?
4284e5b75505Sopenharmony_ci			  "[PROBE_REQ_ONLY]" : "",
4285e5b75505Sopenharmony_ci			  dev->flags & P2P_DEV_REPORTED ? "[REPORTED]" : "",
4286e5b75505Sopenharmony_ci			  dev->flags & P2P_DEV_NOT_YET_READY ?
4287e5b75505Sopenharmony_ci			  "[NOT_YET_READY]" : "",
4288e5b75505Sopenharmony_ci			  dev->flags & P2P_DEV_PD_PEER_DISPLAY ?
4289e5b75505Sopenharmony_ci			  "[PD_PEER_DISPLAY]" : "",
4290e5b75505Sopenharmony_ci			  dev->flags & P2P_DEV_PD_PEER_KEYPAD ?
4291e5b75505Sopenharmony_ci			  "[PD_PEER_KEYPAD]" : "",
4292e5b75505Sopenharmony_ci			  dev->flags & P2P_DEV_PD_PEER_P2PS ?
4293e5b75505Sopenharmony_ci			  "[PD_PEER_P2PS]" : "",
4294e5b75505Sopenharmony_ci			  dev->flags & P2P_DEV_USER_REJECTED ?
4295e5b75505Sopenharmony_ci			  "[USER_REJECTED]" : "",
4296e5b75505Sopenharmony_ci			  dev->flags & P2P_DEV_PEER_WAITING_RESPONSE ?
4297e5b75505Sopenharmony_ci			  "[PEER_WAITING_RESPONSE]" : "",
4298e5b75505Sopenharmony_ci			  dev->flags & P2P_DEV_PREFER_PERSISTENT_GROUP ?
4299e5b75505Sopenharmony_ci			  "[PREFER_PERSISTENT_GROUP]" : "",
4300e5b75505Sopenharmony_ci			  dev->flags & P2P_DEV_WAIT_GO_NEG_RESPONSE ?
4301e5b75505Sopenharmony_ci			  "[WAIT_GO_NEG_RESPONSE]" : "",
4302e5b75505Sopenharmony_ci			  dev->flags & P2P_DEV_WAIT_GO_NEG_CONFIRM ?
4303e5b75505Sopenharmony_ci			  "[WAIT_GO_NEG_CONFIRM]" : "",
4304e5b75505Sopenharmony_ci			  dev->flags & P2P_DEV_GROUP_CLIENT_ONLY ?
4305e5b75505Sopenharmony_ci			  "[GROUP_CLIENT_ONLY]" : "",
4306e5b75505Sopenharmony_ci			  dev->flags & P2P_DEV_FORCE_FREQ ?
4307e5b75505Sopenharmony_ci			  "[FORCE_FREQ]" : "",
4308e5b75505Sopenharmony_ci			  dev->flags & P2P_DEV_PD_FOR_JOIN ?
4309e5b75505Sopenharmony_ci			  "[PD_FOR_JOIN]" : "",
4310e5b75505Sopenharmony_ci			  dev->flags & P2P_DEV_LAST_SEEN_AS_GROUP_CLIENT ?
4311e5b75505Sopenharmony_ci			  "[LAST_SEEN_AS_GROUP_CLIENT]" : "",
4312e5b75505Sopenharmony_ci			  dev->status,
4313e5b75505Sopenharmony_ci			  dev->invitation_reqs);
4314e5b75505Sopenharmony_ci	if (os_snprintf_error(end - pos, res))
4315e5b75505Sopenharmony_ci		return pos - buf;
4316e5b75505Sopenharmony_ci	pos += res;
4317e5b75505Sopenharmony_ci
4318e5b75505Sopenharmony_ci	if (dev->ext_listen_period) {
4319e5b75505Sopenharmony_ci		res = os_snprintf(pos, end - pos,
4320e5b75505Sopenharmony_ci				  "ext_listen_period=%u\n"
4321e5b75505Sopenharmony_ci				  "ext_listen_interval=%u\n",
4322e5b75505Sopenharmony_ci				  dev->ext_listen_period,
4323e5b75505Sopenharmony_ci				  dev->ext_listen_interval);
4324e5b75505Sopenharmony_ci		if (os_snprintf_error(end - pos, res))
4325e5b75505Sopenharmony_ci			return pos - buf;
4326e5b75505Sopenharmony_ci		pos += res;
4327e5b75505Sopenharmony_ci	}
4328e5b75505Sopenharmony_ci
4329e5b75505Sopenharmony_ci	if (dev->oper_ssid_len) {
4330e5b75505Sopenharmony_ci		res = os_snprintf(pos, end - pos,
4331e5b75505Sopenharmony_ci				  "oper_ssid=%s\n",
4332e5b75505Sopenharmony_ci				  wpa_ssid_txt(dev->oper_ssid,
4333e5b75505Sopenharmony_ci					       dev->oper_ssid_len));
4334e5b75505Sopenharmony_ci		if (os_snprintf_error(end - pos, res))
4335e5b75505Sopenharmony_ci			return pos - buf;
4336e5b75505Sopenharmony_ci		pos += res;
4337e5b75505Sopenharmony_ci	}
4338e5b75505Sopenharmony_ci
4339e5b75505Sopenharmony_ci#ifdef CONFIG_WIFI_DISPLAY
4340e5b75505Sopenharmony_ci	if (dev->info.wfd_subelems) {
4341e5b75505Sopenharmony_ci		res = os_snprintf(pos, end - pos, "wfd_subelems=");
4342e5b75505Sopenharmony_ci		if (os_snprintf_error(end - pos, res))
4343e5b75505Sopenharmony_ci			return pos - buf;
4344e5b75505Sopenharmony_ci		pos += res;
4345e5b75505Sopenharmony_ci
4346e5b75505Sopenharmony_ci		pos += wpa_snprintf_hex(pos, end - pos,
4347e5b75505Sopenharmony_ci					wpabuf_head(dev->info.wfd_subelems),
4348e5b75505Sopenharmony_ci					wpabuf_len(dev->info.wfd_subelems));
4349e5b75505Sopenharmony_ci
4350e5b75505Sopenharmony_ci		res = os_snprintf(pos, end - pos, "\n");
4351e5b75505Sopenharmony_ci		if (os_snprintf_error(end - pos, res))
4352e5b75505Sopenharmony_ci			return pos - buf;
4353e5b75505Sopenharmony_ci		pos += res;
4354e5b75505Sopenharmony_ci	}
4355e5b75505Sopenharmony_ci#endif /* CONFIG_WIFI_DISPLAY */
4356e5b75505Sopenharmony_ci
4357e5b75505Sopenharmony_ci	return pos - buf;
4358e5b75505Sopenharmony_ci}
4359e5b75505Sopenharmony_ci
4360e5b75505Sopenharmony_ci
4361e5b75505Sopenharmony_ciint p2p_peer_known(struct p2p_data *p2p, const u8 *addr)
4362e5b75505Sopenharmony_ci{
4363e5b75505Sopenharmony_ci	return p2p_get_device(p2p, addr) != NULL;
4364e5b75505Sopenharmony_ci}
4365e5b75505Sopenharmony_ci
4366e5b75505Sopenharmony_ci
4367e5b75505Sopenharmony_civoid p2p_set_client_discoverability(struct p2p_data *p2p, int enabled)
4368e5b75505Sopenharmony_ci{
4369e5b75505Sopenharmony_ci	if (enabled) {
4370e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Client discoverability enabled");
4371e5b75505Sopenharmony_ci		p2p->dev_capab |= P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
4372e5b75505Sopenharmony_ci	} else {
4373e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Client discoverability disabled");
4374e5b75505Sopenharmony_ci		p2p->dev_capab &= ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
4375e5b75505Sopenharmony_ci	}
4376e5b75505Sopenharmony_ci}
4377e5b75505Sopenharmony_ci
4378e5b75505Sopenharmony_ci
4379e5b75505Sopenharmony_cistatic struct wpabuf * p2p_build_presence_req(u32 duration1, u32 interval1,
4380e5b75505Sopenharmony_ci					      u32 duration2, u32 interval2)
4381e5b75505Sopenharmony_ci{
4382e5b75505Sopenharmony_ci	struct wpabuf *req;
4383e5b75505Sopenharmony_ci	struct p2p_noa_desc desc1, desc2, *ptr1 = NULL, *ptr2 = NULL;
4384e5b75505Sopenharmony_ci	u8 *len;
4385e5b75505Sopenharmony_ci
4386e5b75505Sopenharmony_ci	req = wpabuf_alloc(100);
4387e5b75505Sopenharmony_ci	if (req == NULL)
4388e5b75505Sopenharmony_ci		return NULL;
4389e5b75505Sopenharmony_ci
4390e5b75505Sopenharmony_ci	if (duration1 || interval1) {
4391e5b75505Sopenharmony_ci		os_memset(&desc1, 0, sizeof(desc1));
4392e5b75505Sopenharmony_ci		desc1.count_type = 1;
4393e5b75505Sopenharmony_ci		desc1.duration = duration1;
4394e5b75505Sopenharmony_ci		desc1.interval = interval1;
4395e5b75505Sopenharmony_ci		ptr1 = &desc1;
4396e5b75505Sopenharmony_ci
4397e5b75505Sopenharmony_ci		if (duration2 || interval2) {
4398e5b75505Sopenharmony_ci			os_memset(&desc2, 0, sizeof(desc2));
4399e5b75505Sopenharmony_ci			desc2.count_type = 2;
4400e5b75505Sopenharmony_ci			desc2.duration = duration2;
4401e5b75505Sopenharmony_ci			desc2.interval = interval2;
4402e5b75505Sopenharmony_ci			ptr2 = &desc2;
4403e5b75505Sopenharmony_ci		}
4404e5b75505Sopenharmony_ci	}
4405e5b75505Sopenharmony_ci
4406e5b75505Sopenharmony_ci	p2p_buf_add_action_hdr(req, P2P_PRESENCE_REQ, 1);
4407e5b75505Sopenharmony_ci	len = p2p_buf_add_ie_hdr(req);
4408e5b75505Sopenharmony_ci	p2p_buf_add_noa(req, 0, 0, 0, ptr1, ptr2);
4409e5b75505Sopenharmony_ci	p2p_buf_update_ie_hdr(req, len);
4410e5b75505Sopenharmony_ci
4411e5b75505Sopenharmony_ci	return req;
4412e5b75505Sopenharmony_ci}
4413e5b75505Sopenharmony_ci
4414e5b75505Sopenharmony_ci
4415e5b75505Sopenharmony_ciint p2p_presence_req(struct p2p_data *p2p, const u8 *go_interface_addr,
4416e5b75505Sopenharmony_ci		     const u8 *own_interface_addr, unsigned int freq,
4417e5b75505Sopenharmony_ci		     u32 duration1, u32 interval1, u32 duration2,
4418e5b75505Sopenharmony_ci		     u32 interval2)
4419e5b75505Sopenharmony_ci{
4420e5b75505Sopenharmony_ci	struct wpabuf *req;
4421e5b75505Sopenharmony_ci
4422e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Send Presence Request to GO " MACSTR
4423e5b75505Sopenharmony_ci		" (own interface " MACSTR ") freq=%u dur1=%u int1=%u "
4424e5b75505Sopenharmony_ci		"dur2=%u int2=%u",
4425e5b75505Sopenharmony_ci		MAC2STR(go_interface_addr), MAC2STR(own_interface_addr),
4426e5b75505Sopenharmony_ci		freq, duration1, interval1, duration2, interval2);
4427e5b75505Sopenharmony_ci
4428e5b75505Sopenharmony_ci	req = p2p_build_presence_req(duration1, interval1, duration2,
4429e5b75505Sopenharmony_ci				     interval2);
4430e5b75505Sopenharmony_ci	if (req == NULL)
4431e5b75505Sopenharmony_ci		return -1;
4432e5b75505Sopenharmony_ci
4433e5b75505Sopenharmony_ci	p2p->pending_action_state = P2P_NO_PENDING_ACTION;
4434e5b75505Sopenharmony_ci	if (p2p_send_action(p2p, freq, go_interface_addr, own_interface_addr,
4435e5b75505Sopenharmony_ci			    go_interface_addr,
4436e5b75505Sopenharmony_ci			    wpabuf_head(req), wpabuf_len(req), 200) < 0) {
4437e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Failed to send Action frame");
4438e5b75505Sopenharmony_ci	}
4439e5b75505Sopenharmony_ci	wpabuf_free(req);
4440e5b75505Sopenharmony_ci
4441e5b75505Sopenharmony_ci	return 0;
4442e5b75505Sopenharmony_ci}
4443e5b75505Sopenharmony_ci
4444e5b75505Sopenharmony_ci
4445e5b75505Sopenharmony_cistatic struct wpabuf * p2p_build_presence_resp(u8 status, const u8 *noa,
4446e5b75505Sopenharmony_ci					       size_t noa_len, u8 dialog_token)
4447e5b75505Sopenharmony_ci{
4448e5b75505Sopenharmony_ci	struct wpabuf *resp;
4449e5b75505Sopenharmony_ci	u8 *len;
4450e5b75505Sopenharmony_ci
4451e5b75505Sopenharmony_ci	resp = wpabuf_alloc(100 + noa_len);
4452e5b75505Sopenharmony_ci	if (resp == NULL)
4453e5b75505Sopenharmony_ci		return NULL;
4454e5b75505Sopenharmony_ci
4455e5b75505Sopenharmony_ci	p2p_buf_add_action_hdr(resp, P2P_PRESENCE_RESP, dialog_token);
4456e5b75505Sopenharmony_ci	len = p2p_buf_add_ie_hdr(resp);
4457e5b75505Sopenharmony_ci	p2p_buf_add_status(resp, status);
4458e5b75505Sopenharmony_ci	if (noa) {
4459e5b75505Sopenharmony_ci		wpabuf_put_u8(resp, P2P_ATTR_NOTICE_OF_ABSENCE);
4460e5b75505Sopenharmony_ci		wpabuf_put_le16(resp, noa_len);
4461e5b75505Sopenharmony_ci		wpabuf_put_data(resp, noa, noa_len);
4462e5b75505Sopenharmony_ci	} else
4463e5b75505Sopenharmony_ci		p2p_buf_add_noa(resp, 0, 0, 0, NULL, NULL);
4464e5b75505Sopenharmony_ci	p2p_buf_update_ie_hdr(resp, len);
4465e5b75505Sopenharmony_ci
4466e5b75505Sopenharmony_ci	return resp;
4467e5b75505Sopenharmony_ci}
4468e5b75505Sopenharmony_ci
4469e5b75505Sopenharmony_ci
4470e5b75505Sopenharmony_cistatic void p2p_process_presence_req(struct p2p_data *p2p, const u8 *da,
4471e5b75505Sopenharmony_ci				     const u8 *sa, const u8 *data, size_t len,
4472e5b75505Sopenharmony_ci				     int rx_freq)
4473e5b75505Sopenharmony_ci{
4474e5b75505Sopenharmony_ci	struct p2p_message msg;
4475e5b75505Sopenharmony_ci	u8 status;
4476e5b75505Sopenharmony_ci	struct wpabuf *resp;
4477e5b75505Sopenharmony_ci	size_t g;
4478e5b75505Sopenharmony_ci	struct p2p_group *group = NULL;
4479e5b75505Sopenharmony_ci	int parsed = 0;
4480e5b75505Sopenharmony_ci	u8 noa[50];
4481e5b75505Sopenharmony_ci	int noa_len;
4482e5b75505Sopenharmony_ci
4483e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Received P2P Action - P2P Presence Request");
4484e5b75505Sopenharmony_ci
4485e5b75505Sopenharmony_ci	for (g = 0; g < p2p->num_groups; g++) {
4486e5b75505Sopenharmony_ci		if (os_memcmp(da, p2p_group_get_interface_addr(p2p->groups[g]),
4487e5b75505Sopenharmony_ci			      ETH_ALEN) == 0) {
4488e5b75505Sopenharmony_ci			group = p2p->groups[g];
4489e5b75505Sopenharmony_ci			break;
4490e5b75505Sopenharmony_ci		}
4491e5b75505Sopenharmony_ci	}
4492e5b75505Sopenharmony_ci	if (group == NULL) {
4493e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Ignore P2P Presence Request for unknown group "
4494e5b75505Sopenharmony_ci			MACSTR, MAC2STR(da));
4495e5b75505Sopenharmony_ci		return;
4496e5b75505Sopenharmony_ci	}
4497e5b75505Sopenharmony_ci
4498e5b75505Sopenharmony_ci	if (p2p_parse(data, len, &msg) < 0) {
4499e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Failed to parse P2P Presence Request");
4500e5b75505Sopenharmony_ci		status = P2P_SC_FAIL_INVALID_PARAMS;
4501e5b75505Sopenharmony_ci		goto fail;
4502e5b75505Sopenharmony_ci	}
4503e5b75505Sopenharmony_ci	parsed = 1;
4504e5b75505Sopenharmony_ci
4505e5b75505Sopenharmony_ci	if (msg.noa == NULL) {
4506e5b75505Sopenharmony_ci		p2p_dbg(p2p, "No NoA attribute in P2P Presence Request");
4507e5b75505Sopenharmony_ci		status = P2P_SC_FAIL_INVALID_PARAMS;
4508e5b75505Sopenharmony_ci		goto fail;
4509e5b75505Sopenharmony_ci	}
4510e5b75505Sopenharmony_ci
4511e5b75505Sopenharmony_ci	status = p2p_group_presence_req(group, sa, msg.noa, msg.noa_len);
4512e5b75505Sopenharmony_ci
4513e5b75505Sopenharmony_cifail:
4514e5b75505Sopenharmony_ci	if (p2p->cfg->get_noa)
4515e5b75505Sopenharmony_ci		noa_len = p2p->cfg->get_noa(p2p->cfg->cb_ctx, da, noa,
4516e5b75505Sopenharmony_ci					    sizeof(noa));
4517e5b75505Sopenharmony_ci	else
4518e5b75505Sopenharmony_ci		noa_len = -1;
4519e5b75505Sopenharmony_ci	resp = p2p_build_presence_resp(status, noa_len > 0 ? noa : NULL,
4520e5b75505Sopenharmony_ci				       noa_len > 0 ? noa_len : 0,
4521e5b75505Sopenharmony_ci				       msg.dialog_token);
4522e5b75505Sopenharmony_ci	if (parsed)
4523e5b75505Sopenharmony_ci		p2p_parse_free(&msg);
4524e5b75505Sopenharmony_ci	if (resp == NULL)
4525e5b75505Sopenharmony_ci		return;
4526e5b75505Sopenharmony_ci
4527e5b75505Sopenharmony_ci	p2p->pending_action_state = P2P_NO_PENDING_ACTION;
4528e5b75505Sopenharmony_ci	if (p2p_send_action(p2p, rx_freq, sa, da, da,
4529e5b75505Sopenharmony_ci			    wpabuf_head(resp), wpabuf_len(resp), 200) < 0) {
4530e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Failed to send Action frame");
4531e5b75505Sopenharmony_ci	}
4532e5b75505Sopenharmony_ci	wpabuf_free(resp);
4533e5b75505Sopenharmony_ci}
4534e5b75505Sopenharmony_ci
4535e5b75505Sopenharmony_ci
4536e5b75505Sopenharmony_cistatic void p2p_process_presence_resp(struct p2p_data *p2p, const u8 *da,
4537e5b75505Sopenharmony_ci				      const u8 *sa, const u8 *data, size_t len)
4538e5b75505Sopenharmony_ci{
4539e5b75505Sopenharmony_ci	struct p2p_message msg;
4540e5b75505Sopenharmony_ci
4541e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Received P2P Action - P2P Presence Response");
4542e5b75505Sopenharmony_ci
4543e5b75505Sopenharmony_ci	if (p2p_parse(data, len, &msg) < 0) {
4544e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Failed to parse P2P Presence Response");
4545e5b75505Sopenharmony_ci		return;
4546e5b75505Sopenharmony_ci	}
4547e5b75505Sopenharmony_ci
4548e5b75505Sopenharmony_ci	if (msg.status == NULL || msg.noa == NULL) {
4549e5b75505Sopenharmony_ci		p2p_dbg(p2p, "No Status or NoA attribute in P2P Presence Response");
4550e5b75505Sopenharmony_ci		p2p_parse_free(&msg);
4551e5b75505Sopenharmony_ci		return;
4552e5b75505Sopenharmony_ci	}
4553e5b75505Sopenharmony_ci
4554e5b75505Sopenharmony_ci	if (p2p->cfg->presence_resp) {
4555e5b75505Sopenharmony_ci		p2p->cfg->presence_resp(p2p->cfg->cb_ctx, sa, *msg.status,
4556e5b75505Sopenharmony_ci					msg.noa, msg.noa_len);
4557e5b75505Sopenharmony_ci	}
4558e5b75505Sopenharmony_ci
4559e5b75505Sopenharmony_ci	if (*msg.status) {
4560e5b75505Sopenharmony_ci		p2p_dbg(p2p, "P2P Presence Request was rejected: status %u",
4561e5b75505Sopenharmony_ci			*msg.status);
4562e5b75505Sopenharmony_ci		p2p_parse_free(&msg);
4563e5b75505Sopenharmony_ci		return;
4564e5b75505Sopenharmony_ci	}
4565e5b75505Sopenharmony_ci
4566e5b75505Sopenharmony_ci	p2p_dbg(p2p, "P2P Presence Request was accepted");
4567e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "P2P: P2P Presence Response - NoA",
4568e5b75505Sopenharmony_ci		    msg.noa, msg.noa_len);
4569e5b75505Sopenharmony_ci	/* TODO: process NoA */
4570e5b75505Sopenharmony_ci	p2p_parse_free(&msg);
4571e5b75505Sopenharmony_ci}
4572e5b75505Sopenharmony_ci
4573e5b75505Sopenharmony_ci
4574e5b75505Sopenharmony_cistatic void p2p_ext_listen_timeout(void *eloop_ctx, void *timeout_ctx)
4575e5b75505Sopenharmony_ci{
4576e5b75505Sopenharmony_ci	struct p2p_data *p2p = eloop_ctx;
4577e5b75505Sopenharmony_ci
4578e5b75505Sopenharmony_ci	if (p2p->ext_listen_interval) {
4579e5b75505Sopenharmony_ci		/* Schedule next extended listen timeout */
4580e5b75505Sopenharmony_ci		eloop_register_timeout(p2p->ext_listen_interval_sec,
4581e5b75505Sopenharmony_ci				       p2p->ext_listen_interval_usec,
4582e5b75505Sopenharmony_ci				       p2p_ext_listen_timeout, p2p, NULL);
4583e5b75505Sopenharmony_ci	}
4584e5b75505Sopenharmony_ci
4585e5b75505Sopenharmony_ci	if ((p2p->cfg->is_p2p_in_progress &&
4586e5b75505Sopenharmony_ci	     p2p->cfg->is_p2p_in_progress(p2p->cfg->cb_ctx)) ||
4587e5b75505Sopenharmony_ci	    (p2p->pending_action_state == P2P_PENDING_PD &&
4588e5b75505Sopenharmony_ci	     p2p->pd_retries > 0)) {
4589e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Operation in progress - skip Extended Listen timeout (%s)",
4590e5b75505Sopenharmony_ci			p2p_state_txt(p2p->state));
4591e5b75505Sopenharmony_ci		return;
4592e5b75505Sopenharmony_ci	}
4593e5b75505Sopenharmony_ci
4594e5b75505Sopenharmony_ci	if (p2p->state == P2P_LISTEN_ONLY && p2p->ext_listen_only) {
4595e5b75505Sopenharmony_ci		/*
4596e5b75505Sopenharmony_ci		 * This should not really happen, but it looks like the Listen
4597e5b75505Sopenharmony_ci		 * command may fail is something else (e.g., a scan) was
4598e5b75505Sopenharmony_ci		 * running at an inconvenient time. As a workaround, allow new
4599e5b75505Sopenharmony_ci		 * Extended Listen operation to be started.
4600e5b75505Sopenharmony_ci		 */
4601e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Previous Extended Listen operation had not been completed - try again");
4602e5b75505Sopenharmony_ci		p2p->ext_listen_only = 0;
4603e5b75505Sopenharmony_ci		p2p_set_state(p2p, P2P_IDLE);
4604e5b75505Sopenharmony_ci	}
4605e5b75505Sopenharmony_ci
4606e5b75505Sopenharmony_ci	if (p2p->state != P2P_IDLE) {
4607e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Skip Extended Listen timeout in active state (%s)", p2p_state_txt(p2p->state));
4608e5b75505Sopenharmony_ci		return;
4609e5b75505Sopenharmony_ci	}
4610e5b75505Sopenharmony_ci
4611e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Extended Listen timeout");
4612e5b75505Sopenharmony_ci	p2p->ext_listen_only = 1;
4613e5b75505Sopenharmony_ci	if (p2p_listen(p2p, p2p->ext_listen_period) < 0) {
4614e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Failed to start Listen state for Extended Listen Timing");
4615e5b75505Sopenharmony_ci		p2p->ext_listen_only = 0;
4616e5b75505Sopenharmony_ci	}
4617e5b75505Sopenharmony_ci}
4618e5b75505Sopenharmony_ci
4619e5b75505Sopenharmony_ci
4620e5b75505Sopenharmony_ciint p2p_ext_listen(struct p2p_data *p2p, unsigned int period,
4621e5b75505Sopenharmony_ci		   unsigned int interval)
4622e5b75505Sopenharmony_ci{
4623e5b75505Sopenharmony_ci	if (period > 65535 || interval > 65535 || period > interval ||
4624e5b75505Sopenharmony_ci	    (period == 0 && interval > 0) || (period > 0 && interval == 0)) {
4625e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Invalid Extended Listen Timing request: period=%u interval=%u",
4626e5b75505Sopenharmony_ci			period, interval);
4627e5b75505Sopenharmony_ci		return -1;
4628e5b75505Sopenharmony_ci	}
4629e5b75505Sopenharmony_ci
4630e5b75505Sopenharmony_ci	eloop_cancel_timeout(p2p_ext_listen_timeout, p2p, NULL);
4631e5b75505Sopenharmony_ci
4632e5b75505Sopenharmony_ci	if (interval == 0) {
4633e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Disabling Extended Listen Timing");
4634e5b75505Sopenharmony_ci		p2p->ext_listen_period = 0;
4635e5b75505Sopenharmony_ci		p2p->ext_listen_interval = 0;
4636e5b75505Sopenharmony_ci		return 0;
4637e5b75505Sopenharmony_ci	}
4638e5b75505Sopenharmony_ci
4639e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Enabling Extended Listen Timing: period %u msec, interval %u msec",
4640e5b75505Sopenharmony_ci		period, interval);
4641e5b75505Sopenharmony_ci	p2p->ext_listen_period = period;
4642e5b75505Sopenharmony_ci	p2p->ext_listen_interval = interval;
4643e5b75505Sopenharmony_ci	p2p->ext_listen_interval_sec = interval / 1000;
4644e5b75505Sopenharmony_ci	p2p->ext_listen_interval_usec = (interval % 1000) * 1000;
4645e5b75505Sopenharmony_ci
4646e5b75505Sopenharmony_ci	eloop_register_timeout(p2p->ext_listen_interval_sec,
4647e5b75505Sopenharmony_ci			       p2p->ext_listen_interval_usec,
4648e5b75505Sopenharmony_ci			       p2p_ext_listen_timeout, p2p, NULL);
4649e5b75505Sopenharmony_ci
4650e5b75505Sopenharmony_ci	return 0;
4651e5b75505Sopenharmony_ci}
4652e5b75505Sopenharmony_ci
4653e5b75505Sopenharmony_ci
4654e5b75505Sopenharmony_civoid p2p_deauth_notif(struct p2p_data *p2p, const u8 *bssid, u16 reason_code,
4655e5b75505Sopenharmony_ci		      const u8 *ie, size_t ie_len)
4656e5b75505Sopenharmony_ci{
4657e5b75505Sopenharmony_ci	struct p2p_message msg;
4658e5b75505Sopenharmony_ci
4659e5b75505Sopenharmony_ci	if (bssid == NULL || ie == NULL)
4660e5b75505Sopenharmony_ci		return;
4661e5b75505Sopenharmony_ci
4662e5b75505Sopenharmony_ci	os_memset(&msg, 0, sizeof(msg));
4663e5b75505Sopenharmony_ci	if (p2p_parse_ies(ie, ie_len, &msg))
4664e5b75505Sopenharmony_ci		return;
4665e5b75505Sopenharmony_ci	if (msg.minor_reason_code == NULL) {
4666e5b75505Sopenharmony_ci		p2p_parse_free(&msg);
4667e5b75505Sopenharmony_ci		return;
4668e5b75505Sopenharmony_ci	}
4669e5b75505Sopenharmony_ci
4670e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Deauthentication notification BSSID " MACSTR
4671e5b75505Sopenharmony_ci		" reason_code=%u minor_reason_code=%u",
4672e5b75505Sopenharmony_ci		MAC2STR(bssid), reason_code, *msg.minor_reason_code);
4673e5b75505Sopenharmony_ci
4674e5b75505Sopenharmony_ci	p2p_parse_free(&msg);
4675e5b75505Sopenharmony_ci}
4676e5b75505Sopenharmony_ci
4677e5b75505Sopenharmony_ci
4678e5b75505Sopenharmony_civoid p2p_disassoc_notif(struct p2p_data *p2p, const u8 *bssid, u16 reason_code,
4679e5b75505Sopenharmony_ci			const u8 *ie, size_t ie_len)
4680e5b75505Sopenharmony_ci{
4681e5b75505Sopenharmony_ci	struct p2p_message msg;
4682e5b75505Sopenharmony_ci
4683e5b75505Sopenharmony_ci	if (bssid == NULL || ie == NULL)
4684e5b75505Sopenharmony_ci		return;
4685e5b75505Sopenharmony_ci
4686e5b75505Sopenharmony_ci	os_memset(&msg, 0, sizeof(msg));
4687e5b75505Sopenharmony_ci	if (p2p_parse_ies(ie, ie_len, &msg))
4688e5b75505Sopenharmony_ci		return;
4689e5b75505Sopenharmony_ci	if (msg.minor_reason_code == NULL) {
4690e5b75505Sopenharmony_ci		p2p_parse_free(&msg);
4691e5b75505Sopenharmony_ci		return;
4692e5b75505Sopenharmony_ci	}
4693e5b75505Sopenharmony_ci
4694e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Disassociation notification BSSID " MACSTR
4695e5b75505Sopenharmony_ci		" reason_code=%u minor_reason_code=%u",
4696e5b75505Sopenharmony_ci		MAC2STR(bssid), reason_code, *msg.minor_reason_code);
4697e5b75505Sopenharmony_ci
4698e5b75505Sopenharmony_ci	p2p_parse_free(&msg);
4699e5b75505Sopenharmony_ci}
4700e5b75505Sopenharmony_ci
4701e5b75505Sopenharmony_ci
4702e5b75505Sopenharmony_civoid p2p_set_managed_oper(struct p2p_data *p2p, int enabled)
4703e5b75505Sopenharmony_ci{
4704e5b75505Sopenharmony_ci	if (enabled) {
4705e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Managed P2P Device operations enabled");
4706e5b75505Sopenharmony_ci		p2p->dev_capab |= P2P_DEV_CAPAB_INFRA_MANAGED;
4707e5b75505Sopenharmony_ci	} else {
4708e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Managed P2P Device operations disabled");
4709e5b75505Sopenharmony_ci		p2p->dev_capab &= ~P2P_DEV_CAPAB_INFRA_MANAGED;
4710e5b75505Sopenharmony_ci	}
4711e5b75505Sopenharmony_ci}
4712e5b75505Sopenharmony_ci
4713e5b75505Sopenharmony_ci
4714e5b75505Sopenharmony_ciint p2p_config_get_random_social(struct p2p_config *p2p, u8 *op_class,
4715e5b75505Sopenharmony_ci				 u8 *op_channel,
4716e5b75505Sopenharmony_ci				 struct wpa_freq_range_list *avoid_list,
4717e5b75505Sopenharmony_ci				 struct wpa_freq_range_list *disallow_list)
4718e5b75505Sopenharmony_ci{
4719e5b75505Sopenharmony_ci	return p2p_channel_random_social(&p2p->channels, op_class, op_channel,
4720e5b75505Sopenharmony_ci					 avoid_list, disallow_list);
4721e5b75505Sopenharmony_ci}
4722e5b75505Sopenharmony_ci
4723e5b75505Sopenharmony_ci
4724e5b75505Sopenharmony_ciint p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel,
4725e5b75505Sopenharmony_ci			   u8 forced)
4726e5b75505Sopenharmony_ci{
4727e5b75505Sopenharmony_ci	if (p2p_channel_to_freq(reg_class, channel) < 0)
4728e5b75505Sopenharmony_ci		return -1;
4729e5b75505Sopenharmony_ci
4730e5b75505Sopenharmony_ci	/*
4731e5b75505Sopenharmony_ci	 * Listen channel was set in configuration or set by control interface;
4732e5b75505Sopenharmony_ci	 * cannot override it.
4733e5b75505Sopenharmony_ci	 */
4734e5b75505Sopenharmony_ci	if (p2p->cfg->channel_forced && forced == 0) {
4735e5b75505Sopenharmony_ci		p2p_dbg(p2p,
4736e5b75505Sopenharmony_ci			"Listen channel was previously configured - do not override based on optimization");
4737e5b75505Sopenharmony_ci		return -1;
4738e5b75505Sopenharmony_ci	}
4739e5b75505Sopenharmony_ci
4740e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Set Listen channel: reg_class %u channel %u",
4741e5b75505Sopenharmony_ci		reg_class, channel);
4742e5b75505Sopenharmony_ci
4743e5b75505Sopenharmony_ci	if (p2p->state == P2P_IDLE) {
4744e5b75505Sopenharmony_ci		p2p->cfg->reg_class = reg_class;
4745e5b75505Sopenharmony_ci		p2p->cfg->channel = channel;
4746e5b75505Sopenharmony_ci		p2p->cfg->channel_forced = forced;
4747e5b75505Sopenharmony_ci	} else {
4748e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Defer setting listen channel");
4749e5b75505Sopenharmony_ci		p2p->pending_reg_class = reg_class;
4750e5b75505Sopenharmony_ci		p2p->pending_channel = channel;
4751e5b75505Sopenharmony_ci		p2p->pending_channel_forced = forced;
4752e5b75505Sopenharmony_ci	}
4753e5b75505Sopenharmony_ci
4754e5b75505Sopenharmony_ci	return 0;
4755e5b75505Sopenharmony_ci}
4756e5b75505Sopenharmony_ci
4757e5b75505Sopenharmony_ci
4758e5b75505Sopenharmony_ciu8 p2p_get_listen_channel(struct p2p_data *p2p)
4759e5b75505Sopenharmony_ci{
4760e5b75505Sopenharmony_ci	return p2p->cfg->channel;
4761e5b75505Sopenharmony_ci}
4762e5b75505Sopenharmony_ci
4763e5b75505Sopenharmony_ci
4764e5b75505Sopenharmony_ciint p2p_set_ssid_postfix(struct p2p_data *p2p, const u8 *postfix, size_t len)
4765e5b75505Sopenharmony_ci{
4766e5b75505Sopenharmony_ci	p2p_dbg(p2p, "New SSID postfix: %s", wpa_ssid_txt(postfix, len));
4767e5b75505Sopenharmony_ci	if (postfix == NULL) {
4768e5b75505Sopenharmony_ci		p2p->cfg->ssid_postfix_len = 0;
4769e5b75505Sopenharmony_ci		return 0;
4770e5b75505Sopenharmony_ci	}
4771e5b75505Sopenharmony_ci	if (len > sizeof(p2p->cfg->ssid_postfix))
4772e5b75505Sopenharmony_ci		return -1;
4773e5b75505Sopenharmony_ci	os_memcpy(p2p->cfg->ssid_postfix, postfix, len);
4774e5b75505Sopenharmony_ci	p2p->cfg->ssid_postfix_len = len;
4775e5b75505Sopenharmony_ci	return 0;
4776e5b75505Sopenharmony_ci}
4777e5b75505Sopenharmony_ci
4778e5b75505Sopenharmony_ci
4779e5b75505Sopenharmony_ciint p2p_set_oper_channel(struct p2p_data *p2p, u8 op_reg_class, u8 op_channel,
4780e5b75505Sopenharmony_ci			 int cfg_op_channel)
4781e5b75505Sopenharmony_ci{
4782e5b75505Sopenharmony_ci	if (p2p_channel_to_freq(op_reg_class, op_channel) < 0)
4783e5b75505Sopenharmony_ci		return -1;
4784e5b75505Sopenharmony_ci
4785e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Set Operating channel: reg_class %u channel %u",
4786e5b75505Sopenharmony_ci		op_reg_class, op_channel);
4787e5b75505Sopenharmony_ci	p2p->cfg->op_reg_class = op_reg_class;
4788e5b75505Sopenharmony_ci	p2p->cfg->op_channel = op_channel;
4789e5b75505Sopenharmony_ci	p2p->cfg->cfg_op_channel = cfg_op_channel;
4790e5b75505Sopenharmony_ci	return 0;
4791e5b75505Sopenharmony_ci}
4792e5b75505Sopenharmony_ci
4793e5b75505Sopenharmony_ci
4794e5b75505Sopenharmony_ciint p2p_set_pref_chan(struct p2p_data *p2p, unsigned int num_pref_chan,
4795e5b75505Sopenharmony_ci		      const struct p2p_channel *pref_chan)
4796e5b75505Sopenharmony_ci{
4797e5b75505Sopenharmony_ci	struct p2p_channel *n;
4798e5b75505Sopenharmony_ci
4799e5b75505Sopenharmony_ci	if (pref_chan) {
4800e5b75505Sopenharmony_ci		n = os_memdup(pref_chan,
4801e5b75505Sopenharmony_ci			      num_pref_chan * sizeof(struct p2p_channel));
4802e5b75505Sopenharmony_ci		if (n == NULL)
4803e5b75505Sopenharmony_ci			return -1;
4804e5b75505Sopenharmony_ci	} else
4805e5b75505Sopenharmony_ci		n = NULL;
4806e5b75505Sopenharmony_ci
4807e5b75505Sopenharmony_ci	os_free(p2p->cfg->pref_chan);
4808e5b75505Sopenharmony_ci	p2p->cfg->pref_chan = n;
4809e5b75505Sopenharmony_ci	p2p->cfg->num_pref_chan = num_pref_chan;
4810e5b75505Sopenharmony_ci
4811e5b75505Sopenharmony_ci	return 0;
4812e5b75505Sopenharmony_ci}
4813e5b75505Sopenharmony_ci
4814e5b75505Sopenharmony_ci
4815e5b75505Sopenharmony_ciint p2p_set_no_go_freq(struct p2p_data *p2p,
4816e5b75505Sopenharmony_ci		       const struct wpa_freq_range_list *list)
4817e5b75505Sopenharmony_ci{
4818e5b75505Sopenharmony_ci	struct wpa_freq_range *tmp;
4819e5b75505Sopenharmony_ci
4820e5b75505Sopenharmony_ci	if (list == NULL || list->num == 0) {
4821e5b75505Sopenharmony_ci		os_free(p2p->no_go_freq.range);
4822e5b75505Sopenharmony_ci		p2p->no_go_freq.range = NULL;
4823e5b75505Sopenharmony_ci		p2p->no_go_freq.num = 0;
4824e5b75505Sopenharmony_ci		return 0;
4825e5b75505Sopenharmony_ci	}
4826e5b75505Sopenharmony_ci
4827e5b75505Sopenharmony_ci	tmp = os_calloc(list->num, sizeof(struct wpa_freq_range));
4828e5b75505Sopenharmony_ci	if (tmp == NULL)
4829e5b75505Sopenharmony_ci		return -1;
4830e5b75505Sopenharmony_ci	os_memcpy(tmp, list->range, list->num * sizeof(struct wpa_freq_range));
4831e5b75505Sopenharmony_ci	os_free(p2p->no_go_freq.range);
4832e5b75505Sopenharmony_ci	p2p->no_go_freq.range = tmp;
4833e5b75505Sopenharmony_ci	p2p->no_go_freq.num = list->num;
4834e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Updated no GO chan list");
4835e5b75505Sopenharmony_ci
4836e5b75505Sopenharmony_ci	return 0;
4837e5b75505Sopenharmony_ci}
4838e5b75505Sopenharmony_ci
4839e5b75505Sopenharmony_ci
4840e5b75505Sopenharmony_ciint p2p_get_interface_addr(struct p2p_data *p2p, const u8 *dev_addr,
4841e5b75505Sopenharmony_ci			   u8 *iface_addr)
4842e5b75505Sopenharmony_ci{
4843e5b75505Sopenharmony_ci	struct p2p_device *dev = p2p_get_device(p2p, dev_addr);
4844e5b75505Sopenharmony_ci	if (dev == NULL || is_zero_ether_addr(dev->interface_addr))
4845e5b75505Sopenharmony_ci		return -1;
4846e5b75505Sopenharmony_ci	os_memcpy(iface_addr, dev->interface_addr, ETH_ALEN);
4847e5b75505Sopenharmony_ci	return 0;
4848e5b75505Sopenharmony_ci}
4849e5b75505Sopenharmony_ci
4850e5b75505Sopenharmony_ci
4851e5b75505Sopenharmony_ciint p2p_get_dev_addr(struct p2p_data *p2p, const u8 *iface_addr,
4852e5b75505Sopenharmony_ci			   u8 *dev_addr)
4853e5b75505Sopenharmony_ci{
4854e5b75505Sopenharmony_ci	struct p2p_device *dev = p2p_get_device_interface(p2p, iface_addr);
4855e5b75505Sopenharmony_ci	if (dev == NULL)
4856e5b75505Sopenharmony_ci		return -1;
4857e5b75505Sopenharmony_ci	os_memcpy(dev_addr, dev->info.p2p_device_addr, ETH_ALEN);
4858e5b75505Sopenharmony_ci	return 0;
4859e5b75505Sopenharmony_ci}
4860e5b75505Sopenharmony_ci
4861e5b75505Sopenharmony_ci
4862e5b75505Sopenharmony_civoid p2p_set_peer_filter(struct p2p_data *p2p, const u8 *addr)
4863e5b75505Sopenharmony_ci{
4864e5b75505Sopenharmony_ci	os_memcpy(p2p->peer_filter, addr, ETH_ALEN);
4865e5b75505Sopenharmony_ci	if (is_zero_ether_addr(p2p->peer_filter))
4866e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Disable peer filter");
4867e5b75505Sopenharmony_ci	else
4868e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Enable peer filter for " MACSTR,
4869e5b75505Sopenharmony_ci			MAC2STR(p2p->peer_filter));
4870e5b75505Sopenharmony_ci}
4871e5b75505Sopenharmony_ci
4872e5b75505Sopenharmony_ci
4873e5b75505Sopenharmony_civoid p2p_set_cross_connect(struct p2p_data *p2p, int enabled)
4874e5b75505Sopenharmony_ci{
4875e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Cross connection %s", enabled ? "enabled" : "disabled");
4876e5b75505Sopenharmony_ci	if (p2p->cross_connect == enabled)
4877e5b75505Sopenharmony_ci		return;
4878e5b75505Sopenharmony_ci	p2p->cross_connect = enabled;
4879e5b75505Sopenharmony_ci	/* TODO: may need to tear down any action group where we are GO(?) */
4880e5b75505Sopenharmony_ci}
4881e5b75505Sopenharmony_ci
4882e5b75505Sopenharmony_ci
4883e5b75505Sopenharmony_ciint p2p_get_oper_freq(struct p2p_data *p2p, const u8 *iface_addr)
4884e5b75505Sopenharmony_ci{
4885e5b75505Sopenharmony_ci	struct p2p_device *dev = p2p_get_device_interface(p2p, iface_addr);
4886e5b75505Sopenharmony_ci	if (dev == NULL)
4887e5b75505Sopenharmony_ci		return -1;
4888e5b75505Sopenharmony_ci	if (dev->oper_freq <= 0)
4889e5b75505Sopenharmony_ci		return -1;
4890e5b75505Sopenharmony_ci	return dev->oper_freq;
4891e5b75505Sopenharmony_ci}
4892e5b75505Sopenharmony_ci
4893e5b75505Sopenharmony_ci
4894e5b75505Sopenharmony_civoid p2p_set_intra_bss_dist(struct p2p_data *p2p, int enabled)
4895e5b75505Sopenharmony_ci{
4896e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Intra BSS distribution %s",
4897e5b75505Sopenharmony_ci		enabled ? "enabled" : "disabled");
4898e5b75505Sopenharmony_ci	p2p->cfg->p2p_intra_bss = enabled;
4899e5b75505Sopenharmony_ci}
4900e5b75505Sopenharmony_ci
4901e5b75505Sopenharmony_ci
4902e5b75505Sopenharmony_civoid p2p_update_channel_list(struct p2p_data *p2p,
4903e5b75505Sopenharmony_ci			     const struct p2p_channels *chan,
4904e5b75505Sopenharmony_ci			     const struct p2p_channels *cli_chan)
4905e5b75505Sopenharmony_ci{
4906e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Update channel list");
4907e5b75505Sopenharmony_ci	os_memcpy(&p2p->cfg->channels, chan, sizeof(struct p2p_channels));
4908e5b75505Sopenharmony_ci	p2p_channels_dump(p2p, "channels", &p2p->cfg->channels);
4909e5b75505Sopenharmony_ci	os_memcpy(&p2p->cfg->cli_channels, cli_chan,
4910e5b75505Sopenharmony_ci		  sizeof(struct p2p_channels));
4911e5b75505Sopenharmony_ci	p2p_channels_dump(p2p, "cli_channels", &p2p->cfg->cli_channels);
4912e5b75505Sopenharmony_ci}
4913e5b75505Sopenharmony_ci
4914e5b75505Sopenharmony_ci
4915e5b75505Sopenharmony_ciint p2p_send_action(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
4916e5b75505Sopenharmony_ci		    const u8 *src, const u8 *bssid, const u8 *buf,
4917e5b75505Sopenharmony_ci		    size_t len, unsigned int wait_time)
4918e5b75505Sopenharmony_ci{
4919e5b75505Sopenharmony_ci	int res, scheduled;
4920e5b75505Sopenharmony_ci
4921e5b75505Sopenharmony_ci	res = p2p->cfg->send_action(p2p->cfg->cb_ctx, freq, dst, src, bssid,
4922e5b75505Sopenharmony_ci				    buf, len, wait_time, &scheduled);
4923e5b75505Sopenharmony_ci	if (res == 0 && scheduled && p2p->in_listen && freq > 0 &&
4924e5b75505Sopenharmony_ci	    (unsigned int) p2p->drv_in_listen != freq) {
4925e5b75505Sopenharmony_ci		p2p_dbg(p2p,
4926e5b75505Sopenharmony_ci			"Stop listen on %d MHz to allow a frame to be sent immediately on %d MHz",
4927e5b75505Sopenharmony_ci			p2p->drv_in_listen, freq);
4928e5b75505Sopenharmony_ci		p2p_stop_listen_for_freq(p2p, freq);
4929e5b75505Sopenharmony_ci	}
4930e5b75505Sopenharmony_ci	return res;
4931e5b75505Sopenharmony_ci}
4932e5b75505Sopenharmony_ci
4933e5b75505Sopenharmony_ci
4934e5b75505Sopenharmony_civoid p2p_set_best_channels(struct p2p_data *p2p, int freq_24, int freq_5,
4935e5b75505Sopenharmony_ci			   int freq_overall)
4936e5b75505Sopenharmony_ci{
4937e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Best channel: 2.4 GHz: %d,  5 GHz: %d,  overall: %d",
4938e5b75505Sopenharmony_ci		freq_24, freq_5, freq_overall);
4939e5b75505Sopenharmony_ci	p2p->best_freq_24 = freq_24;
4940e5b75505Sopenharmony_ci	p2p->best_freq_5 = freq_5;
4941e5b75505Sopenharmony_ci	p2p->best_freq_overall = freq_overall;
4942e5b75505Sopenharmony_ci}
4943e5b75505Sopenharmony_ci
4944e5b75505Sopenharmony_ci
4945e5b75505Sopenharmony_civoid p2p_set_own_freq_preference(struct p2p_data *p2p, int freq)
4946e5b75505Sopenharmony_ci{
4947e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Own frequency preference: %d MHz", freq);
4948e5b75505Sopenharmony_ci	p2p->own_freq_preference = freq;
4949e5b75505Sopenharmony_ci}
4950e5b75505Sopenharmony_ci
4951e5b75505Sopenharmony_ci
4952e5b75505Sopenharmony_ciconst u8 * p2p_get_go_neg_peer(struct p2p_data *p2p)
4953e5b75505Sopenharmony_ci{
4954e5b75505Sopenharmony_ci	if (p2p == NULL || p2p->go_neg_peer == NULL)
4955e5b75505Sopenharmony_ci		return NULL;
4956e5b75505Sopenharmony_ci	return p2p->go_neg_peer->info.p2p_device_addr;
4957e5b75505Sopenharmony_ci}
4958e5b75505Sopenharmony_ci
4959e5b75505Sopenharmony_ci
4960e5b75505Sopenharmony_ciconst struct p2p_peer_info *
4961e5b75505Sopenharmony_cip2p_get_peer_found(struct p2p_data *p2p, const u8 *addr, int next)
4962e5b75505Sopenharmony_ci{
4963e5b75505Sopenharmony_ci	struct p2p_device *dev;
4964e5b75505Sopenharmony_ci
4965e5b75505Sopenharmony_ci	if (addr) {
4966e5b75505Sopenharmony_ci		dev = p2p_get_device(p2p, addr);
4967e5b75505Sopenharmony_ci		if (!dev)
4968e5b75505Sopenharmony_ci			return NULL;
4969e5b75505Sopenharmony_ci
4970e5b75505Sopenharmony_ci		if (!next) {
4971e5b75505Sopenharmony_ci			if (dev->flags & P2P_DEV_PROBE_REQ_ONLY)
4972e5b75505Sopenharmony_ci				return NULL;
4973e5b75505Sopenharmony_ci
4974e5b75505Sopenharmony_ci			return &dev->info;
4975e5b75505Sopenharmony_ci		} else {
4976e5b75505Sopenharmony_ci			do {
4977e5b75505Sopenharmony_ci				dev = dl_list_first(&dev->list,
4978e5b75505Sopenharmony_ci						    struct p2p_device,
4979e5b75505Sopenharmony_ci						    list);
4980e5b75505Sopenharmony_ci				if (!dev || &dev->list == &p2p->devices)
4981e5b75505Sopenharmony_ci					return NULL;
4982e5b75505Sopenharmony_ci			} while (dev->flags & P2P_DEV_PROBE_REQ_ONLY);
4983e5b75505Sopenharmony_ci		}
4984e5b75505Sopenharmony_ci	} else {
4985e5b75505Sopenharmony_ci		dev = dl_list_first(&p2p->devices, struct p2p_device, list);
4986e5b75505Sopenharmony_ci		if (!dev)
4987e5b75505Sopenharmony_ci			return NULL;
4988e5b75505Sopenharmony_ci		while (dev->flags & P2P_DEV_PROBE_REQ_ONLY) {
4989e5b75505Sopenharmony_ci			dev = dl_list_first(&dev->list,
4990e5b75505Sopenharmony_ci					    struct p2p_device,
4991e5b75505Sopenharmony_ci					    list);
4992e5b75505Sopenharmony_ci			if (!dev || &dev->list == &p2p->devices)
4993e5b75505Sopenharmony_ci				return NULL;
4994e5b75505Sopenharmony_ci		}
4995e5b75505Sopenharmony_ci	}
4996e5b75505Sopenharmony_ci
4997e5b75505Sopenharmony_ci	return &dev->info;
4998e5b75505Sopenharmony_ci}
4999e5b75505Sopenharmony_ci
5000e5b75505Sopenharmony_ci
5001e5b75505Sopenharmony_ciint p2p_in_progress(struct p2p_data *p2p)
5002e5b75505Sopenharmony_ci{
5003e5b75505Sopenharmony_ci	if (p2p == NULL)
5004e5b75505Sopenharmony_ci		return 0;
5005e5b75505Sopenharmony_ci	if (p2p->state == P2P_SEARCH)
5006e5b75505Sopenharmony_ci		return 2;
5007e5b75505Sopenharmony_ci	return p2p->state != P2P_IDLE && p2p->state != P2P_PROVISIONING;
5008e5b75505Sopenharmony_ci}
5009e5b75505Sopenharmony_ci
5010e5b75505Sopenharmony_ci
5011e5b75505Sopenharmony_civoid p2p_set_config_timeout(struct p2p_data *p2p, u8 go_timeout,
5012e5b75505Sopenharmony_ci			    u8 client_timeout)
5013e5b75505Sopenharmony_ci{
5014e5b75505Sopenharmony_ci	if (p2p) {
5015e5b75505Sopenharmony_ci		p2p->go_timeout = go_timeout;
5016e5b75505Sopenharmony_ci		p2p->client_timeout = client_timeout;
5017e5b75505Sopenharmony_ci	}
5018e5b75505Sopenharmony_ci}
5019e5b75505Sopenharmony_ci
5020e5b75505Sopenharmony_ci
5021e5b75505Sopenharmony_ci#ifdef CONFIG_WIFI_DISPLAY
5022e5b75505Sopenharmony_ci
5023e5b75505Sopenharmony_cistatic void p2p_update_wfd_ie_groups(struct p2p_data *p2p)
5024e5b75505Sopenharmony_ci{
5025e5b75505Sopenharmony_ci	size_t g;
5026e5b75505Sopenharmony_ci	struct p2p_group *group;
5027e5b75505Sopenharmony_ci
5028e5b75505Sopenharmony_ci	for (g = 0; g < p2p->num_groups; g++) {
5029e5b75505Sopenharmony_ci		group = p2p->groups[g];
5030e5b75505Sopenharmony_ci		p2p_group_force_beacon_update_ies(group);
5031e5b75505Sopenharmony_ci	}
5032e5b75505Sopenharmony_ci}
5033e5b75505Sopenharmony_ci
5034e5b75505Sopenharmony_ci
5035e5b75505Sopenharmony_ciint p2p_set_wfd_ie_beacon(struct p2p_data *p2p, struct wpabuf *ie)
5036e5b75505Sopenharmony_ci{
5037e5b75505Sopenharmony_ci	wpabuf_free(p2p->wfd_ie_beacon);
5038e5b75505Sopenharmony_ci	p2p->wfd_ie_beacon = ie;
5039e5b75505Sopenharmony_ci	p2p_update_wfd_ie_groups(p2p);
5040e5b75505Sopenharmony_ci	return 0;
5041e5b75505Sopenharmony_ci}
5042e5b75505Sopenharmony_ci
5043e5b75505Sopenharmony_ci
5044e5b75505Sopenharmony_ciint p2p_set_wfd_ie_probe_req(struct p2p_data *p2p, struct wpabuf *ie)
5045e5b75505Sopenharmony_ci{
5046e5b75505Sopenharmony_ci	wpabuf_free(p2p->wfd_ie_probe_req);
5047e5b75505Sopenharmony_ci	p2p->wfd_ie_probe_req = ie;
5048e5b75505Sopenharmony_ci	return 0;
5049e5b75505Sopenharmony_ci}
5050e5b75505Sopenharmony_ci
5051e5b75505Sopenharmony_ci
5052e5b75505Sopenharmony_ciint p2p_set_wfd_ie_probe_resp(struct p2p_data *p2p, struct wpabuf *ie)
5053e5b75505Sopenharmony_ci{
5054e5b75505Sopenharmony_ci	wpabuf_free(p2p->wfd_ie_probe_resp);
5055e5b75505Sopenharmony_ci	p2p->wfd_ie_probe_resp = ie;
5056e5b75505Sopenharmony_ci	p2p_update_wfd_ie_groups(p2p);
5057e5b75505Sopenharmony_ci	return 0;
5058e5b75505Sopenharmony_ci}
5059e5b75505Sopenharmony_ci
5060e5b75505Sopenharmony_ci
5061e5b75505Sopenharmony_ciint p2p_set_wfd_ie_assoc_req(struct p2p_data *p2p, struct wpabuf *ie)
5062e5b75505Sopenharmony_ci{
5063e5b75505Sopenharmony_ci	wpabuf_free(p2p->wfd_ie_assoc_req);
5064e5b75505Sopenharmony_ci	p2p->wfd_ie_assoc_req = ie;
5065e5b75505Sopenharmony_ci	return 0;
5066e5b75505Sopenharmony_ci}
5067e5b75505Sopenharmony_ci
5068e5b75505Sopenharmony_ci
5069e5b75505Sopenharmony_ciint p2p_set_wfd_ie_invitation(struct p2p_data *p2p, struct wpabuf *ie)
5070e5b75505Sopenharmony_ci{
5071e5b75505Sopenharmony_ci	wpabuf_free(p2p->wfd_ie_invitation);
5072e5b75505Sopenharmony_ci	p2p->wfd_ie_invitation = ie;
5073e5b75505Sopenharmony_ci	return 0;
5074e5b75505Sopenharmony_ci}
5075e5b75505Sopenharmony_ci
5076e5b75505Sopenharmony_ci
5077e5b75505Sopenharmony_ciint p2p_set_wfd_ie_prov_disc_req(struct p2p_data *p2p, struct wpabuf *ie)
5078e5b75505Sopenharmony_ci{
5079e5b75505Sopenharmony_ci	wpabuf_free(p2p->wfd_ie_prov_disc_req);
5080e5b75505Sopenharmony_ci	p2p->wfd_ie_prov_disc_req = ie;
5081e5b75505Sopenharmony_ci	return 0;
5082e5b75505Sopenharmony_ci}
5083e5b75505Sopenharmony_ci
5084e5b75505Sopenharmony_ci
5085e5b75505Sopenharmony_ciint p2p_set_wfd_ie_prov_disc_resp(struct p2p_data *p2p, struct wpabuf *ie)
5086e5b75505Sopenharmony_ci{
5087e5b75505Sopenharmony_ci	wpabuf_free(p2p->wfd_ie_prov_disc_resp);
5088e5b75505Sopenharmony_ci	p2p->wfd_ie_prov_disc_resp = ie;
5089e5b75505Sopenharmony_ci	return 0;
5090e5b75505Sopenharmony_ci}
5091e5b75505Sopenharmony_ci
5092e5b75505Sopenharmony_ci
5093e5b75505Sopenharmony_ciint p2p_set_wfd_ie_go_neg(struct p2p_data *p2p, struct wpabuf *ie)
5094e5b75505Sopenharmony_ci{
5095e5b75505Sopenharmony_ci	wpabuf_free(p2p->wfd_ie_go_neg);
5096e5b75505Sopenharmony_ci	p2p->wfd_ie_go_neg = ie;
5097e5b75505Sopenharmony_ci	return 0;
5098e5b75505Sopenharmony_ci}
5099e5b75505Sopenharmony_ci
5100e5b75505Sopenharmony_ci
5101e5b75505Sopenharmony_ciint p2p_set_wfd_dev_info(struct p2p_data *p2p, const struct wpabuf *elem)
5102e5b75505Sopenharmony_ci{
5103e5b75505Sopenharmony_ci	wpabuf_free(p2p->wfd_dev_info);
5104e5b75505Sopenharmony_ci	if (elem) {
5105e5b75505Sopenharmony_ci		p2p->wfd_dev_info = wpabuf_dup(elem);
5106e5b75505Sopenharmony_ci		if (p2p->wfd_dev_info == NULL)
5107e5b75505Sopenharmony_ci			return -1;
5108e5b75505Sopenharmony_ci	} else
5109e5b75505Sopenharmony_ci		p2p->wfd_dev_info = NULL;
5110e5b75505Sopenharmony_ci
5111e5b75505Sopenharmony_ci	return 0;
5112e5b75505Sopenharmony_ci}
5113e5b75505Sopenharmony_ci
5114e5b75505Sopenharmony_ci
5115e5b75505Sopenharmony_ciint p2p_set_wfd_r2_dev_info(struct p2p_data *p2p, const struct wpabuf *elem)
5116e5b75505Sopenharmony_ci{
5117e5b75505Sopenharmony_ci	wpabuf_free(p2p->wfd_r2_dev_info);
5118e5b75505Sopenharmony_ci	if (elem) {
5119e5b75505Sopenharmony_ci		p2p->wfd_r2_dev_info = wpabuf_dup(elem);
5120e5b75505Sopenharmony_ci		if (p2p->wfd_r2_dev_info == NULL)
5121e5b75505Sopenharmony_ci			return -1;
5122e5b75505Sopenharmony_ci	} else
5123e5b75505Sopenharmony_ci		p2p->wfd_r2_dev_info = NULL;
5124e5b75505Sopenharmony_ci
5125e5b75505Sopenharmony_ci	return 0;
5126e5b75505Sopenharmony_ci}
5127e5b75505Sopenharmony_ci
5128e5b75505Sopenharmony_ci
5129e5b75505Sopenharmony_ciint p2p_set_wfd_assoc_bssid(struct p2p_data *p2p, const struct wpabuf *elem)
5130e5b75505Sopenharmony_ci{
5131e5b75505Sopenharmony_ci	wpabuf_free(p2p->wfd_assoc_bssid);
5132e5b75505Sopenharmony_ci	if (elem) {
5133e5b75505Sopenharmony_ci		p2p->wfd_assoc_bssid = wpabuf_dup(elem);
5134e5b75505Sopenharmony_ci		if (p2p->wfd_assoc_bssid == NULL)
5135e5b75505Sopenharmony_ci			return -1;
5136e5b75505Sopenharmony_ci	} else
5137e5b75505Sopenharmony_ci		p2p->wfd_assoc_bssid = NULL;
5138e5b75505Sopenharmony_ci
5139e5b75505Sopenharmony_ci	return 0;
5140e5b75505Sopenharmony_ci}
5141e5b75505Sopenharmony_ci
5142e5b75505Sopenharmony_ci
5143e5b75505Sopenharmony_ciint p2p_set_wfd_coupled_sink_info(struct p2p_data *p2p,
5144e5b75505Sopenharmony_ci				  const struct wpabuf *elem)
5145e5b75505Sopenharmony_ci{
5146e5b75505Sopenharmony_ci	wpabuf_free(p2p->wfd_coupled_sink_info);
5147e5b75505Sopenharmony_ci	if (elem) {
5148e5b75505Sopenharmony_ci		p2p->wfd_coupled_sink_info = wpabuf_dup(elem);
5149e5b75505Sopenharmony_ci		if (p2p->wfd_coupled_sink_info == NULL)
5150e5b75505Sopenharmony_ci			return -1;
5151e5b75505Sopenharmony_ci	} else
5152e5b75505Sopenharmony_ci		p2p->wfd_coupled_sink_info = NULL;
5153e5b75505Sopenharmony_ci
5154e5b75505Sopenharmony_ci	return 0;
5155e5b75505Sopenharmony_ci}
5156e5b75505Sopenharmony_ci
5157e5b75505Sopenharmony_ci#endif /* CONFIG_WIFI_DISPLAY */
5158e5b75505Sopenharmony_ci
5159e5b75505Sopenharmony_ci
5160e5b75505Sopenharmony_ciint p2p_set_disc_int(struct p2p_data *p2p, int min_disc_int, int max_disc_int,
5161e5b75505Sopenharmony_ci		     int max_disc_tu)
5162e5b75505Sopenharmony_ci{
5163e5b75505Sopenharmony_ci	if (min_disc_int > max_disc_int || min_disc_int < 0 || max_disc_int < 0)
5164e5b75505Sopenharmony_ci		return -1;
5165e5b75505Sopenharmony_ci
5166e5b75505Sopenharmony_ci	p2p->min_disc_int = min_disc_int;
5167e5b75505Sopenharmony_ci	p2p->max_disc_int = max_disc_int;
5168e5b75505Sopenharmony_ci	p2p->max_disc_tu = max_disc_tu;
5169e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Set discoverable interval: min=%d max=%d max_tu=%d",
5170e5b75505Sopenharmony_ci		min_disc_int, max_disc_int, max_disc_tu);
5171e5b75505Sopenharmony_ci
5172e5b75505Sopenharmony_ci	return 0;
5173e5b75505Sopenharmony_ci}
5174e5b75505Sopenharmony_ci
5175e5b75505Sopenharmony_ci
5176e5b75505Sopenharmony_civoid p2p_dbg(struct p2p_data *p2p, const char *fmt, ...)
5177e5b75505Sopenharmony_ci{
5178e5b75505Sopenharmony_ci	va_list ap;
5179e5b75505Sopenharmony_ci	char buf[500];
5180e5b75505Sopenharmony_ci
5181e5b75505Sopenharmony_ci	if (!p2p->cfg->debug_print)
5182e5b75505Sopenharmony_ci		return;
5183e5b75505Sopenharmony_ci
5184e5b75505Sopenharmony_ci	va_start(ap, fmt);
5185e5b75505Sopenharmony_ci	vsnprintf(buf, sizeof(buf), fmt, ap);
5186e5b75505Sopenharmony_ci	buf[sizeof(buf) - 1] = '\0';
5187e5b75505Sopenharmony_ci	va_end(ap);
5188e5b75505Sopenharmony_ci	p2p->cfg->debug_print(p2p->cfg->cb_ctx, MSG_DEBUG, buf);
5189e5b75505Sopenharmony_ci}
5190e5b75505Sopenharmony_ci
5191e5b75505Sopenharmony_ci
5192e5b75505Sopenharmony_civoid p2p_info(struct p2p_data *p2p, const char *fmt, ...)
5193e5b75505Sopenharmony_ci{
5194e5b75505Sopenharmony_ci	va_list ap;
5195e5b75505Sopenharmony_ci	char buf[500];
5196e5b75505Sopenharmony_ci
5197e5b75505Sopenharmony_ci	if (!p2p->cfg->debug_print)
5198e5b75505Sopenharmony_ci		return;
5199e5b75505Sopenharmony_ci
5200e5b75505Sopenharmony_ci	va_start(ap, fmt);
5201e5b75505Sopenharmony_ci	vsnprintf(buf, sizeof(buf), fmt, ap);
5202e5b75505Sopenharmony_ci	buf[sizeof(buf) - 1] = '\0';
5203e5b75505Sopenharmony_ci	va_end(ap);
5204e5b75505Sopenharmony_ci	p2p->cfg->debug_print(p2p->cfg->cb_ctx, MSG_INFO, buf);
5205e5b75505Sopenharmony_ci}
5206e5b75505Sopenharmony_ci
5207e5b75505Sopenharmony_ci
5208e5b75505Sopenharmony_civoid p2p_err(struct p2p_data *p2p, const char *fmt, ...)
5209e5b75505Sopenharmony_ci{
5210e5b75505Sopenharmony_ci	va_list ap;
5211e5b75505Sopenharmony_ci	char buf[500];
5212e5b75505Sopenharmony_ci
5213e5b75505Sopenharmony_ci	if (!p2p->cfg->debug_print)
5214e5b75505Sopenharmony_ci		return;
5215e5b75505Sopenharmony_ci
5216e5b75505Sopenharmony_ci	va_start(ap, fmt);
5217e5b75505Sopenharmony_ci	vsnprintf(buf, sizeof(buf), fmt, ap);
5218e5b75505Sopenharmony_ci	buf[sizeof(buf) - 1] = '\0';
5219e5b75505Sopenharmony_ci	va_end(ap);
5220e5b75505Sopenharmony_ci	p2p->cfg->debug_print(p2p->cfg->cb_ctx, MSG_ERROR, buf);
5221e5b75505Sopenharmony_ci}
5222e5b75505Sopenharmony_ci
5223e5b75505Sopenharmony_ci
5224e5b75505Sopenharmony_civoid p2p_loop_on_known_peers(struct p2p_data *p2p,
5225e5b75505Sopenharmony_ci			     void (*peer_callback)(struct p2p_peer_info *peer,
5226e5b75505Sopenharmony_ci						   void *user_data),
5227e5b75505Sopenharmony_ci			     void *user_data)
5228e5b75505Sopenharmony_ci{
5229e5b75505Sopenharmony_ci	struct p2p_device *dev, *n;
5230e5b75505Sopenharmony_ci
5231e5b75505Sopenharmony_ci	dl_list_for_each_safe(dev, n, &p2p->devices, struct p2p_device, list) {
5232e5b75505Sopenharmony_ci		peer_callback(&dev->info, user_data);
5233e5b75505Sopenharmony_ci	}
5234e5b75505Sopenharmony_ci}
5235e5b75505Sopenharmony_ci
5236e5b75505Sopenharmony_ci
5237e5b75505Sopenharmony_ci#ifdef CONFIG_WPS_NFC
5238e5b75505Sopenharmony_ci
5239e5b75505Sopenharmony_cistatic struct wpabuf * p2p_build_nfc_handover(struct p2p_data *p2p,
5240e5b75505Sopenharmony_ci					      int client_freq,
5241e5b75505Sopenharmony_ci					      const u8 *go_dev_addr,
5242e5b75505Sopenharmony_ci					      const u8 *ssid, size_t ssid_len)
5243e5b75505Sopenharmony_ci{
5244e5b75505Sopenharmony_ci	struct wpabuf *buf;
5245e5b75505Sopenharmony_ci	u8 op_class, channel;
5246e5b75505Sopenharmony_ci	enum p2p_role_indication role = P2P_DEVICE_NOT_IN_GROUP;
5247e5b75505Sopenharmony_ci
5248e5b75505Sopenharmony_ci	buf = wpabuf_alloc(1000);
5249e5b75505Sopenharmony_ci	if (buf == NULL)
5250e5b75505Sopenharmony_ci		return NULL;
5251e5b75505Sopenharmony_ci
5252e5b75505Sopenharmony_ci	op_class = p2p->cfg->reg_class;
5253e5b75505Sopenharmony_ci	channel = p2p->cfg->channel;
5254e5b75505Sopenharmony_ci
5255e5b75505Sopenharmony_ci	p2p_buf_add_capability(buf, p2p->dev_capab &
5256e5b75505Sopenharmony_ci			       ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, 0);
5257e5b75505Sopenharmony_ci	p2p_buf_add_device_info(buf, p2p, NULL);
5258e5b75505Sopenharmony_ci
5259e5b75505Sopenharmony_ci	if (p2p->num_groups > 0) {
5260e5b75505Sopenharmony_ci		int freq = p2p_group_get_freq(p2p->groups[0]);
5261e5b75505Sopenharmony_ci		role = P2P_GO_IN_A_GROUP;
5262e5b75505Sopenharmony_ci		if (p2p_freq_to_channel(freq, &op_class, &channel) < 0) {
5263e5b75505Sopenharmony_ci			p2p_dbg(p2p,
5264e5b75505Sopenharmony_ci				"Unknown GO operating frequency %d MHz for NFC handover",
5265e5b75505Sopenharmony_ci				freq);
5266e5b75505Sopenharmony_ci			wpabuf_free(buf);
5267e5b75505Sopenharmony_ci			return NULL;
5268e5b75505Sopenharmony_ci		}
5269e5b75505Sopenharmony_ci	} else if (client_freq > 0) {
5270e5b75505Sopenharmony_ci		role = P2P_CLIENT_IN_A_GROUP;
5271e5b75505Sopenharmony_ci		if (p2p_freq_to_channel(client_freq, &op_class, &channel) < 0) {
5272e5b75505Sopenharmony_ci			p2p_dbg(p2p,
5273e5b75505Sopenharmony_ci				"Unknown client operating frequency %d MHz for NFC handover",
5274e5b75505Sopenharmony_ci				client_freq);
5275e5b75505Sopenharmony_ci			wpabuf_free(buf);
5276e5b75505Sopenharmony_ci			return NULL;
5277e5b75505Sopenharmony_ci		}
5278e5b75505Sopenharmony_ci	}
5279e5b75505Sopenharmony_ci
5280e5b75505Sopenharmony_ci	p2p_buf_add_oob_go_neg_channel(buf, p2p->cfg->country, op_class,
5281e5b75505Sopenharmony_ci				       channel, role);
5282e5b75505Sopenharmony_ci
5283e5b75505Sopenharmony_ci	if (p2p->num_groups > 0) {
5284e5b75505Sopenharmony_ci		/* Limit number of clients to avoid very long message */
5285e5b75505Sopenharmony_ci		p2p_buf_add_group_info(p2p->groups[0], buf, 5);
5286e5b75505Sopenharmony_ci		p2p_group_buf_add_id(p2p->groups[0], buf);
5287e5b75505Sopenharmony_ci	} else if (client_freq > 0 &&
5288e5b75505Sopenharmony_ci		   go_dev_addr && !is_zero_ether_addr(go_dev_addr) &&
5289e5b75505Sopenharmony_ci		   ssid && ssid_len > 0) {
5290e5b75505Sopenharmony_ci		/*
5291e5b75505Sopenharmony_ci		 * Add the optional P2P Group ID to indicate in which group this
5292e5b75505Sopenharmony_ci		 * device is a P2P Client.
5293e5b75505Sopenharmony_ci		 */
5294e5b75505Sopenharmony_ci		p2p_buf_add_group_id(buf, go_dev_addr, ssid, ssid_len);
5295e5b75505Sopenharmony_ci	}
5296e5b75505Sopenharmony_ci
5297e5b75505Sopenharmony_ci	return buf;
5298e5b75505Sopenharmony_ci}
5299e5b75505Sopenharmony_ci
5300e5b75505Sopenharmony_ci
5301e5b75505Sopenharmony_cistruct wpabuf * p2p_build_nfc_handover_req(struct p2p_data *p2p,
5302e5b75505Sopenharmony_ci					   int client_freq,
5303e5b75505Sopenharmony_ci					   const u8 *go_dev_addr,
5304e5b75505Sopenharmony_ci					   const u8 *ssid, size_t ssid_len)
5305e5b75505Sopenharmony_ci{
5306e5b75505Sopenharmony_ci	return p2p_build_nfc_handover(p2p, client_freq, go_dev_addr, ssid,
5307e5b75505Sopenharmony_ci				      ssid_len);
5308e5b75505Sopenharmony_ci}
5309e5b75505Sopenharmony_ci
5310e5b75505Sopenharmony_ci
5311e5b75505Sopenharmony_cistruct wpabuf * p2p_build_nfc_handover_sel(struct p2p_data *p2p,
5312e5b75505Sopenharmony_ci					   int client_freq,
5313e5b75505Sopenharmony_ci					   const u8 *go_dev_addr,
5314e5b75505Sopenharmony_ci					   const u8 *ssid, size_t ssid_len)
5315e5b75505Sopenharmony_ci{
5316e5b75505Sopenharmony_ci	return p2p_build_nfc_handover(p2p, client_freq, go_dev_addr, ssid,
5317e5b75505Sopenharmony_ci				      ssid_len);
5318e5b75505Sopenharmony_ci}
5319e5b75505Sopenharmony_ci
5320e5b75505Sopenharmony_ci
5321e5b75505Sopenharmony_ciint p2p_process_nfc_connection_handover(struct p2p_data *p2p,
5322e5b75505Sopenharmony_ci					struct p2p_nfc_params *params)
5323e5b75505Sopenharmony_ci{
5324e5b75505Sopenharmony_ci	struct p2p_message msg;
5325e5b75505Sopenharmony_ci	struct p2p_device *dev;
5326e5b75505Sopenharmony_ci	const u8 *p2p_dev_addr;
5327e5b75505Sopenharmony_ci	int freq;
5328e5b75505Sopenharmony_ci	enum p2p_role_indication role;
5329e5b75505Sopenharmony_ci
5330e5b75505Sopenharmony_ci	params->next_step = NO_ACTION;
5331e5b75505Sopenharmony_ci
5332e5b75505Sopenharmony_ci	if (p2p_parse_ies_separate(params->wsc_attr, params->wsc_len,
5333e5b75505Sopenharmony_ci				   params->p2p_attr, params->p2p_len, &msg)) {
5334e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Failed to parse WSC/P2P attributes from NFC");
5335e5b75505Sopenharmony_ci		p2p_parse_free(&msg);
5336e5b75505Sopenharmony_ci		return -1;
5337e5b75505Sopenharmony_ci	}
5338e5b75505Sopenharmony_ci
5339e5b75505Sopenharmony_ci	if (msg.p2p_device_addr)
5340e5b75505Sopenharmony_ci		p2p_dev_addr = msg.p2p_device_addr;
5341e5b75505Sopenharmony_ci	else if (msg.device_id)
5342e5b75505Sopenharmony_ci		p2p_dev_addr = msg.device_id;
5343e5b75505Sopenharmony_ci	else {
5344e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Ignore scan data without P2P Device Info or P2P Device Id");
5345e5b75505Sopenharmony_ci		p2p_parse_free(&msg);
5346e5b75505Sopenharmony_ci		return -1;
5347e5b75505Sopenharmony_ci	}
5348e5b75505Sopenharmony_ci
5349e5b75505Sopenharmony_ci	if (msg.oob_dev_password) {
5350e5b75505Sopenharmony_ci		os_memcpy(params->oob_dev_pw, msg.oob_dev_password,
5351e5b75505Sopenharmony_ci			  msg.oob_dev_password_len);
5352e5b75505Sopenharmony_ci		params->oob_dev_pw_len = msg.oob_dev_password_len;
5353e5b75505Sopenharmony_ci	}
5354e5b75505Sopenharmony_ci
5355e5b75505Sopenharmony_ci	dev = p2p_create_device(p2p, p2p_dev_addr);
5356e5b75505Sopenharmony_ci	if (dev == NULL) {
5357e5b75505Sopenharmony_ci		p2p_parse_free(&msg);
5358e5b75505Sopenharmony_ci		return -1;
5359e5b75505Sopenharmony_ci	}
5360e5b75505Sopenharmony_ci
5361e5b75505Sopenharmony_ci	params->peer = &dev->info;
5362e5b75505Sopenharmony_ci
5363e5b75505Sopenharmony_ci	os_get_reltime(&dev->last_seen);
5364e5b75505Sopenharmony_ci	dev->flags &= ~(P2P_DEV_PROBE_REQ_ONLY | P2P_DEV_GROUP_CLIENT_ONLY);
5365e5b75505Sopenharmony_ci	p2p_copy_wps_info(p2p, dev, 0, &msg);
5366e5b75505Sopenharmony_ci
5367e5b75505Sopenharmony_ci	if (!msg.oob_go_neg_channel) {
5368e5b75505Sopenharmony_ci		p2p_dbg(p2p, "OOB GO Negotiation Channel attribute not included");
5369e5b75505Sopenharmony_ci		p2p_parse_free(&msg);
5370e5b75505Sopenharmony_ci		return -1;
5371e5b75505Sopenharmony_ci	}
5372e5b75505Sopenharmony_ci
5373e5b75505Sopenharmony_ci	if (msg.oob_go_neg_channel[3] == 0 &&
5374e5b75505Sopenharmony_ci	    msg.oob_go_neg_channel[4] == 0)
5375e5b75505Sopenharmony_ci		freq = 0;
5376e5b75505Sopenharmony_ci	else
5377e5b75505Sopenharmony_ci		freq = p2p_channel_to_freq(msg.oob_go_neg_channel[3],
5378e5b75505Sopenharmony_ci					   msg.oob_go_neg_channel[4]);
5379e5b75505Sopenharmony_ci	if (freq < 0) {
5380e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Unknown peer OOB GO Neg channel");
5381e5b75505Sopenharmony_ci		p2p_parse_free(&msg);
5382e5b75505Sopenharmony_ci		return -1;
5383e5b75505Sopenharmony_ci	}
5384e5b75505Sopenharmony_ci	role = msg.oob_go_neg_channel[5];
5385e5b75505Sopenharmony_ci
5386e5b75505Sopenharmony_ci	if (role == P2P_GO_IN_A_GROUP) {
5387e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Peer OOB GO operating channel: %u MHz", freq);
5388e5b75505Sopenharmony_ci		params->go_freq = freq;
5389e5b75505Sopenharmony_ci	} else if (role == P2P_CLIENT_IN_A_GROUP) {
5390e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Peer (client) OOB GO operating channel: %u MHz",
5391e5b75505Sopenharmony_ci			freq);
5392e5b75505Sopenharmony_ci		params->go_freq = freq;
5393e5b75505Sopenharmony_ci	} else
5394e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Peer OOB GO Neg channel: %u MHz", freq);
5395e5b75505Sopenharmony_ci	dev->oob_go_neg_freq = freq;
5396e5b75505Sopenharmony_ci
5397e5b75505Sopenharmony_ci	if (!params->sel && role != P2P_GO_IN_A_GROUP) {
5398e5b75505Sopenharmony_ci		freq = p2p_channel_to_freq(p2p->cfg->reg_class,
5399e5b75505Sopenharmony_ci					   p2p->cfg->channel);
5400e5b75505Sopenharmony_ci		if (freq < 0) {
5401e5b75505Sopenharmony_ci			p2p_dbg(p2p, "Own listen channel not known");
5402e5b75505Sopenharmony_ci			p2p_parse_free(&msg);
5403e5b75505Sopenharmony_ci			return -1;
5404e5b75505Sopenharmony_ci		}
5405e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Use own Listen channel as OOB GO Neg channel: %u MHz", freq);
5406e5b75505Sopenharmony_ci		dev->oob_go_neg_freq = freq;
5407e5b75505Sopenharmony_ci	}
5408e5b75505Sopenharmony_ci
5409e5b75505Sopenharmony_ci	if (msg.group_id) {
5410e5b75505Sopenharmony_ci		os_memcpy(params->go_dev_addr, msg.group_id, ETH_ALEN);
5411e5b75505Sopenharmony_ci		params->go_ssid_len = msg.group_id_len - ETH_ALEN;
5412e5b75505Sopenharmony_ci		os_memcpy(params->go_ssid, msg.group_id + ETH_ALEN,
5413e5b75505Sopenharmony_ci			  params->go_ssid_len);
5414e5b75505Sopenharmony_ci	}
5415e5b75505Sopenharmony_ci
5416e5b75505Sopenharmony_ci	if (dev->flags & P2P_DEV_USER_REJECTED) {
5417e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Do not report rejected device");
5418e5b75505Sopenharmony_ci		p2p_parse_free(&msg);
5419e5b75505Sopenharmony_ci		return 0;
5420e5b75505Sopenharmony_ci	}
5421e5b75505Sopenharmony_ci
5422e5b75505Sopenharmony_ci	if (!(dev->flags & P2P_DEV_REPORTED)) {
5423e5b75505Sopenharmony_ci		p2p->cfg->dev_found(p2p->cfg->cb_ctx, p2p_dev_addr, &dev->info,
5424e5b75505Sopenharmony_ci				    !(dev->flags & P2P_DEV_REPORTED_ONCE));
5425e5b75505Sopenharmony_ci		dev->flags |= P2P_DEV_REPORTED | P2P_DEV_REPORTED_ONCE;
5426e5b75505Sopenharmony_ci	}
5427e5b75505Sopenharmony_ci	p2p_parse_free(&msg);
5428e5b75505Sopenharmony_ci
5429e5b75505Sopenharmony_ci	if (role == P2P_GO_IN_A_GROUP && p2p->num_groups > 0)
5430e5b75505Sopenharmony_ci		params->next_step = BOTH_GO;
5431e5b75505Sopenharmony_ci	else if (role == P2P_GO_IN_A_GROUP)
5432e5b75505Sopenharmony_ci		params->next_step = JOIN_GROUP;
5433e5b75505Sopenharmony_ci	else if (role == P2P_CLIENT_IN_A_GROUP) {
5434e5b75505Sopenharmony_ci		dev->flags |= P2P_DEV_GROUP_CLIENT_ONLY;
5435e5b75505Sopenharmony_ci		params->next_step = PEER_CLIENT;
5436e5b75505Sopenharmony_ci	} else if (p2p->num_groups > 0)
5437e5b75505Sopenharmony_ci		params->next_step = AUTH_JOIN;
5438e5b75505Sopenharmony_ci	else if (params->sel)
5439e5b75505Sopenharmony_ci		params->next_step = INIT_GO_NEG;
5440e5b75505Sopenharmony_ci	else
5441e5b75505Sopenharmony_ci		params->next_step = RESP_GO_NEG;
5442e5b75505Sopenharmony_ci
5443e5b75505Sopenharmony_ci	return 0;
5444e5b75505Sopenharmony_ci}
5445e5b75505Sopenharmony_ci
5446e5b75505Sopenharmony_ci
5447e5b75505Sopenharmony_civoid p2p_set_authorized_oob_dev_pw_id(struct p2p_data *p2p, u16 dev_pw_id,
5448e5b75505Sopenharmony_ci				      int go_intent,
5449e5b75505Sopenharmony_ci				      const u8 *own_interface_addr)
5450e5b75505Sopenharmony_ci{
5451e5b75505Sopenharmony_ci
5452e5b75505Sopenharmony_ci	p2p->authorized_oob_dev_pw_id = dev_pw_id;
5453e5b75505Sopenharmony_ci	if (dev_pw_id == 0) {
5454e5b75505Sopenharmony_ci		p2p_dbg(p2p, "NFC OOB Password unauthorized for static handover");
5455e5b75505Sopenharmony_ci		return;
5456e5b75505Sopenharmony_ci	}
5457e5b75505Sopenharmony_ci
5458e5b75505Sopenharmony_ci	p2p_dbg(p2p, "NFC OOB Password (id=%u) authorized for static handover",
5459e5b75505Sopenharmony_ci		dev_pw_id);
5460e5b75505Sopenharmony_ci
5461e5b75505Sopenharmony_ci	p2p->go_intent = go_intent;
5462e5b75505Sopenharmony_ci	os_memcpy(p2p->intended_addr, own_interface_addr, ETH_ALEN);
5463e5b75505Sopenharmony_ci}
5464e5b75505Sopenharmony_ci
5465e5b75505Sopenharmony_ci#endif /* CONFIG_WPS_NFC */
5466e5b75505Sopenharmony_ci
5467e5b75505Sopenharmony_ci
5468e5b75505Sopenharmony_ciint p2p_set_passphrase_len(struct p2p_data *p2p, unsigned int len)
5469e5b75505Sopenharmony_ci{
5470e5b75505Sopenharmony_ci	if (len < 8 || len > 63)
5471e5b75505Sopenharmony_ci		return -1;
5472e5b75505Sopenharmony_ci	p2p->cfg->passphrase_len = len;
5473e5b75505Sopenharmony_ci	return 0;
5474e5b75505Sopenharmony_ci}
5475e5b75505Sopenharmony_ci
5476e5b75505Sopenharmony_ci
5477e5b75505Sopenharmony_civoid p2p_set_vendor_elems(struct p2p_data *p2p, struct wpabuf **vendor_elem)
5478e5b75505Sopenharmony_ci{
5479e5b75505Sopenharmony_ci	p2p->vendor_elem = vendor_elem;
5480e5b75505Sopenharmony_ci}
5481e5b75505Sopenharmony_ci
5482e5b75505Sopenharmony_ci
5483e5b75505Sopenharmony_civoid p2p_go_neg_wait_timeout(void *eloop_ctx, void *timeout_ctx)
5484e5b75505Sopenharmony_ci{
5485e5b75505Sopenharmony_ci	struct p2p_data *p2p = eloop_ctx;
5486e5b75505Sopenharmony_ci
5487e5b75505Sopenharmony_ci	p2p_dbg(p2p,
5488e5b75505Sopenharmony_ci		"Timeout on waiting peer to become ready for GO Negotiation");
5489e5b75505Sopenharmony_ci	p2p_go_neg_failed(p2p, -1);
5490e5b75505Sopenharmony_ci}
5491e5b75505Sopenharmony_ci
5492e5b75505Sopenharmony_ci
5493e5b75505Sopenharmony_civoid p2p_set_own_pref_freq_list(struct p2p_data *p2p,
5494e5b75505Sopenharmony_ci				const unsigned int *pref_freq_list,
5495e5b75505Sopenharmony_ci				unsigned int size)
5496e5b75505Sopenharmony_ci{
5497e5b75505Sopenharmony_ci	unsigned int i;
5498e5b75505Sopenharmony_ci
5499e5b75505Sopenharmony_ci	if (size > P2P_MAX_PREF_CHANNELS)
5500e5b75505Sopenharmony_ci		size = P2P_MAX_PREF_CHANNELS;
5501e5b75505Sopenharmony_ci	p2p->num_pref_freq = size;
5502e5b75505Sopenharmony_ci	for (i = 0; i < size; i++) {
5503e5b75505Sopenharmony_ci		p2p->pref_freq_list[i] = pref_freq_list[i];
5504e5b75505Sopenharmony_ci		p2p_dbg(p2p, "Own preferred frequency list[%u]=%u MHz",
5505e5b75505Sopenharmony_ci			i, p2p->pref_freq_list[i]);
5506e5b75505Sopenharmony_ci	}
5507e5b75505Sopenharmony_ci}
5508e5b75505Sopenharmony_ci
5509e5b75505Sopenharmony_ci
5510e5b75505Sopenharmony_civoid p2p_set_override_pref_op_chan(struct p2p_data *p2p, u8 op_class,
5511e5b75505Sopenharmony_ci				   u8 chan)
5512e5b75505Sopenharmony_ci{
5513e5b75505Sopenharmony_ci	p2p->override_pref_op_class = op_class;
5514e5b75505Sopenharmony_ci	p2p->override_pref_channel = chan;
5515e5b75505Sopenharmony_ci}
5516e5b75505Sopenharmony_ci
5517e5b75505Sopenharmony_ci
5518e5b75505Sopenharmony_cistruct wpabuf * p2p_build_probe_resp_template(struct p2p_data *p2p,
5519e5b75505Sopenharmony_ci					      unsigned int freq)
5520e5b75505Sopenharmony_ci{
5521e5b75505Sopenharmony_ci	struct wpabuf *ies, *buf;
5522e5b75505Sopenharmony_ci	u8 addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
5523e5b75505Sopenharmony_ci	int ret;
5524e5b75505Sopenharmony_ci
5525e5b75505Sopenharmony_ci	ies = p2p_build_probe_resp_ies(p2p, NULL, 0);
5526e5b75505Sopenharmony_ci	if (!ies) {
5527e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR,
5528e5b75505Sopenharmony_ci			   "CTRL: Failed to build Probe Response IEs");
5529e5b75505Sopenharmony_ci		return NULL;
5530e5b75505Sopenharmony_ci	}
5531e5b75505Sopenharmony_ci
5532e5b75505Sopenharmony_ci	buf = wpabuf_alloc(200 + wpabuf_len(ies));
5533e5b75505Sopenharmony_ci	if (!buf) {
5534e5b75505Sopenharmony_ci		wpabuf_free(ies);
5535e5b75505Sopenharmony_ci		return NULL;
5536e5b75505Sopenharmony_ci	}
5537e5b75505Sopenharmony_ci
5538e5b75505Sopenharmony_ci	ret = p2p_build_probe_resp_buf(p2p, buf, ies, addr, freq);
5539e5b75505Sopenharmony_ci	wpabuf_free(ies);
5540e5b75505Sopenharmony_ci	if (ret) {
5541e5b75505Sopenharmony_ci		wpabuf_free(buf);
5542e5b75505Sopenharmony_ci		return NULL;
5543e5b75505Sopenharmony_ci	}
5544e5b75505Sopenharmony_ci
5545e5b75505Sopenharmony_ci	return buf;
5546e5b75505Sopenharmony_ci}
5547