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, ®_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