xref: /freebsd/contrib/wpa/src/p2p/p2p_invitation.c (revision a90b9d0159070121c221b966469c3e36d912bf82)
1f05cddf9SRui Paulo /*
2f05cddf9SRui Paulo  * Wi-Fi Direct - P2P Invitation procedure
3f05cddf9SRui Paulo  * Copyright (c) 2010, Atheros Communications
4f05cddf9SRui Paulo  *
5f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo  * See README for more details.
7f05cddf9SRui Paulo  */
8f05cddf9SRui Paulo 
9f05cddf9SRui Paulo #include "includes.h"
10f05cddf9SRui Paulo 
11f05cddf9SRui Paulo #include "common.h"
12f05cddf9SRui Paulo #include "common/ieee802_11_defs.h"
135b9c547cSRui Paulo #include "common/wpa_ctrl.h"
14f05cddf9SRui Paulo #include "p2p_i.h"
15f05cddf9SRui Paulo #include "p2p.h"
16f05cddf9SRui Paulo 
17f05cddf9SRui Paulo 
p2p_build_invitation_req(struct p2p_data * p2p,struct p2p_device * peer,const u8 * go_dev_addr,int dev_pw_id)18f05cddf9SRui Paulo static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p,
19f05cddf9SRui Paulo 						struct p2p_device *peer,
205b9c547cSRui Paulo 						const u8 *go_dev_addr,
215b9c547cSRui Paulo 						int dev_pw_id)
22f05cddf9SRui Paulo {
23f05cddf9SRui Paulo 	struct wpabuf *buf;
24f05cddf9SRui Paulo 	u8 *len;
25f05cddf9SRui Paulo 	const u8 *dev_addr;
26f05cddf9SRui Paulo 	size_t extra = 0;
27*a90b9d01SCy Schubert 	bool is_6ghz_capab;
28f05cddf9SRui Paulo 
29f05cddf9SRui Paulo #ifdef CONFIG_WIFI_DISPLAY
30f05cddf9SRui Paulo 	struct wpabuf *wfd_ie = p2p->wfd_ie_invitation;
31f05cddf9SRui Paulo 	if (wfd_ie && p2p->inv_role == P2P_INVITE_ROLE_ACTIVE_GO) {
32f05cddf9SRui Paulo 		size_t i;
33f05cddf9SRui Paulo 		for (i = 0; i < p2p->num_groups; i++) {
34f05cddf9SRui Paulo 			struct p2p_group *g = p2p->groups[i];
35f05cddf9SRui Paulo 			struct wpabuf *ie;
36*a90b9d01SCy Schubert 			if (!ether_addr_equal(p2p_group_get_interface_addr(g),
37*a90b9d01SCy Schubert 					      p2p->inv_bssid))
38f05cddf9SRui Paulo 				continue;
39f05cddf9SRui Paulo 			ie = p2p_group_get_wfd_ie(g);
40f05cddf9SRui Paulo 			if (ie) {
41f05cddf9SRui Paulo 				wfd_ie = ie;
42f05cddf9SRui Paulo 				break;
43f05cddf9SRui Paulo 			}
44f05cddf9SRui Paulo 		}
45f05cddf9SRui Paulo 	}
46f05cddf9SRui Paulo 	if (wfd_ie)
47f05cddf9SRui Paulo 		extra = wpabuf_len(wfd_ie);
48f05cddf9SRui Paulo #endif /* CONFIG_WIFI_DISPLAY */
49f05cddf9SRui Paulo 
505b9c547cSRui Paulo 	if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_INV_REQ])
515b9c547cSRui Paulo 		extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_INV_REQ]);
525b9c547cSRui Paulo 
53f05cddf9SRui Paulo 	buf = wpabuf_alloc(1000 + extra);
54f05cddf9SRui Paulo 	if (buf == NULL)
55f05cddf9SRui Paulo 		return NULL;
56f05cddf9SRui Paulo 
57f05cddf9SRui Paulo 	peer->dialog_token++;
58f05cddf9SRui Paulo 	if (peer->dialog_token == 0)
59f05cddf9SRui Paulo 		peer->dialog_token = 1;
60f05cddf9SRui Paulo 	p2p_buf_add_public_action_hdr(buf, P2P_INVITATION_REQ,
61f05cddf9SRui Paulo 				      peer->dialog_token);
62f05cddf9SRui Paulo 
63f05cddf9SRui Paulo 	len = p2p_buf_add_ie_hdr(buf);
64f05cddf9SRui Paulo 	if (p2p->inv_role == P2P_INVITE_ROLE_ACTIVE_GO || !p2p->inv_persistent)
65f05cddf9SRui Paulo 		p2p_buf_add_config_timeout(buf, 0, 0);
66f05cddf9SRui Paulo 	else
67f05cddf9SRui Paulo 		p2p_buf_add_config_timeout(buf, p2p->go_timeout,
68f05cddf9SRui Paulo 					   p2p->client_timeout);
69f05cddf9SRui Paulo 	p2p_buf_add_invitation_flags(buf, p2p->inv_persistent ?
70f05cddf9SRui Paulo 				     P2P_INVITATION_FLAGS_TYPE : 0);
715b9c547cSRui Paulo 	if (p2p->inv_role != P2P_INVITE_ROLE_CLIENT ||
725b9c547cSRui Paulo 	    !(peer->flags & P2P_DEV_NO_PREF_CHAN))
73f05cddf9SRui Paulo 		p2p_buf_add_operating_channel(buf, p2p->cfg->country,
745b9c547cSRui Paulo 					      p2p->op_reg_class,
755b9c547cSRui Paulo 					      p2p->op_channel);
76f05cddf9SRui Paulo 	if (p2p->inv_bssid_set)
77f05cddf9SRui Paulo 		p2p_buf_add_group_bssid(buf, p2p->inv_bssid);
78*a90b9d01SCy Schubert 	is_6ghz_capab = is_p2p_6ghz_capable(p2p) &&
79*a90b9d01SCy Schubert 		p2p_is_peer_6ghz_capab(p2p, peer->info.p2p_device_addr);
80*a90b9d01SCy Schubert 	p2p_buf_add_channel_list(buf, p2p->cfg->country, &p2p->channels,
81*a90b9d01SCy Schubert 				 is_6ghz_capab);
82f05cddf9SRui Paulo 	if (go_dev_addr)
83f05cddf9SRui Paulo 		dev_addr = go_dev_addr;
84f05cddf9SRui Paulo 	else if (p2p->inv_role == P2P_INVITE_ROLE_CLIENT)
85f05cddf9SRui Paulo 		dev_addr = peer->info.p2p_device_addr;
86f05cddf9SRui Paulo 	else
87f05cddf9SRui Paulo 		dev_addr = p2p->cfg->dev_addr;
88f05cddf9SRui Paulo 	p2p_buf_add_group_id(buf, dev_addr, p2p->inv_ssid, p2p->inv_ssid_len);
89f05cddf9SRui Paulo 	p2p_buf_add_device_info(buf, p2p, peer);
90f05cddf9SRui Paulo 	p2p_buf_update_ie_hdr(buf, len);
91f05cddf9SRui Paulo 
92325151a3SRui Paulo 	p2p_buf_add_pref_channel_list(buf, p2p->pref_freq_list,
93325151a3SRui Paulo 				      p2p->num_pref_freq);
94325151a3SRui Paulo 
95f05cddf9SRui Paulo #ifdef CONFIG_WIFI_DISPLAY
96f05cddf9SRui Paulo 	if (wfd_ie)
97f05cddf9SRui Paulo 		wpabuf_put_buf(buf, wfd_ie);
98f05cddf9SRui Paulo #endif /* CONFIG_WIFI_DISPLAY */
99f05cddf9SRui Paulo 
1005b9c547cSRui Paulo 	if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_INV_REQ])
1015b9c547cSRui Paulo 		wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_INV_REQ]);
1025b9c547cSRui Paulo 
1035b9c547cSRui Paulo 	if (dev_pw_id >= 0) {
1045b9c547cSRui Paulo 		/* WSC IE in Invitation Request for NFC static handover */
1055b9c547cSRui Paulo 		p2p_build_wps_ie(p2p, buf, dev_pw_id, 0);
1065b9c547cSRui Paulo 	}
1075b9c547cSRui Paulo 
108f05cddf9SRui Paulo 	return buf;
109f05cddf9SRui Paulo }
110f05cddf9SRui Paulo 
111f05cddf9SRui Paulo 
p2p_build_invitation_resp(struct p2p_data * p2p,struct p2p_device * peer,u8 dialog_token,u8 status,const u8 * group_bssid,u8 reg_class,u8 channel,struct p2p_channels * channels)112f05cddf9SRui Paulo static struct wpabuf * p2p_build_invitation_resp(struct p2p_data *p2p,
113f05cddf9SRui Paulo 						 struct p2p_device *peer,
114f05cddf9SRui Paulo 						 u8 dialog_token, u8 status,
115f05cddf9SRui Paulo 						 const u8 *group_bssid,
116f05cddf9SRui Paulo 						 u8 reg_class, u8 channel,
117f05cddf9SRui Paulo 						 struct p2p_channels *channels)
118f05cddf9SRui Paulo {
119f05cddf9SRui Paulo 	struct wpabuf *buf;
120f05cddf9SRui Paulo 	u8 *len;
121f05cddf9SRui Paulo 	size_t extra = 0;
122f05cddf9SRui Paulo 
123f05cddf9SRui Paulo #ifdef CONFIG_WIFI_DISPLAY
124f05cddf9SRui Paulo 	struct wpabuf *wfd_ie = p2p->wfd_ie_invitation;
125f05cddf9SRui Paulo 	if (wfd_ie && group_bssid) {
126f05cddf9SRui Paulo 		size_t i;
127f05cddf9SRui Paulo 		for (i = 0; i < p2p->num_groups; i++) {
128f05cddf9SRui Paulo 			struct p2p_group *g = p2p->groups[i];
129f05cddf9SRui Paulo 			struct wpabuf *ie;
130*a90b9d01SCy Schubert 			if (!ether_addr_equal(p2p_group_get_interface_addr(g),
131*a90b9d01SCy Schubert 					      group_bssid))
132f05cddf9SRui Paulo 				continue;
133f05cddf9SRui Paulo 			ie = p2p_group_get_wfd_ie(g);
134f05cddf9SRui Paulo 			if (ie) {
135f05cddf9SRui Paulo 				wfd_ie = ie;
136f05cddf9SRui Paulo 				break;
137f05cddf9SRui Paulo 			}
138f05cddf9SRui Paulo 		}
139f05cddf9SRui Paulo 	}
140f05cddf9SRui Paulo 	if (wfd_ie)
141f05cddf9SRui Paulo 		extra = wpabuf_len(wfd_ie);
142f05cddf9SRui Paulo #endif /* CONFIG_WIFI_DISPLAY */
143f05cddf9SRui Paulo 
144325151a3SRui Paulo 	if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_INV_RESP])
145325151a3SRui Paulo 		extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_INV_RESP]);
146325151a3SRui Paulo 
147f05cddf9SRui Paulo 	buf = wpabuf_alloc(1000 + extra);
148f05cddf9SRui Paulo 	if (buf == NULL)
149f05cddf9SRui Paulo 		return NULL;
150f05cddf9SRui Paulo 
151f05cddf9SRui Paulo 	p2p_buf_add_public_action_hdr(buf, P2P_INVITATION_RESP,
152f05cddf9SRui Paulo 				      dialog_token);
153f05cddf9SRui Paulo 
154f05cddf9SRui Paulo 	len = p2p_buf_add_ie_hdr(buf);
155f05cddf9SRui Paulo 	p2p_buf_add_status(buf, status);
156f05cddf9SRui Paulo 	p2p_buf_add_config_timeout(buf, 0, 0); /* FIX */
157f05cddf9SRui Paulo 	if (reg_class && channel)
158f05cddf9SRui Paulo 		p2p_buf_add_operating_channel(buf, p2p->cfg->country,
159f05cddf9SRui Paulo 					      reg_class, channel);
160f05cddf9SRui Paulo 	if (group_bssid)
161f05cddf9SRui Paulo 		p2p_buf_add_group_bssid(buf, group_bssid);
162*a90b9d01SCy Schubert 	if (channels) {
163*a90b9d01SCy Schubert 		bool is_6ghz_capab;
164*a90b9d01SCy Schubert 
165*a90b9d01SCy Schubert 		is_6ghz_capab = is_p2p_6ghz_capable(p2p) &&
166*a90b9d01SCy Schubert 			p2p_is_peer_6ghz_capab(p2p, peer->info.p2p_device_addr);
167*a90b9d01SCy Schubert 		p2p_buf_add_channel_list(buf, p2p->cfg->country, channels,
168*a90b9d01SCy Schubert 					 is_6ghz_capab);
169*a90b9d01SCy Schubert 	}
170f05cddf9SRui Paulo 	p2p_buf_update_ie_hdr(buf, len);
171f05cddf9SRui Paulo 
172f05cddf9SRui Paulo #ifdef CONFIG_WIFI_DISPLAY
173f05cddf9SRui Paulo 	if (wfd_ie)
174f05cddf9SRui Paulo 		wpabuf_put_buf(buf, wfd_ie);
175f05cddf9SRui Paulo #endif /* CONFIG_WIFI_DISPLAY */
176f05cddf9SRui Paulo 
177325151a3SRui Paulo 	if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_INV_RESP])
178325151a3SRui Paulo 		wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_INV_RESP]);
179325151a3SRui Paulo 
180f05cddf9SRui Paulo 	return buf;
181f05cddf9SRui Paulo }
182f05cddf9SRui Paulo 
183f05cddf9SRui Paulo 
p2p_process_invitation_req(struct p2p_data * p2p,const u8 * sa,const u8 * data,size_t len,int rx_freq)184f05cddf9SRui Paulo void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
185f05cddf9SRui Paulo 				const u8 *data, size_t len, int rx_freq)
186f05cddf9SRui Paulo {
187f05cddf9SRui Paulo 	struct p2p_device *dev;
188f05cddf9SRui Paulo 	struct p2p_message msg;
189f05cddf9SRui Paulo 	struct wpabuf *resp = NULL;
190f05cddf9SRui Paulo 	u8 status = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
191f05cddf9SRui Paulo 	int freq;
192f05cddf9SRui Paulo 	int go = 0;
193f05cddf9SRui Paulo 	u8 group_bssid[ETH_ALEN], *bssid;
194f05cddf9SRui Paulo 	int op_freq = 0;
195f05cddf9SRui Paulo 	u8 reg_class = 0, channel = 0;
1965b9c547cSRui Paulo 	struct p2p_channels all_channels, intersection, *channels = NULL;
197f05cddf9SRui Paulo 	int persistent;
198f05cddf9SRui Paulo 
199f05cddf9SRui Paulo 	os_memset(group_bssid, 0, sizeof(group_bssid));
200f05cddf9SRui Paulo 
2015b9c547cSRui Paulo 	p2p_dbg(p2p, "Received Invitation Request from " MACSTR " (freq=%d)",
202f05cddf9SRui Paulo 		MAC2STR(sa), rx_freq);
203f05cddf9SRui Paulo 
204f05cddf9SRui Paulo 	if (p2p_parse(data, len, &msg))
205f05cddf9SRui Paulo 		return;
206f05cddf9SRui Paulo 
207f05cddf9SRui Paulo 	dev = p2p_get_device(p2p, sa);
208f05cddf9SRui Paulo 	if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
2095b9c547cSRui Paulo 		p2p_dbg(p2p, "Invitation Request from unknown peer " MACSTR,
2105b9c547cSRui Paulo 			MAC2STR(sa));
211f05cddf9SRui Paulo 
2125b9c547cSRui Paulo 		if (p2p_add_device(p2p, sa, rx_freq, NULL, 0, data + 1, len - 1,
213f05cddf9SRui Paulo 				   0)) {
2145b9c547cSRui Paulo 			p2p_dbg(p2p, "Invitation Request add device failed "
215f05cddf9SRui Paulo 				MACSTR, MAC2STR(sa));
216f05cddf9SRui Paulo 			status = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
217f05cddf9SRui Paulo 			goto fail;
218f05cddf9SRui Paulo 		}
219f05cddf9SRui Paulo 
220f05cddf9SRui Paulo 		dev = p2p_get_device(p2p, sa);
221f05cddf9SRui Paulo 		if (dev == NULL) {
2225b9c547cSRui Paulo 			p2p_dbg(p2p, "Reject Invitation Request from unknown peer "
2235b9c547cSRui Paulo 				MACSTR, MAC2STR(sa));
224f05cddf9SRui Paulo 			status = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
225f05cddf9SRui Paulo 			goto fail;
226f05cddf9SRui Paulo 		}
227f05cddf9SRui Paulo 	}
228f05cddf9SRui Paulo 
229f05cddf9SRui Paulo 	if (!msg.group_id || !msg.channel_list) {
2305b9c547cSRui Paulo 		p2p_dbg(p2p, "Mandatory attribute missing in Invitation Request from "
2315b9c547cSRui Paulo 			MACSTR, MAC2STR(sa));
232f05cddf9SRui Paulo 		status = P2P_SC_FAIL_INVALID_PARAMS;
233f05cddf9SRui Paulo 		goto fail;
234f05cddf9SRui Paulo 	}
235f05cddf9SRui Paulo 
236f05cddf9SRui Paulo 	if (msg.invitation_flags)
237f05cddf9SRui Paulo 		persistent = *msg.invitation_flags & P2P_INVITATION_FLAGS_TYPE;
238f05cddf9SRui Paulo 	else {
239f05cddf9SRui Paulo 		/* Invitation Flags is a mandatory attribute starting from P2P
240f05cddf9SRui Paulo 		 * spec 1.06. As a backwards compatibility mechanism, assume
241f05cddf9SRui Paulo 		 * the request was for a persistent group if the attribute is
242f05cddf9SRui Paulo 		 * missing.
243f05cddf9SRui Paulo 		 */
2445b9c547cSRui Paulo 		p2p_dbg(p2p, "Mandatory Invitation Flags attribute missing from Invitation Request");
245f05cddf9SRui Paulo 		persistent = 1;
246f05cddf9SRui Paulo 	}
247f05cddf9SRui Paulo 
2485b9c547cSRui Paulo 	p2p_channels_union(&p2p->cfg->channels, &p2p->cfg->cli_channels,
2495b9c547cSRui Paulo 			   &all_channels);
2505b9c547cSRui Paulo 
2515b9c547cSRui Paulo 	if (p2p_peer_channels_check(p2p, &all_channels, dev,
252f05cddf9SRui Paulo 				    msg.channel_list, msg.channel_list_len) <
253f05cddf9SRui Paulo 	    0) {
2545b9c547cSRui Paulo 		p2p_dbg(p2p, "No common channels found");
255f05cddf9SRui Paulo 		status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
256f05cddf9SRui Paulo 		goto fail;
257f05cddf9SRui Paulo 	}
258f05cddf9SRui Paulo 
2595b9c547cSRui Paulo 	p2p_channels_dump(p2p, "own channels", &p2p->cfg->channels);
2605b9c547cSRui Paulo 	p2p_channels_dump(p2p, "own client channels", &all_channels);
2615b9c547cSRui Paulo 	p2p_channels_dump(p2p, "peer channels", &dev->channels);
2625b9c547cSRui Paulo 	p2p_channels_intersect(&all_channels, &dev->channels,
2635b9c547cSRui Paulo 			       &intersection);
2645b9c547cSRui Paulo 	p2p_channels_dump(p2p, "intersection", &intersection);
2655b9c547cSRui Paulo 
266f05cddf9SRui Paulo 	if (p2p->cfg->invitation_process) {
267f05cddf9SRui Paulo 		status = p2p->cfg->invitation_process(
268f05cddf9SRui Paulo 			p2p->cfg->cb_ctx, sa, msg.group_bssid, msg.group_id,
269f05cddf9SRui Paulo 			msg.group_id + ETH_ALEN, msg.group_id_len - ETH_ALEN,
2705b9c547cSRui Paulo 			&go, group_bssid, &op_freq, persistent, &intersection,
2715b9c547cSRui Paulo 			msg.dev_password_id_present ? msg.dev_password_id : -1);
2725b9c547cSRui Paulo 	}
2735b9c547cSRui Paulo 
2745b9c547cSRui Paulo 	if (go) {
2755b9c547cSRui Paulo 		p2p_channels_intersect(&p2p->cfg->channels, &dev->channels,
2765b9c547cSRui Paulo 				       &intersection);
2775b9c547cSRui Paulo 		p2p_channels_dump(p2p, "intersection(GO)", &intersection);
2785b9c547cSRui Paulo 		if (intersection.reg_classes == 0) {
2795b9c547cSRui Paulo 			p2p_dbg(p2p, "No common channels found (GO)");
2805b9c547cSRui Paulo 			status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
2815b9c547cSRui Paulo 			goto fail;
2825b9c547cSRui Paulo 		}
283f05cddf9SRui Paulo 	}
284f05cddf9SRui Paulo 
285f05cddf9SRui Paulo 	if (op_freq) {
2865b9c547cSRui Paulo 		p2p_dbg(p2p, "Invitation processing forced frequency %d MHz",
2875b9c547cSRui Paulo 			op_freq);
2885b9c547cSRui Paulo 		if (p2p_freq_to_channel(op_freq, &reg_class, &channel) < 0) {
2895b9c547cSRui Paulo 			p2p_dbg(p2p, "Unknown forced freq %d MHz from invitation_process()",
2905b9c547cSRui Paulo 				op_freq);
291f05cddf9SRui Paulo 			status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
292f05cddf9SRui Paulo 			goto fail;
293f05cddf9SRui Paulo 		}
294f05cddf9SRui Paulo 
295f05cddf9SRui Paulo 		if (!p2p_channels_includes(&intersection, reg_class, channel))
296f05cddf9SRui Paulo 		{
297780fb4a2SCy Schubert 			p2p_dbg(p2p, "forced freq %d MHz not in the supported channels intersection",
2985b9c547cSRui Paulo 				op_freq);
299f05cddf9SRui Paulo 			status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
300f05cddf9SRui Paulo 			goto fail;
301f05cddf9SRui Paulo 		}
302f05cddf9SRui Paulo 
303f05cddf9SRui Paulo 		if (status == P2P_SC_SUCCESS)
304f05cddf9SRui Paulo 			channels = &intersection;
305f05cddf9SRui Paulo 	} else {
3065b9c547cSRui Paulo 		p2p_dbg(p2p, "No forced channel from invitation processing - figure out best one to use");
307f05cddf9SRui Paulo 
308f05cddf9SRui Paulo 		/* Default to own configuration as a starting point */
309f05cddf9SRui Paulo 		p2p->op_reg_class = p2p->cfg->op_reg_class;
310f05cddf9SRui Paulo 		p2p->op_channel = p2p->cfg->op_channel;
3115b9c547cSRui Paulo 		p2p_dbg(p2p, "Own default op_class %d channel %d",
312f05cddf9SRui Paulo 			p2p->op_reg_class, p2p->op_channel);
313f05cddf9SRui Paulo 
314f05cddf9SRui Paulo 		/* Use peer preference if specified and compatible */
315f05cddf9SRui Paulo 		if (msg.operating_channel) {
316f05cddf9SRui Paulo 			int req_freq;
317f05cddf9SRui Paulo 			req_freq = p2p_channel_to_freq(
318f05cddf9SRui Paulo 				msg.operating_channel[3],
319f05cddf9SRui Paulo 				msg.operating_channel[4]);
3205b9c547cSRui Paulo 			p2p_dbg(p2p, "Peer operating channel preference: %d MHz",
321f05cddf9SRui Paulo 				req_freq);
322f05cddf9SRui Paulo 			if (req_freq > 0 &&
323f05cddf9SRui Paulo 			    p2p_channels_includes(&intersection,
324f05cddf9SRui Paulo 						  msg.operating_channel[3],
325f05cddf9SRui Paulo 						  msg.operating_channel[4])) {
326f05cddf9SRui Paulo 				p2p->op_reg_class = msg.operating_channel[3];
327f05cddf9SRui Paulo 				p2p->op_channel = msg.operating_channel[4];
3285b9c547cSRui Paulo 				p2p_dbg(p2p, "Use peer preference op_class %d channel %d",
329f05cddf9SRui Paulo 					p2p->op_reg_class, p2p->op_channel);
330f05cddf9SRui Paulo 			} else {
3315b9c547cSRui Paulo 				p2p_dbg(p2p, "Cannot use peer channel preference");
332f05cddf9SRui Paulo 			}
333f05cddf9SRui Paulo 		}
334f05cddf9SRui Paulo 
3355b9c547cSRui Paulo 		/* Reselect the channel only for the case of the GO */
3365b9c547cSRui Paulo 		if (go &&
3375b9c547cSRui Paulo 		    !p2p_channels_includes(&intersection, p2p->op_reg_class,
338f05cddf9SRui Paulo 					   p2p->op_channel)) {
3395b9c547cSRui Paulo 			p2p_dbg(p2p, "Initially selected channel (op_class %d channel %d) not in channel intersection - try to reselect",
340f05cddf9SRui Paulo 				p2p->op_reg_class, p2p->op_channel);
341f05cddf9SRui Paulo 			p2p_reselect_channel(p2p, &intersection);
3425b9c547cSRui Paulo 			p2p_dbg(p2p, "Re-selection result: op_class %d channel %d",
343f05cddf9SRui Paulo 				p2p->op_reg_class, p2p->op_channel);
344f05cddf9SRui Paulo 			if (!p2p_channels_includes(&intersection,
345f05cddf9SRui Paulo 						   p2p->op_reg_class,
346f05cddf9SRui Paulo 						   p2p->op_channel)) {
3475b9c547cSRui Paulo 				p2p_dbg(p2p, "Peer does not support selected operating channel (reg_class=%u channel=%u)",
348f05cddf9SRui Paulo 					p2p->op_reg_class, p2p->op_channel);
349f05cddf9SRui Paulo 				status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
350f05cddf9SRui Paulo 				goto fail;
351f05cddf9SRui Paulo 			}
3525b9c547cSRui Paulo 		} else if (go && !(dev->flags & P2P_DEV_FORCE_FREQ) &&
3535b9c547cSRui Paulo 			   !p2p->cfg->cfg_op_channel) {
3545b9c547cSRui Paulo 			p2p_dbg(p2p, "Try to reselect channel selection with peer information received; previously selected op_class %u channel %u",
3555b9c547cSRui Paulo 				p2p->op_reg_class, p2p->op_channel);
3565b9c547cSRui Paulo 			p2p_reselect_channel(p2p, &intersection);
357f05cddf9SRui Paulo 		}
358f05cddf9SRui Paulo 
359325151a3SRui Paulo 		/*
360325151a3SRui Paulo 		 * Use the driver preferred frequency list extension if
361325151a3SRui Paulo 		 * supported.
362325151a3SRui Paulo 		 */
363325151a3SRui Paulo 		p2p_check_pref_chan(p2p, go, dev, &msg);
364325151a3SRui Paulo 
3655b9c547cSRui Paulo 		op_freq = p2p_channel_to_freq(p2p->op_reg_class,
366f05cddf9SRui Paulo 					      p2p->op_channel);
367f05cddf9SRui Paulo 		if (op_freq < 0) {
3685b9c547cSRui Paulo 			p2p_dbg(p2p, "Unknown operational channel (country=%c%c reg_class=%u channel=%u)",
369f05cddf9SRui Paulo 				p2p->cfg->country[0], p2p->cfg->country[1],
370f05cddf9SRui Paulo 				p2p->op_reg_class, p2p->op_channel);
371f05cddf9SRui Paulo 			status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
372f05cddf9SRui Paulo 			goto fail;
373f05cddf9SRui Paulo 		}
3745b9c547cSRui Paulo 		p2p_dbg(p2p, "Selected operating channel - %d MHz", op_freq);
375f05cddf9SRui Paulo 
376f05cddf9SRui Paulo 		if (status == P2P_SC_SUCCESS) {
377f05cddf9SRui Paulo 			reg_class = p2p->op_reg_class;
378f05cddf9SRui Paulo 			channel = p2p->op_channel;
379f05cddf9SRui Paulo 			channels = &intersection;
380f05cddf9SRui Paulo 		}
381f05cddf9SRui Paulo 	}
382f05cddf9SRui Paulo 
383f05cddf9SRui Paulo fail:
384f05cddf9SRui Paulo 	if (go && status == P2P_SC_SUCCESS && !is_zero_ether_addr(group_bssid))
385f05cddf9SRui Paulo 		bssid = group_bssid;
386f05cddf9SRui Paulo 	else
387f05cddf9SRui Paulo 		bssid = NULL;
388f05cddf9SRui Paulo 	resp = p2p_build_invitation_resp(p2p, dev, msg.dialog_token, status,
389f05cddf9SRui Paulo 					 bssid, reg_class, channel, channels);
390f05cddf9SRui Paulo 
391f05cddf9SRui Paulo 	if (resp == NULL)
392f05cddf9SRui Paulo 		goto out;
393f05cddf9SRui Paulo 
394f05cddf9SRui Paulo 	if (rx_freq > 0)
395f05cddf9SRui Paulo 		freq = rx_freq;
396f05cddf9SRui Paulo 	else
3975b9c547cSRui Paulo 		freq = p2p_channel_to_freq(p2p->cfg->reg_class,
398f05cddf9SRui Paulo 					   p2p->cfg->channel);
399f05cddf9SRui Paulo 	if (freq < 0) {
4005b9c547cSRui Paulo 		p2p_dbg(p2p, "Unknown regulatory class/channel");
401f05cddf9SRui Paulo 		goto out;
402f05cddf9SRui Paulo 	}
403f05cddf9SRui Paulo 
404f05cddf9SRui Paulo 	/*
405f05cddf9SRui Paulo 	 * Store copy of invitation data to be used when processing TX status
406f05cddf9SRui Paulo 	 * callback for the Acton frame.
407f05cddf9SRui Paulo 	 */
408f05cddf9SRui Paulo 	os_memcpy(p2p->inv_sa, sa, ETH_ALEN);
409f05cddf9SRui Paulo 	if (msg.group_bssid) {
410f05cddf9SRui Paulo 		os_memcpy(p2p->inv_group_bssid, msg.group_bssid, ETH_ALEN);
411f05cddf9SRui Paulo 		p2p->inv_group_bssid_ptr = p2p->inv_group_bssid;
412f05cddf9SRui Paulo 	} else
413f05cddf9SRui Paulo 		p2p->inv_group_bssid_ptr = NULL;
4145b9c547cSRui Paulo 	if (msg.group_id) {
415325151a3SRui Paulo 		if (msg.group_id_len - ETH_ALEN <= SSID_MAX_LEN) {
416f05cddf9SRui Paulo 			os_memcpy(p2p->inv_ssid, msg.group_id + ETH_ALEN,
417f05cddf9SRui Paulo 				  msg.group_id_len - ETH_ALEN);
418f05cddf9SRui Paulo 			p2p->inv_ssid_len = msg.group_id_len - ETH_ALEN;
419f05cddf9SRui Paulo 		}
420f05cddf9SRui Paulo 		os_memcpy(p2p->inv_go_dev_addr, msg.group_id, ETH_ALEN);
4215b9c547cSRui Paulo 	} else {
4225b9c547cSRui Paulo 		p2p->inv_ssid_len = 0;
4235b9c547cSRui Paulo 		os_memset(p2p->inv_go_dev_addr, 0, ETH_ALEN);
4245b9c547cSRui Paulo 	}
425f05cddf9SRui Paulo 	p2p->inv_status = status;
426f05cddf9SRui Paulo 	p2p->inv_op_freq = op_freq;
427f05cddf9SRui Paulo 
428f05cddf9SRui Paulo 	p2p->pending_action_state = P2P_PENDING_INVITATION_RESPONSE;
429f05cddf9SRui Paulo 	if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr,
430f05cddf9SRui Paulo 			    p2p->cfg->dev_addr,
431780fb4a2SCy Schubert 			    wpabuf_head(resp), wpabuf_len(resp), 50) < 0) {
4325b9c547cSRui Paulo 		p2p_dbg(p2p, "Failed to send Action frame");
433f05cddf9SRui Paulo 	}
434f05cddf9SRui Paulo 
435f05cddf9SRui Paulo out:
436f05cddf9SRui Paulo 	wpabuf_free(resp);
437f05cddf9SRui Paulo 	p2p_parse_free(&msg);
438f05cddf9SRui Paulo }
439f05cddf9SRui Paulo 
440f05cddf9SRui Paulo 
p2p_process_invitation_resp(struct p2p_data * p2p,const u8 * sa,const u8 * data,size_t len)441f05cddf9SRui Paulo void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa,
442f05cddf9SRui Paulo 				 const u8 *data, size_t len)
443f05cddf9SRui Paulo {
444f05cddf9SRui Paulo 	struct p2p_device *dev;
445f05cddf9SRui Paulo 	struct p2p_message msg;
4465b9c547cSRui Paulo 	struct p2p_channels intersection, *channels = NULL;
447f05cddf9SRui Paulo 
4485b9c547cSRui Paulo 	p2p_dbg(p2p, "Received Invitation Response from " MACSTR,
449f05cddf9SRui Paulo 		MAC2STR(sa));
450f05cddf9SRui Paulo 
451f05cddf9SRui Paulo 	dev = p2p_get_device(p2p, sa);
452f05cddf9SRui Paulo 	if (dev == NULL) {
4535b9c547cSRui Paulo 		p2p_dbg(p2p, "Ignore Invitation Response from unknown peer "
454f05cddf9SRui Paulo 			MACSTR, MAC2STR(sa));
4555b9c547cSRui Paulo 		p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
456f05cddf9SRui Paulo 		return;
457f05cddf9SRui Paulo 	}
458f05cddf9SRui Paulo 
459f05cddf9SRui Paulo 	if (dev != p2p->invite_peer) {
4605b9c547cSRui Paulo 		p2p_dbg(p2p, "Ignore unexpected Invitation Response from peer "
461f05cddf9SRui Paulo 			MACSTR, MAC2STR(sa));
4625b9c547cSRui Paulo 		p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
463f05cddf9SRui Paulo 		return;
464f05cddf9SRui Paulo 	}
465f05cddf9SRui Paulo 
4665b9c547cSRui Paulo 	if (p2p_parse(data, len, &msg)) {
4675b9c547cSRui Paulo 		p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
468f05cddf9SRui Paulo 		return;
4695b9c547cSRui Paulo 	}
470f05cddf9SRui Paulo 
471f05cddf9SRui Paulo 	if (!msg.status) {
4725b9c547cSRui Paulo 		p2p_dbg(p2p, "Mandatory Status attribute missing in Invitation Response from "
4735b9c547cSRui Paulo 			MACSTR, MAC2STR(sa));
4745b9c547cSRui Paulo 		p2p_parse_free(&msg);
4755b9c547cSRui Paulo 		p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
4765b9c547cSRui Paulo 		return;
4775b9c547cSRui Paulo 	}
4785b9c547cSRui Paulo 
4795b9c547cSRui Paulo 	/*
4805b9c547cSRui Paulo 	 * We should not really receive a replayed response twice since
4815b9c547cSRui Paulo 	 * duplicate frames are supposed to be dropped. However, not all drivers
4825b9c547cSRui Paulo 	 * do that for pre-association frames. We did not use to verify dialog
4835b9c547cSRui Paulo 	 * token matches for invitation response frames, but that check can be
4845b9c547cSRui Paulo 	 * safely used to drop a replayed response to the previous Invitation
4855b9c547cSRui Paulo 	 * Request in case the suggested operating channel was changed. This
4865b9c547cSRui Paulo 	 * allows a duplicated reject frame to be dropped with the assumption
4875b9c547cSRui Paulo 	 * that the real response follows after it.
4885b9c547cSRui Paulo 	 */
4895b9c547cSRui Paulo 	if (*msg.status == P2P_SC_FAIL_NO_COMMON_CHANNELS &&
4905b9c547cSRui Paulo 	    p2p->retry_invite_req_sent &&
4915b9c547cSRui Paulo 	    msg.dialog_token != dev->dialog_token) {
4925b9c547cSRui Paulo 		p2p_dbg(p2p, "Unexpected Dialog Token %u (expected %u)",
4935b9c547cSRui Paulo 			msg.dialog_token, dev->dialog_token);
494f05cddf9SRui Paulo 		p2p_parse_free(&msg);
495f05cddf9SRui Paulo 		return;
496f05cddf9SRui Paulo 	}
497f05cddf9SRui Paulo 
4985b9c547cSRui Paulo 	if (*msg.status == P2P_SC_FAIL_NO_COMMON_CHANNELS &&
4995b9c547cSRui Paulo 	    p2p->retry_invite_req &&
5005b9c547cSRui Paulo 	    p2p_channel_random_social(&p2p->cfg->channels, &p2p->op_reg_class,
5014bc52338SCy Schubert 				      &p2p->op_channel, NULL, NULL) == 0) {
5025b9c547cSRui Paulo 		p2p->retry_invite_req = 0;
5035b9c547cSRui Paulo 		p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
5045b9c547cSRui Paulo 		p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
5055b9c547cSRui Paulo 		p2p_set_state(p2p, P2P_INVITE);
5065b9c547cSRui Paulo 		p2p_dbg(p2p, "Resend Invitation Request setting op_class %u channel %u as operating channel",
5075b9c547cSRui Paulo 			p2p->op_reg_class, p2p->op_channel);
5085b9c547cSRui Paulo 		p2p->retry_invite_req_sent = 1;
5095b9c547cSRui Paulo 		p2p_invite_send(p2p, p2p->invite_peer, p2p->invite_go_dev_addr,
5105b9c547cSRui Paulo 				p2p->invite_dev_pw_id);
5115b9c547cSRui Paulo 		p2p_parse_free(&msg);
5125b9c547cSRui Paulo 		return;
5135b9c547cSRui Paulo 	}
5145b9c547cSRui Paulo 	p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
5155b9c547cSRui Paulo 	p2p->retry_invite_req = 0;
5165b9c547cSRui Paulo 
5175b9c547cSRui Paulo 	if (!msg.channel_list && *msg.status == P2P_SC_SUCCESS) {
5185b9c547cSRui Paulo 		p2p_dbg(p2p, "Mandatory Channel List attribute missing in Invitation Response from "
5195b9c547cSRui Paulo 			MACSTR, MAC2STR(sa));
5205b9c547cSRui Paulo #ifdef CONFIG_P2P_STRICT
5215b9c547cSRui Paulo 		p2p_parse_free(&msg);
5225b9c547cSRui Paulo 		return;
5235b9c547cSRui Paulo #endif /* CONFIG_P2P_STRICT */
5245b9c547cSRui Paulo 		/* Try to survive without peer channel list */
5255b9c547cSRui Paulo 		channels = &p2p->channels;
5265b9c547cSRui Paulo 	} else if (!msg.channel_list) {
5275b9c547cSRui Paulo 		/* Non-success cases are not required to include Channel List */
5285b9c547cSRui Paulo 		channels = &p2p->channels;
5295b9c547cSRui Paulo 	} else if (p2p_peer_channels_check(p2p, &p2p->channels, dev,
5305b9c547cSRui Paulo 					   msg.channel_list,
5315b9c547cSRui Paulo 					   msg.channel_list_len) < 0) {
5325b9c547cSRui Paulo 		p2p_dbg(p2p, "No common channels found");
5335b9c547cSRui Paulo 		p2p_parse_free(&msg);
5345b9c547cSRui Paulo 		return;
5355b9c547cSRui Paulo 	} else {
5365b9c547cSRui Paulo 		p2p_channels_intersect(&p2p->channels, &dev->channels,
5375b9c547cSRui Paulo 				       &intersection);
5385b9c547cSRui Paulo 		channels = &intersection;
5395b9c547cSRui Paulo 	}
5405b9c547cSRui Paulo 
5415b9c547cSRui Paulo 	if (p2p->cfg->invitation_result) {
5425b9c547cSRui Paulo 		int peer_oper_freq = 0;
5435b9c547cSRui Paulo 		int freq = p2p_channel_to_freq(p2p->op_reg_class,
5445b9c547cSRui Paulo 					       p2p->op_channel);
5455b9c547cSRui Paulo 		if (freq < 0)
5465b9c547cSRui Paulo 			freq = 0;
5475b9c547cSRui Paulo 
5485b9c547cSRui Paulo 		if (msg.operating_channel) {
5495b9c547cSRui Paulo 			peer_oper_freq = p2p_channel_to_freq(
5505b9c547cSRui Paulo 				msg.operating_channel[3],
5515b9c547cSRui Paulo 				msg.operating_channel[4]);
5525b9c547cSRui Paulo 			if (peer_oper_freq < 0)
5535b9c547cSRui Paulo 				peer_oper_freq = 0;
5545b9c547cSRui Paulo 		}
5555b9c547cSRui Paulo 
556325151a3SRui Paulo 		/*
557325151a3SRui Paulo 		 * Use the driver preferred frequency list extension if
558325151a3SRui Paulo 		 * supported.
559325151a3SRui Paulo 		 */
560325151a3SRui Paulo 		p2p_check_pref_chan(p2p, 0, dev, &msg);
561325151a3SRui Paulo 
562f05cddf9SRui Paulo 		p2p->cfg->invitation_result(p2p->cfg->cb_ctx, *msg.status,
5635b9c547cSRui Paulo 					    msg.group_bssid, channels, sa,
5645b9c547cSRui Paulo 					    freq, peer_oper_freq);
5655b9c547cSRui Paulo 	}
566f05cddf9SRui Paulo 
567f05cddf9SRui Paulo 	p2p_parse_free(&msg);
568f05cddf9SRui Paulo 
569f05cddf9SRui Paulo 	p2p_clear_timeout(p2p);
570f05cddf9SRui Paulo 	p2p_set_state(p2p, P2P_IDLE);
571f05cddf9SRui Paulo 	p2p->invite_peer = NULL;
572f05cddf9SRui Paulo }
573f05cddf9SRui Paulo 
574f05cddf9SRui Paulo 
p2p_invite_send(struct p2p_data * p2p,struct p2p_device * dev,const u8 * go_dev_addr,int dev_pw_id)575f05cddf9SRui Paulo int p2p_invite_send(struct p2p_data *p2p, struct p2p_device *dev,
5765b9c547cSRui Paulo 		    const u8 *go_dev_addr, int dev_pw_id)
577f05cddf9SRui Paulo {
578f05cddf9SRui Paulo 	struct wpabuf *req;
579f05cddf9SRui Paulo 	int freq;
580f05cddf9SRui Paulo 
581f05cddf9SRui Paulo 	freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
5825b9c547cSRui Paulo 	if (freq <= 0)
5835b9c547cSRui Paulo 		freq = dev->oob_go_neg_freq;
584f05cddf9SRui Paulo 	if (freq <= 0) {
5855b9c547cSRui Paulo 		p2p_dbg(p2p, "No Listen/Operating frequency known for the peer "
5865b9c547cSRui Paulo 			MACSTR " to send Invitation Request",
587f05cddf9SRui Paulo 			MAC2STR(dev->info.p2p_device_addr));
588f05cddf9SRui Paulo 		return -1;
589f05cddf9SRui Paulo 	}
590f05cddf9SRui Paulo 
5915b9c547cSRui Paulo 	req = p2p_build_invitation_req(p2p, dev, go_dev_addr, dev_pw_id);
592f05cddf9SRui Paulo 	if (req == NULL)
593f05cddf9SRui Paulo 		return -1;
594f05cddf9SRui Paulo 	if (p2p->state != P2P_IDLE)
595f05cddf9SRui Paulo 		p2p_stop_listen_for_freq(p2p, freq);
5965b9c547cSRui Paulo 	p2p_dbg(p2p, "Sending Invitation Request");
597f05cddf9SRui Paulo 	p2p_set_state(p2p, P2P_INVITE);
598f05cddf9SRui Paulo 	p2p->pending_action_state = P2P_PENDING_INVITATION_REQUEST;
599f05cddf9SRui Paulo 	p2p->invite_peer = dev;
600f05cddf9SRui Paulo 	dev->invitation_reqs++;
601*a90b9d01SCy Schubert 
602*a90b9d01SCy Schubert 	/* In case of an active P2P GO use a shorter wait time to avoid
603*a90b9d01SCy Schubert 	 * issues if not sending out multiple consecutive Beacon frames. */
604f05cddf9SRui Paulo 	if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
605f05cddf9SRui Paulo 			    p2p->cfg->dev_addr, dev->info.p2p_device_addr,
606*a90b9d01SCy Schubert 			    wpabuf_head(req), wpabuf_len(req),
607*a90b9d01SCy Schubert 			    p2p->inv_role == P2P_INVITE_ROLE_ACTIVE_GO ?
608*a90b9d01SCy Schubert 			    150 : 500) < 0) {
6095b9c547cSRui Paulo 		p2p_dbg(p2p, "Failed to send Action frame");
610f05cddf9SRui Paulo 		/* Use P2P find to recover and retry */
611f05cddf9SRui Paulo 		p2p_set_timeout(p2p, 0, 0);
6125b9c547cSRui Paulo 	} else {
6135b9c547cSRui Paulo 		dev->flags |= P2P_DEV_WAIT_INV_REQ_ACK;
614f05cddf9SRui Paulo 	}
615f05cddf9SRui Paulo 
616f05cddf9SRui Paulo 	wpabuf_free(req);
617f05cddf9SRui Paulo 
618f05cddf9SRui Paulo 	return 0;
619f05cddf9SRui Paulo }
620f05cddf9SRui Paulo 
621f05cddf9SRui Paulo 
p2p_invitation_req_cb(struct p2p_data * p2p,int success)622f05cddf9SRui Paulo void p2p_invitation_req_cb(struct p2p_data *p2p, int success)
623f05cddf9SRui Paulo {
6245b9c547cSRui Paulo 	p2p_dbg(p2p, "Invitation Request TX callback: success=%d", success);
625f05cddf9SRui Paulo 
626f05cddf9SRui Paulo 	if (p2p->invite_peer == NULL) {
6275b9c547cSRui Paulo 		p2p_dbg(p2p, "No pending Invite");
628f05cddf9SRui Paulo 		return;
629f05cddf9SRui Paulo 	}
630f05cddf9SRui Paulo 
6315b9c547cSRui Paulo 	if (success)
6325b9c547cSRui Paulo 		p2p->invite_peer->flags &= ~P2P_DEV_WAIT_INV_REQ_ACK;
6335b9c547cSRui Paulo 
634f05cddf9SRui Paulo 	/*
635f05cddf9SRui Paulo 	 * Use P2P find, if needed, to find the other device from its listen
636f05cddf9SRui Paulo 	 * channel.
637f05cddf9SRui Paulo 	 */
638f05cddf9SRui Paulo 	p2p_set_state(p2p, P2P_INVITE);
6395b9c547cSRui Paulo 	p2p_set_timeout(p2p, 0, success ? 500000 : 100000);
640f05cddf9SRui Paulo }
641f05cddf9SRui Paulo 
642f05cddf9SRui Paulo 
p2p_invitation_resp_cb(struct p2p_data * p2p,int success)643f05cddf9SRui Paulo void p2p_invitation_resp_cb(struct p2p_data *p2p, int success)
644f05cddf9SRui Paulo {
6455b9c547cSRui Paulo 	p2p_dbg(p2p, "Invitation Response TX callback: success=%d", success);
646f05cddf9SRui Paulo 	p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
647f05cddf9SRui Paulo 
6485b9c547cSRui Paulo 	if (!success)
6495b9c547cSRui Paulo 		p2p_dbg(p2p, "Assume Invitation Response was actually received by the peer even though Ack was not reported");
6505b9c547cSRui Paulo 
6515b9c547cSRui Paulo 	if (p2p->cfg->invitation_received) {
652f05cddf9SRui Paulo 		p2p->cfg->invitation_received(p2p->cfg->cb_ctx,
653f05cddf9SRui Paulo 					      p2p->inv_sa,
654f05cddf9SRui Paulo 					      p2p->inv_group_bssid_ptr,
655f05cddf9SRui Paulo 					      p2p->inv_ssid, p2p->inv_ssid_len,
656f05cddf9SRui Paulo 					      p2p->inv_go_dev_addr,
657f05cddf9SRui Paulo 					      p2p->inv_status,
658f05cddf9SRui Paulo 					      p2p->inv_op_freq);
659f05cddf9SRui Paulo 	}
660f05cddf9SRui Paulo }
661f05cddf9SRui Paulo 
662f05cddf9SRui Paulo 
p2p_invite(struct p2p_data * p2p,const u8 * peer,enum p2p_invite_role role,const u8 * bssid,const u8 * ssid,size_t ssid_len,unsigned int force_freq,const u8 * go_dev_addr,int persistent_group,unsigned int pref_freq,int dev_pw_id)663f05cddf9SRui Paulo int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role,
664f05cddf9SRui Paulo 	       const u8 *bssid, const u8 *ssid, size_t ssid_len,
665f05cddf9SRui Paulo 	       unsigned int force_freq, const u8 *go_dev_addr,
6665b9c547cSRui Paulo 	       int persistent_group, unsigned int pref_freq, int dev_pw_id)
667f05cddf9SRui Paulo {
668f05cddf9SRui Paulo 	struct p2p_device *dev;
669f05cddf9SRui Paulo 
6705b9c547cSRui Paulo 	p2p_dbg(p2p, "Request to invite peer " MACSTR " role=%d persistent=%d "
671c1d255d3SCy Schubert 		"force_freq=%u allow_6ghz=%d",
672c1d255d3SCy Schubert 		MAC2STR(peer), role, persistent_group, force_freq,
673c1d255d3SCy Schubert 		p2p->allow_6ghz);
674f05cddf9SRui Paulo 	if (bssid)
6755b9c547cSRui Paulo 		p2p_dbg(p2p, "Invitation for BSSID " MACSTR, MAC2STR(bssid));
676f05cddf9SRui Paulo 	if (go_dev_addr) {
6775b9c547cSRui Paulo 		p2p_dbg(p2p, "Invitation for GO Device Address " MACSTR,
678f05cddf9SRui Paulo 			MAC2STR(go_dev_addr));
679f05cddf9SRui Paulo 		os_memcpy(p2p->invite_go_dev_addr_buf, go_dev_addr, ETH_ALEN);
680f05cddf9SRui Paulo 		p2p->invite_go_dev_addr = p2p->invite_go_dev_addr_buf;
681f05cddf9SRui Paulo 	} else
682f05cddf9SRui Paulo 		p2p->invite_go_dev_addr = NULL;
6835b9c547cSRui Paulo 	wpa_hexdump_ascii(MSG_DEBUG, "Invitation for SSID",
684f05cddf9SRui Paulo 			  ssid, ssid_len);
6855b9c547cSRui Paulo 	if (dev_pw_id >= 0) {
6865b9c547cSRui Paulo 		p2p_dbg(p2p, "Invitation to use Device Password ID %d",
6875b9c547cSRui Paulo 			dev_pw_id);
6885b9c547cSRui Paulo 	}
6895b9c547cSRui Paulo 	p2p->invite_dev_pw_id = dev_pw_id;
6905b9c547cSRui Paulo 	p2p->retry_invite_req = role == P2P_INVITE_ROLE_GO &&
6915b9c547cSRui Paulo 		persistent_group && !force_freq;
6925b9c547cSRui Paulo 	p2p->retry_invite_req_sent = 0;
693f05cddf9SRui Paulo 
694f05cddf9SRui Paulo 	dev = p2p_get_device(p2p, peer);
6955b9c547cSRui Paulo 	if (dev == NULL || (dev->listen_freq <= 0 && dev->oper_freq <= 0 &&
6965b9c547cSRui Paulo 			    dev->oob_go_neg_freq <= 0)) {
6975b9c547cSRui Paulo 		p2p_dbg(p2p, "Cannot invite unknown P2P Device " MACSTR,
698f05cddf9SRui Paulo 			MAC2STR(peer));
699f05cddf9SRui Paulo 		return -1;
700f05cddf9SRui Paulo 	}
701f05cddf9SRui Paulo 
7025b9c547cSRui Paulo 	if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq,
7035b9c547cSRui Paulo 				role != P2P_INVITE_ROLE_CLIENT) < 0)
7045b9c547cSRui Paulo 		return -1;
7055b9c547cSRui Paulo 
7065b9c547cSRui Paulo 	if (persistent_group && role == P2P_INVITE_ROLE_CLIENT && !force_freq &&
7075b9c547cSRui Paulo 	    !pref_freq)
7085b9c547cSRui Paulo 		dev->flags |= P2P_DEV_NO_PREF_CHAN;
7095b9c547cSRui Paulo 	else
7105b9c547cSRui Paulo 		dev->flags &= ~P2P_DEV_NO_PREF_CHAN;
7115b9c547cSRui Paulo 
712f05cddf9SRui Paulo 	if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) {
713f05cddf9SRui Paulo 		if (!(dev->info.dev_capab &
714f05cddf9SRui Paulo 		      P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) {
7155b9c547cSRui Paulo 			p2p_dbg(p2p, "Cannot invite a P2P Device " MACSTR
716f05cddf9SRui Paulo 				" that is in a group and is not discoverable",
717f05cddf9SRui Paulo 				MAC2STR(peer));
718f05cddf9SRui Paulo 		}
719f05cddf9SRui Paulo 		/* TODO: use device discoverability request through GO */
720f05cddf9SRui Paulo 	}
721f05cddf9SRui Paulo 
722f05cddf9SRui Paulo 	dev->invitation_reqs = 0;
723f05cddf9SRui Paulo 
724f05cddf9SRui Paulo 	if (p2p->state != P2P_IDLE)
725f05cddf9SRui Paulo 		p2p_stop_find(p2p);
726f05cddf9SRui Paulo 
727f05cddf9SRui Paulo 	p2p->inv_role = role;
728f05cddf9SRui Paulo 	p2p->inv_bssid_set = bssid != NULL;
729f05cddf9SRui Paulo 	if (bssid)
730f05cddf9SRui Paulo 		os_memcpy(p2p->inv_bssid, bssid, ETH_ALEN);
731f05cddf9SRui Paulo 	os_memcpy(p2p->inv_ssid, ssid, ssid_len);
732f05cddf9SRui Paulo 	p2p->inv_ssid_len = ssid_len;
733f05cddf9SRui Paulo 	p2p->inv_persistent = persistent_group;
7345b9c547cSRui Paulo 	return p2p_invite_send(p2p, dev, go_dev_addr, dev_pw_id);
735f05cddf9SRui Paulo }
736