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