blob: a55e7e68822aea8f746eec9ecbd18ff7fc4d1943 [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * Wi-Fi Direct - P2P provision discovery
3 * Copyright (c) 2009-2010, Atheros Communications
4 *
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007 */
8
9#include "includes.h"
10
11#include "common.h"
12#include "common/ieee802_11_defs.h"
Dmitry Shmidt2e67f062014-07-16 09:55:28 -070013#include "common/wpa_ctrl.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070014#include "wps/wps_defs.h"
15#include "p2p_i.h"
16#include "p2p.h"
17
18
Jouni Malinen75ecf522011-06-27 15:19:46 -070019/*
Dmitry Shmidt61d9df32012-08-29 16:22:06 -070020 * Number of retries to attempt for provision discovery requests
21 * in case the peer is not listening.
Jouni Malinen75ecf522011-06-27 15:19:46 -070022 */
Dmitry Shmidtd5e49232012-12-03 15:08:10 -080023#define MAX_PROV_DISC_REQ_RETRIES 120
Jouni Malinen75ecf522011-06-27 15:19:46 -070024
25
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070026static void p2p_build_wps_ie_config_methods(struct wpabuf *buf,
27 u16 config_methods)
28{
29 u8 *len;
30 wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
31 len = wpabuf_put(buf, 1);
32 wpabuf_put_be32(buf, WPS_DEV_OUI_WFA);
33
34 /* Config Methods */
35 wpabuf_put_be16(buf, ATTR_CONFIG_METHODS);
36 wpabuf_put_be16(buf, 2);
37 wpabuf_put_be16(buf, config_methods);
38
39 p2p_buf_update_ie_hdr(buf, len);
40}
41
42
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080043static void p2ps_add_new_group_info(struct p2p_data *p2p,
44 struct p2p_device *dev,
45 struct wpabuf *buf)
Dmitry Shmidt216983b2015-02-06 10:50:36 -080046{
47 int found;
48 u8 intended_addr[ETH_ALEN];
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -070049 u8 ssid[SSID_MAX_LEN];
Dmitry Shmidt216983b2015-02-06 10:50:36 -080050 size_t ssid_len;
51 int group_iface;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080052 unsigned int force_freq;
Dmitry Shmidt216983b2015-02-06 10:50:36 -080053
54 if (!p2p->cfg->get_go_info)
55 return;
56
57 found = p2p->cfg->get_go_info(
58 p2p->cfg->cb_ctx, intended_addr, ssid,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080059 &ssid_len, &group_iface, &force_freq);
Dmitry Shmidt216983b2015-02-06 10:50:36 -080060 if (found) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080061 if (force_freq > 0) {
62 p2p->p2ps_prov->force_freq = force_freq;
63 p2p->p2ps_prov->pref_freq = 0;
64
65 if (dev)
66 p2p_prepare_channel(p2p, dev, force_freq, 0, 0);
67 }
Dmitry Shmidt216983b2015-02-06 10:50:36 -080068 p2p_buf_add_group_id(buf, p2p->cfg->dev_addr,
69 ssid, ssid_len);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080070
71 if (group_iface)
72 p2p_buf_add_intended_addr(buf, p2p->intended_addr);
73 else
74 p2p_buf_add_intended_addr(buf, intended_addr);
Dmitry Shmidt216983b2015-02-06 10:50:36 -080075 } else {
76 if (!p2p->ssid_set) {
77 p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len);
78 p2p->ssid_set = 1;
79 }
80
81 /* Add pre-composed P2P Group ID */
82 p2p_buf_add_group_id(buf, p2p->cfg->dev_addr,
83 p2p->ssid, p2p->ssid_len);
84
85 if (group_iface)
86 p2p_buf_add_intended_addr(
87 buf, p2p->intended_addr);
88 else
89 p2p_buf_add_intended_addr(
90 buf, p2p->cfg->dev_addr);
91 }
92}
93
94
95static void p2ps_add_pd_req_attrs(struct p2p_data *p2p, struct p2p_device *dev,
96 struct wpabuf *buf, u16 config_methods)
97{
98 struct p2ps_provision *prov = p2p->p2ps_prov;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080099 struct p2ps_feature_capab fcap = { prov->cpt_mask, 0 };
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800100 int shared_group = 0;
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -0700101 u8 ssid[SSID_MAX_LEN];
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800102 size_t ssid_len;
103 u8 go_dev_addr[ETH_ALEN];
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800104 u8 intended_addr[ETH_ALEN];
105 int follow_on_req_fail = prov->status >= 0 &&
106 prov->status != P2P_SC_SUCCESS_DEFERRED;
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800107
108 /* If we might be explicite group owner, add GO details */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800109 if (!follow_on_req_fail &&
110 (prov->conncap & (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW)))
111 p2ps_add_new_group_info(p2p, dev, buf);
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800112
113 if (prov->status >= 0)
114 p2p_buf_add_status(buf, (u8) prov->status);
115 else
116 prov->method = config_methods;
117
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800118 if (!follow_on_req_fail) {
119 if (p2p->cfg->get_persistent_group) {
120 shared_group = p2p->cfg->get_persistent_group(
121 p2p->cfg->cb_ctx, dev->info.p2p_device_addr,
122 NULL, 0, go_dev_addr, ssid, &ssid_len,
123 intended_addr);
124 }
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800125
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800126 if (shared_group ||
Sunil8cd6f4d2022-06-28 18:40:46 +0000127 (prov->conncap & (P2PS_SETUP_CLIENT | P2PS_SETUP_NEW))) {
128 bool is_6ghz_capab;
129
130 is_6ghz_capab = is_p2p_6ghz_capable(p2p) &&
131 p2p_is_peer_6ghz_capab(
132 p2p, dev->info.p2p_device_addr);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800133 p2p_buf_add_channel_list(buf, p2p->cfg->country,
Sunil8cd6f4d2022-06-28 18:40:46 +0000134 &p2p->channels, is_6ghz_capab);
135 }
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800136
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800137 if ((shared_group && !is_zero_ether_addr(intended_addr)) ||
138 (prov->conncap & (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW)))
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800139 p2p_buf_add_operating_channel(buf, p2p->cfg->country,
140 p2p->op_reg_class,
141 p2p->op_channel);
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800142 }
143
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800144 if (prov->status < 0 && prov->info[0])
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800145 p2p_buf_add_session_info(buf, prov->info);
146
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800147 if (!follow_on_req_fail)
148 p2p_buf_add_connection_capability(buf, prov->conncap);
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800149
150 p2p_buf_add_advertisement_id(buf, prov->adv_id, prov->adv_mac);
151
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800152 if (!follow_on_req_fail) {
153 if (shared_group || prov->conncap == P2PS_SETUP_NEW ||
154 prov->conncap ==
155 (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW) ||
156 prov->conncap ==
157 (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_CLIENT)) {
158 /* Add Config Timeout */
159 p2p_buf_add_config_timeout(buf, p2p->go_timeout,
160 p2p->client_timeout);
161 }
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800162
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800163 p2p_buf_add_listen_channel(buf, p2p->cfg->country,
164 p2p->cfg->reg_class,
165 p2p->cfg->channel);
166 }
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800167
168 p2p_buf_add_session_id(buf, prov->session_id, prov->session_mac);
169
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800170 p2p_buf_add_feature_capability(buf, sizeof(fcap), (const u8 *) &fcap);
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800171
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800172 if (shared_group) {
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800173 p2p_buf_add_persistent_group_info(buf, go_dev_addr,
174 ssid, ssid_len);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800175 /* Add intended interface address if it is not added yet */
176 if ((prov->conncap == P2PS_SETUP_NONE ||
177 prov->conncap == P2PS_SETUP_CLIENT) &&
178 !is_zero_ether_addr(intended_addr))
179 p2p_buf_add_intended_addr(buf, intended_addr);
180 }
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800181}
182
183
Sunil Ravic0f5d412024-09-11 22:12:49 +0000184static struct wpabuf * p2p_build_prov_disc_bootstrap_req(struct p2p_data *p2p,
185 struct p2p_device *dev)
186{
187 struct wpabuf *buf;
188 u8 *len;
189 size_t cookie_len = 0;
190 const u8 *cookie = NULL;
191 u8 dialog_token = dev->dialog_token;
192 u8 group_capab;
193
194 buf = wpabuf_alloc(1000);
195 if (!buf)
196 return NULL;
197
198 p2p_dbg(p2p, "P2P2: Building bootstrapping PD Request");
199 p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_REQ, dialog_token);
200
201 len = p2p_buf_add_ie_hdr(buf);
202
203 group_capab = 0;
204
205 if (p2p->num_groups) {
206 group_capab |= P2P_GROUP_CAPAB_GROUP_OWNER;
207 if ((p2p->dev_capab & P2P_DEV_CAPAB_CONCURRENT_OPER) &&
208 (p2p->dev_capab & P2P_DEV_CAPAB_INFRA_MANAGED) &&
209 p2p->cross_connect)
210 group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
211 }
212 if (p2p->cfg->p2p_intra_bss)
213 group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST;
214
215 p2p_buf_add_capability(buf, p2p->dev_capab &
216 ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY,
217 group_capab);
218 p2p_buf_add_device_info(buf, p2p, NULL);
219
220 if (dev->bootstrap_params) {
221 cookie = dev->bootstrap_params->cookie;
222 cookie_len = dev->bootstrap_params->cookie_len;
223
224 if (dev->bootstrap_params->status == P2P_SC_COMEBACK)
225 p2p_buf_add_status(buf, dev->bootstrap_params->status);
226 }
227
228 p2p_buf_update_ie_hdr(buf, len);
229
230 len = p2p_buf_add_p2p2_ie_hdr(buf);
231
232 p2p_buf_add_pcea(buf, p2p);
233 p2p_buf_add_pbma(buf, dev->req_bootstrap_method, cookie, cookie_len, 0);
234
235 p2p_buf_update_ie_hdr(buf, len);
236
237 wpa_printf(MSG_DEBUG, "P2P2: Added PCEA and PBMA in PD Request");
238 return buf;
239}
240
241
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700242static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p,
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800243 struct p2p_device *dev,
244 int join)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700245{
246 struct wpabuf *buf;
247 u8 *len;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700248 size_t extra = 0;
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800249 u8 dialog_token = dev->dialog_token;
250 u16 config_methods = dev->req_config_methods;
251 struct p2p_device *go = join ? dev : NULL;
252 u8 group_capab;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700253
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700254#ifdef CONFIG_WIFI_DISPLAY
255 if (p2p->wfd_ie_prov_disc_req)
256 extra = wpabuf_len(p2p->wfd_ie_prov_disc_req);
257#endif /* CONFIG_WIFI_DISPLAY */
258
Dmitry Shmidt2e67f062014-07-16 09:55:28 -0700259 if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ])
260 extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ]);
261
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800262 if (p2p->p2ps_prov)
263 extra += os_strlen(p2p->p2ps_prov->info) + 1 +
264 sizeof(struct p2ps_provision);
265
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700266 buf = wpabuf_alloc(1000 + extra);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700267 if (buf == NULL)
268 return NULL;
269
270 p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_REQ, dialog_token);
271
272 len = p2p_buf_add_ie_hdr(buf);
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800273
274 group_capab = 0;
275 if (p2p->p2ps_prov) {
276 group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP;
277 group_capab |= P2P_GROUP_CAPAB_PERSISTENT_RECONN;
278 if (p2p->cross_connect)
279 group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
280 if (p2p->cfg->p2p_intra_bss)
281 group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST;
282 }
Dmitry Shmidt04949592012-07-19 12:16:46 -0700283 p2p_buf_add_capability(buf, p2p->dev_capab &
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800284 ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY,
285 group_capab);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700286 p2p_buf_add_device_info(buf, p2p, NULL);
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800287 if (p2p->p2ps_prov) {
288 p2ps_add_pd_req_attrs(p2p, dev, buf, config_methods);
289 } else if (go) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700290 p2p_buf_add_group_id(buf, go->info.p2p_device_addr,
291 go->oper_ssid, go->oper_ssid_len);
292 }
293 p2p_buf_update_ie_hdr(buf, len);
294
295 /* WPS IE with Config Methods attribute */
296 p2p_build_wps_ie_config_methods(buf, config_methods);
297
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700298#ifdef CONFIG_WIFI_DISPLAY
299 if (p2p->wfd_ie_prov_disc_req)
300 wpabuf_put_buf(buf, p2p->wfd_ie_prov_disc_req);
301#endif /* CONFIG_WIFI_DISPLAY */
302
Dmitry Shmidt2e67f062014-07-16 09:55:28 -0700303 if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ])
304 wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ]);
305
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700306 return buf;
307}
308
309
Sunil Ravic0f5d412024-09-11 22:12:49 +0000310static struct wpabuf *
311p2p_build_prov_disc_bootstrap_resp(struct p2p_data *p2p, struct p2p_device *dev,
312 u8 dialog_token, enum p2p_status_code status)
313{
314 struct wpabuf *buf;
315 u8 *cookie = NULL;
316 size_t cookie_len = 0;
317 int comeback_after = 0;
318 u8 *len;
319
320 buf = wpabuf_alloc(1000);
321 if (!buf)
322 return NULL;
323
324 p2p_dbg(p2p, "P2P2: Building boostrapping PD Response");
325 if (status == P2P_SC_COMEBACK && dev->bootstrap_params) {
326 cookie = dev->bootstrap_params->cookie;
327 cookie_len = dev->bootstrap_params->cookie_len;
328 comeback_after = dev->bootstrap_params->comeback_after;
329 }
330
331 p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_RESP, dialog_token);
332
333 len = p2p_buf_add_p2p2_ie_hdr(buf);
334
335 p2p_buf_add_status(buf, status);
336 p2p_buf_add_pcea(buf, p2p);
337 p2p_buf_add_pbma(buf, dev->req_bootstrap_method, cookie, cookie_len,
338 comeback_after);
339
340 p2p_buf_update_ie_hdr(buf, len);
341
342 return buf;
343}
344
345
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700346static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800347 struct p2p_device *dev,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700348 u8 dialog_token,
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800349 enum p2p_status_code status,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700350 u16 config_methods,
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800351 u32 adv_id,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700352 const u8 *group_id,
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800353 size_t group_id_len,
354 const u8 *persist_ssid,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800355 size_t persist_ssid_len,
356 const u8 *fcap,
357 u16 fcap_len)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700358{
359 struct wpabuf *buf;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700360 size_t extra = 0;
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800361 int persist = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700362
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700363#ifdef CONFIG_WIFI_DISPLAY
364 struct wpabuf *wfd_ie = p2p->wfd_ie_prov_disc_resp;
365 if (wfd_ie && group_id) {
366 size_t i;
367 for (i = 0; i < p2p->num_groups; i++) {
368 struct p2p_group *g = p2p->groups[i];
369 struct wpabuf *ie;
370 if (!p2p_group_is_group_id_match(g, group_id,
371 group_id_len))
372 continue;
373 ie = p2p_group_get_wfd_ie(g);
374 if (ie) {
375 wfd_ie = ie;
376 break;
377 }
378 }
379 }
380 if (wfd_ie)
381 extra = wpabuf_len(wfd_ie);
382#endif /* CONFIG_WIFI_DISPLAY */
383
Dmitry Shmidt2e67f062014-07-16 09:55:28 -0700384 if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP])
385 extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP]);
386
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800387 buf = wpabuf_alloc(1000 + extra);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700388 if (buf == NULL)
389 return NULL;
390
391 p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_RESP, dialog_token);
392
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800393 /* Add P2P IE for P2PS */
394 if (p2p->p2ps_prov && p2p->p2ps_prov->adv_id == adv_id) {
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800395 u8 *len = p2p_buf_add_ie_hdr(buf);
396 struct p2ps_provision *prov = p2p->p2ps_prov;
397 u8 group_capab;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800398 u8 conncap = 0;
399
400 if (status == P2P_SC_SUCCESS ||
401 status == P2P_SC_SUCCESS_DEFERRED)
402 conncap = prov->conncap;
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800403
404 if (!status && prov->status != -1)
405 status = prov->status;
406
407 p2p_buf_add_status(buf, status);
408 group_capab = P2P_GROUP_CAPAB_PERSISTENT_GROUP |
409 P2P_GROUP_CAPAB_PERSISTENT_RECONN;
410 if (p2p->cross_connect)
411 group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
412 if (p2p->cfg->p2p_intra_bss)
413 group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST;
414 p2p_buf_add_capability(buf, p2p->dev_capab &
415 ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY,
416 group_capab);
417 p2p_buf_add_device_info(buf, p2p, NULL);
418
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800419 if (persist_ssid && p2p->cfg->get_persistent_group && dev &&
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800420 (status == P2P_SC_SUCCESS ||
421 status == P2P_SC_SUCCESS_DEFERRED)) {
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -0700422 u8 ssid[SSID_MAX_LEN];
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800423 size_t ssid_len;
424 u8 go_dev_addr[ETH_ALEN];
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800425 u8 intended_addr[ETH_ALEN];
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800426
427 persist = p2p->cfg->get_persistent_group(
428 p2p->cfg->cb_ctx,
429 dev->info.p2p_device_addr,
430 persist_ssid, persist_ssid_len, go_dev_addr,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800431 ssid, &ssid_len, intended_addr);
432 if (persist) {
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800433 p2p_buf_add_persistent_group_info(
434 buf, go_dev_addr, ssid, ssid_len);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800435 if (!is_zero_ether_addr(intended_addr))
436 p2p_buf_add_intended_addr(
437 buf, intended_addr);
438 }
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800439 }
440
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800441 if (!persist && (conncap & P2PS_SETUP_GROUP_OWNER))
442 p2ps_add_new_group_info(p2p, dev, buf);
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800443
444 /* Add Operating Channel if conncap indicates GO */
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800445 if (persist || (conncap & P2PS_SETUP_GROUP_OWNER)) {
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800446 if (p2p->op_reg_class && p2p->op_channel)
447 p2p_buf_add_operating_channel(
448 buf, p2p->cfg->country,
449 p2p->op_reg_class,
450 p2p->op_channel);
451 else
452 p2p_buf_add_operating_channel(
453 buf, p2p->cfg->country,
454 p2p->cfg->op_reg_class,
455 p2p->cfg->op_channel);
456 }
457
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800458 if (persist ||
Sunil8cd6f4d2022-06-28 18:40:46 +0000459 (conncap & (P2PS_SETUP_CLIENT | P2PS_SETUP_GROUP_OWNER))) {
460 bool is_6ghz_capab;
461
Sunil Ravi38ad1ed2023-01-17 23:58:31 +0000462 is_6ghz_capab = is_p2p_6ghz_capable(p2p) && dev &&
Sunil8cd6f4d2022-06-28 18:40:46 +0000463 p2p_is_peer_6ghz_capab(
464 p2p, dev->info.p2p_device_addr);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800465 p2p_buf_add_channel_list(buf, p2p->cfg->country,
Sunil8cd6f4d2022-06-28 18:40:46 +0000466 &p2p->channels, is_6ghz_capab);
467 }
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800468
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800469 if (!persist && conncap)
470 p2p_buf_add_connection_capability(buf, conncap);
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800471
472 p2p_buf_add_advertisement_id(buf, adv_id, prov->adv_mac);
473
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800474 if (persist ||
475 (conncap & (P2PS_SETUP_CLIENT | P2PS_SETUP_GROUP_OWNER)))
476 p2p_buf_add_config_timeout(buf, p2p->go_timeout,
477 p2p->client_timeout);
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800478
479 p2p_buf_add_session_id(buf, prov->session_id,
480 prov->session_mac);
481
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800482 p2p_buf_add_feature_capability(buf, fcap_len, fcap);
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800483 p2p_buf_update_ie_hdr(buf, len);
484 } else if (status != P2P_SC_SUCCESS || adv_id) {
485 u8 *len = p2p_buf_add_ie_hdr(buf);
486
487 p2p_buf_add_status(buf, status);
488
489 if (p2p->p2ps_prov)
490 p2p_buf_add_advertisement_id(buf, adv_id,
491 p2p->p2ps_prov->adv_mac);
492
493 p2p_buf_update_ie_hdr(buf, len);
494 }
495
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700496 /* WPS IE with Config Methods attribute */
497 p2p_build_wps_ie_config_methods(buf, config_methods);
498
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700499#ifdef CONFIG_WIFI_DISPLAY
500 if (wfd_ie)
501 wpabuf_put_buf(buf, wfd_ie);
502#endif /* CONFIG_WIFI_DISPLAY */
503
Dmitry Shmidt2e67f062014-07-16 09:55:28 -0700504 if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP])
505 wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP]);
506
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700507 return buf;
508}
509
510
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800511static int p2ps_setup_p2ps_prov(struct p2p_data *p2p, u32 adv_id,
512 u32 session_id, u16 method,
513 const u8 *session_mac, const u8 *adv_mac)
514{
515 struct p2ps_provision *tmp;
516
517 if (!p2p->p2ps_prov) {
518 p2p->p2ps_prov = os_zalloc(sizeof(struct p2ps_provision) + 1);
519 if (!p2p->p2ps_prov)
520 return -1;
521 } else {
522 os_memset(p2p->p2ps_prov, 0, sizeof(struct p2ps_provision) + 1);
523 }
524
525 tmp = p2p->p2ps_prov;
526 tmp->adv_id = adv_id;
527 tmp->session_id = session_id;
528 tmp->method = method;
529 os_memcpy(tmp->session_mac, session_mac, ETH_ALEN);
530 os_memcpy(tmp->adv_mac, adv_mac, ETH_ALEN);
531 tmp->info[0] = '\0';
532
533 return 0;
534}
535
536
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800537static u8 p2ps_own_preferred_cpt(const u8 *cpt_priority, u8 req_cpt_mask)
538{
539 int i;
540
541 for (i = 0; cpt_priority[i]; i++)
542 if (req_cpt_mask & cpt_priority[i])
543 return cpt_priority[i];
544
545 return 0;
546}
547
548
549/* Check if the message contains a valid P2PS PD Request */
550static int p2ps_validate_pd_req(struct p2p_data *p2p, struct p2p_message *msg,
551 const u8 *addr)
552{
553 u8 group_id = 0;
554 u8 intended_addr = 0;
555 u8 operating_channel = 0;
556 u8 channel_list = 0;
557 u8 config_timeout = 0;
558 u8 listen_channel = 0;
559
560#define P2PS_PD_REQ_CHECK(_val, _attr) \
561do { \
562 if ((_val) && !msg->_attr) { \
563 p2p_dbg(p2p, "Not P2PS PD Request. Missing %s", #_attr); \
564 return -1; \
565 } \
566} while (0)
567
568 P2PS_PD_REQ_CHECK(1, adv_id);
569 P2PS_PD_REQ_CHECK(1, session_id);
570 P2PS_PD_REQ_CHECK(1, session_mac);
571 P2PS_PD_REQ_CHECK(1, adv_mac);
572 P2PS_PD_REQ_CHECK(1, capability);
573 P2PS_PD_REQ_CHECK(1, p2p_device_info);
574 P2PS_PD_REQ_CHECK(1, feature_cap);
575
576 /*
577 * We don't need to check Connection Capability, Persistent Group,
578 * and related attributes for follow-on PD Request with a status
579 * other than SUCCESS_DEFERRED.
580 */
581 if (msg->status && *msg->status != P2P_SC_SUCCESS_DEFERRED)
582 return 0;
583
584 P2PS_PD_REQ_CHECK(1, conn_cap);
585
586 /*
587 * Note 1: A feature capability attribute structure can be changed
588 * in the future. The assumption is that such modifications are
589 * backward compatible, therefore we allow processing of msg.feature_cap
590 * exceeding the size of the p2ps_feature_capab structure.
591 * Note 2: Verification of msg.feature_cap_len below has to be changed
592 * to allow 2 byte feature capability processing if
593 * struct p2ps_feature_capab is extended to include additional fields
594 * and it affects the structure size.
595 */
596 if (msg->feature_cap_len < sizeof(struct p2ps_feature_capab)) {
597 p2p_dbg(p2p, "P2PS: Invalid feature capability len");
598 return -1;
599 }
600
601 switch (*msg->conn_cap) {
602 case P2PS_SETUP_NEW:
603 group_id = 1;
604 intended_addr = 1;
605 operating_channel = 1;
606 channel_list = 1;
607 config_timeout = 1;
608 listen_channel = 1;
609 break;
610 case P2PS_SETUP_CLIENT:
611 channel_list = 1;
612 listen_channel = 1;
613 break;
614 case P2PS_SETUP_GROUP_OWNER:
615 group_id = 1;
616 intended_addr = 1;
617 operating_channel = 1;
618 break;
619 case P2PS_SETUP_NEW | P2PS_SETUP_GROUP_OWNER:
620 group_id = 1;
621 operating_channel = 1;
622 intended_addr = 1;
623 channel_list = 1;
624 config_timeout = 1;
625 break;
626 case P2PS_SETUP_CLIENT | P2PS_SETUP_GROUP_OWNER:
627 group_id = 1;
628 intended_addr = 1;
629 operating_channel = 1;
630 channel_list = 1;
631 config_timeout = 1;
632 break;
633 default:
634 p2p_dbg(p2p, "Invalid P2PS PD connection capability");
635 return -1;
636 }
637
638 if (msg->persistent_dev) {
639 channel_list = 1;
640 config_timeout = 1;
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000641 if (ether_addr_equal(msg->persistent_dev, addr)) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800642 intended_addr = 1;
643 operating_channel = 1;
644 }
645 }
646
647 P2PS_PD_REQ_CHECK(group_id, group_id);
648 P2PS_PD_REQ_CHECK(intended_addr, intended_addr);
649 P2PS_PD_REQ_CHECK(operating_channel, operating_channel);
650 P2PS_PD_REQ_CHECK(channel_list, channel_list);
651 P2PS_PD_REQ_CHECK(config_timeout, config_timeout);
652 P2PS_PD_REQ_CHECK(listen_channel, listen_channel);
653
654#undef P2PS_PD_REQ_CHECK
655
656 return 0;
657}
658
659
Sunil Ravic0f5d412024-09-11 22:12:49 +0000660void p2p_process_pcea(struct p2p_data *p2p, struct p2p_message *msg,
661 struct p2p_device *dev)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700662{
Sunil Ravic0f5d412024-09-11 22:12:49 +0000663 const u8 *pos, *end;
664 u8 cap_info_len;
665
666 if (!p2p || !dev || !msg || !msg->pcea_info)
667 return;
668
669 pos = msg->pcea_info;
670 end = pos + msg->pcea_info_len;
671 dev->info.pcea_cap_info = WPA_GET_LE16(pos);
672 cap_info_len = dev->info.pcea_cap_info & P2P_PCEA_LEN_MASK;
673
674 /* Field length is (n-1), n in octets */
675 if (end - pos < cap_info_len + 1)
676 return;
677 pos += cap_info_len + 1;
678
679 if (dev->info.pcea_cap_info & P2P_PCEA_6GHZ)
680 dev->support_6ghz = true;
681
682 if (dev->info.pcea_cap_info & P2P_PCEA_REG_INFO) {
683 if (end - pos < 1) {
684 p2p_dbg(p2p, "Truncated PCEA");
685 return;
686 }
687 dev->info.reg_info = *pos++;
688 }
689
690 if (dev->info.pcea_cap_info & P2P_PCEA_PASN_TYPE) {
691 if (end - pos < 1) {
692 p2p_dbg(p2p, "Truncated PCEA");
693 return;
694 }
695 dev->info.pairing_config.pasn_type = *pos++;
696 }
697
698 if (dev->info.pcea_cap_info & P2P_PCEA_PAIRING_CAPABLE)
699 dev->info.pairing_config.pairing_capable = true;
700
701 if (dev->info.pcea_cap_info & P2P_PCEA_PAIRING_SETUP_ENABLED)
702 dev->info.pairing_config.enable_pairing_setup = true;
703
704 if (dev->info.pcea_cap_info & P2P_PCEA_PMK_CACHING) {
705 dev->info.pairing_config.enable_pairing_cache = true;
Sunil Ravic0f5d412024-09-11 22:12:49 +0000706 }
707}
708
709
710static void p2p_process_prov_disc_bootstrap_req(struct p2p_data *p2p,
711 struct p2p_message *msg,
712 const u8 *sa, const u8 *data,
713 size_t len, int rx_freq)
714{
715 struct p2p_device *dev;
716 int freq;
717 struct wpabuf *resp;
718 u16 bootstrap;
719 size_t cookie_len = 0;
720 const u8 *pos, *cookie;
721 enum p2p_status_code status = P2P_SC_FAIL_INVALID_PARAMS;
722
723 p2p_dbg(p2p, "Received Provision Discovery Request from " MACSTR
724 " with bootstrapping Attribute (freq=%d)",
725 MAC2STR(sa), rx_freq);
726
727 dev = p2p_get_device(p2p, sa);
728 if (!dev) {
729 p2p_dbg(p2p, "Provision Discovery Request from unknown peer "
730 MACSTR, MAC2STR(sa));
731
732 if (p2p_add_device(p2p, sa, rx_freq, NULL, 0, data, len, 0)) {
733 p2p_dbg(p2p,
734 "Provision Discovery Request add device failed "
735 MACSTR, MAC2STR(sa));
736 return;
737 }
738
739 dev = p2p_get_device(p2p, sa);
740 if (!dev) {
741 p2p_dbg(p2p,
742 "Provision Discovery device not found "
743 MACSTR, MAC2STR(sa));
744 return;
745 }
746 }
747 dev->p2p2 = true;
748
749 if (p2p->send_action_in_progress) {
750 p2p_dbg(p2p, "Dropping retry frame as response TX pending");
751 return;
752 }
753
754 p2p_update_peer_6ghz_capab(dev, msg);
755
756 if (msg->pcea_info && msg->pcea_info_len >= 2)
757 p2p_process_pcea(p2p, msg, dev);
758
759 pos = msg->pbma_info;
760
761 if (msg->pbma_info_len > 2 && msg->status &&
762 *msg->status == P2P_SC_COMEBACK) {
763 /* PBMA comeback request */
764 cookie_len = *pos++;
765 if (msg->pbma_info_len < 1 + cookie_len) {
766 p2p_dbg(p2p, "Truncated PBMA");
767 return;
768 }
769 cookie = pos;
770
771 if (!dev->bootstrap_params ||
772 dev->bootstrap_params->cookie_len != cookie_len ||
773 os_memcmp(cookie, dev->bootstrap_params->cookie,
774 cookie_len) != 0) {
775 status = P2P_SC_FAIL_REJECTED_BY_USER;
776 goto out;
777 }
778
779 bootstrap = dev->bootstrap_params->bootstrap_method;
780
781 if (!dev->req_bootstrap_method) {
782 status = P2P_SC_COMEBACK;
783 if (p2p->cfg->bootstrap_req_rx)
784 p2p->cfg->bootstrap_req_rx(p2p->cfg->cb_ctx,
785 sa, bootstrap);
786 goto out;
787 }
788 } else {
789 /* PBMA request */
790 bootstrap = WPA_GET_LE16(pos);
791
792 os_free(dev->bootstrap_params);
793 dev->bootstrap_params = NULL;
794
795 if (!dev->req_bootstrap_method) {
796 dev->bootstrap_params =
797 os_zalloc(sizeof(struct p2p_bootstrap_params));
798 if (!dev->bootstrap_params)
799 return;
800 dev->bootstrap_params->bootstrap_method = bootstrap;
801 dev->bootstrap_params->cookie_len = 4;
802 if (os_get_random(dev->bootstrap_params->cookie,
803 dev->bootstrap_params->cookie_len) <
804 0) {
805 os_free(dev->bootstrap_params);
806 dev->bootstrap_params = NULL;
807 return;
808 }
809 dev->bootstrap_params->comeback_after =
810 p2p->cfg->comeback_after;
811 status = P2P_SC_COMEBACK;
812 if (p2p->cfg->bootstrap_req_rx)
813 p2p->cfg->bootstrap_req_rx(p2p->cfg->cb_ctx,
814 sa, bootstrap);
815 goto out;
816 }
817 }
818
819 if (bootstrap == P2P_PBMA_PIN_CODE_DISPLAY &&
820 dev->req_bootstrap_method == P2P_PBMA_PIN_CODE_KEYPAD)
821 status = P2P_SC_SUCCESS;
822 else if (bootstrap == P2P_PBMA_PIN_CODE_KEYPAD &&
823 dev->req_bootstrap_method == P2P_PBMA_PIN_CODE_DISPLAY)
824 status = P2P_SC_SUCCESS;
825 else if (bootstrap == P2P_PBMA_PASSPHRASE_DISPLAY &&
826 dev->req_bootstrap_method == P2P_PBMA_PASSPHRASE_KEYPAD)
827 status = P2P_SC_SUCCESS;
828 else if (bootstrap == P2P_PBMA_PASSPHRASE_KEYPAD &&
829 dev->req_bootstrap_method == P2P_PBMA_PASSPHRASE_DISPLAY)
830 status = P2P_SC_SUCCESS;
831 else if (bootstrap == P2P_PBMA_NFC_TAG &&
832 dev->req_bootstrap_method == P2P_PBMA_NFC_READER)
833 status = P2P_SC_SUCCESS;
834 else if (bootstrap == P2P_PBMA_NFC_READER &&
835 dev->req_bootstrap_method == P2P_PBMA_NFC_TAG)
836 status = P2P_SC_SUCCESS;
837 else if (bootstrap == P2P_PBMA_QR_DISPLAY &&
838 dev->req_bootstrap_method == P2P_PBMA_QR_SCAN)
839 status = P2P_SC_SUCCESS;
840 else if (bootstrap == P2P_PBMA_QR_SCAN &&
841 dev->req_bootstrap_method == P2P_PBMA_QR_DISPLAY)
842 status = P2P_SC_SUCCESS;
843 else if (bootstrap == P2P_PBMA_OPPORTUNISTIC &&
844 dev->req_bootstrap_method == P2P_PBMA_OPPORTUNISTIC)
845 status = P2P_SC_SUCCESS;
846 else
847 status = P2P_SC_FAIL_INVALID_PARAMS;
848
849 wpa_printf(MSG_ERROR, "Bootstrap received %d", bootstrap);
850
Sunil Ravi79e6c4f2025-01-04 00:47:06 +0000851 if (status == P2P_SC_SUCCESS) {
852 dev->role = P2P_ROLE_PAIRING_RESPONDER;
853#ifdef CONFIG_PASN
854 p2p_pasn_initialize(p2p, dev, sa, rx_freq, false, true);
855#endif /* CONFIG_PASN */
856 }
Sunil Ravic0f5d412024-09-11 22:12:49 +0000857out:
858 /* Send PD Bootstrapping Response for the PD Request */
859 resp = p2p_build_prov_disc_bootstrap_resp(p2p, dev, msg->dialog_token,
860 status);
861 if (!resp)
862 return;
863
864 p2p_dbg(p2p, "Sending Provision Discovery Bootstrap Response");
865 if (rx_freq > 0)
866 freq = rx_freq;
867 else
868 freq = p2p_channel_to_freq(p2p->cfg->reg_class,
869 p2p->cfg->channel);
870 if (freq < 0) {
871 p2p_dbg(p2p, "Unknown operating class/channel");
872 wpabuf_free(resp);
873 return;
874 }
875 p2p->pending_action_state = P2P_PENDING_PD_RESPONSE;
876 if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr,
877 p2p->cfg->dev_addr, wpabuf_head(resp),
878 wpabuf_len(resp), 50) < 0)
879 p2p_dbg(p2p, "Failed to send Action frame");
880 else
881 p2p->send_action_in_progress = 1;
882
883 wpabuf_free(resp);
884}
885
886
887static void p2p_process_prov_disc_req(struct p2p_data *p2p,
888 struct p2p_message *msg, const u8 *sa,
889 const u8 *data, size_t len, int rx_freq)
890{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700891 struct p2p_device *dev;
892 int freq;
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800893 enum p2p_status_code reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700894 struct wpabuf *resp;
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800895 u32 adv_id = 0;
896 struct p2ps_advertisement *p2ps_adv = NULL;
897 u8 conncap = P2PS_SETUP_NEW;
898 u8 auto_accept = 0;
899 u32 session_id = 0;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800900 u8 session_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
901 u8 adv_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
902 const u8 *group_mac;
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800903 int passwd_id = DEV_PW_DEFAULT;
904 u16 config_methods;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800905 u16 allowed_config_methods = WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
906 struct p2ps_feature_capab resp_fcap = { 0, 0 };
907 struct p2ps_feature_capab *req_fcap = NULL;
908 u8 remote_conncap;
909 u16 method;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700910
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700911 p2p_dbg(p2p, "Received Provision Discovery Request from " MACSTR
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700912 " with config methods 0x%x (freq=%d)",
Sunil Ravic0f5d412024-09-11 22:12:49 +0000913 MAC2STR(sa), msg->wps_config_methods, rx_freq);
914 group_mac = msg->intended_addr;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700915
916 dev = p2p_get_device(p2p, sa);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800917 if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700918 p2p_dbg(p2p, "Provision Discovery Request from unknown peer "
919 MACSTR, MAC2STR(sa));
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800920
Sunil Ravic0f5d412024-09-11 22:12:49 +0000921 if (p2p_add_device(p2p, sa, rx_freq, NULL, 0, data, len, 0)) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700922 p2p_dbg(p2p, "Provision Discovery Request add device failed "
923 MACSTR, MAC2STR(sa));
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800924 goto out;
925 }
926
Hai Shalomc09ec812021-03-01 08:11:54 -0800927 dev = p2p_get_device(p2p, sa);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800928 if (!dev) {
Hai Shalomc09ec812021-03-01 08:11:54 -0800929 p2p_dbg(p2p,
930 "Provision Discovery device not found "
931 MACSTR, MAC2STR(sa));
932 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700933 }
Sunil Ravic0f5d412024-09-11 22:12:49 +0000934 } else if (msg->wfd_subelems) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700935 wpabuf_free(dev->info.wfd_subelems);
Sunil Ravic0f5d412024-09-11 22:12:49 +0000936 dev->info.wfd_subelems = wpabuf_dup(msg->wfd_subelems);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700937 }
938
Sunil Ravic0f5d412024-09-11 22:12:49 +0000939 p2p_update_peer_6ghz_capab(dev, msg);
Sunil Ravi38ad1ed2023-01-17 23:58:31 +0000940
Sunil Ravic0f5d412024-09-11 22:12:49 +0000941 if (!msg->adv_id) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800942 allowed_config_methods |= WPS_CONFIG_PUSHBUTTON;
Sunil Ravic0f5d412024-09-11 22:12:49 +0000943 if (!(msg->wps_config_methods & allowed_config_methods)) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800944 p2p_dbg(p2p,
945 "Unsupported Config Methods in Provision Discovery Request");
Dmitry Shmidt04949592012-07-19 12:16:46 -0700946 goto out;
947 }
Dmitry Shmidt04949592012-07-19 12:16:46 -0700948
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800949 /* Legacy (non-P2PS) - Unknown groups allowed for P2PS */
Sunil Ravic0f5d412024-09-11 22:12:49 +0000950 if (msg->group_id) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800951 size_t i;
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800952
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800953 for (i = 0; i < p2p->num_groups; i++) {
954 if (p2p_group_is_group_id_match(
955 p2p->groups[i],
Sunil Ravic0f5d412024-09-11 22:12:49 +0000956 msg->group_id, msg->group_id_len))
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800957 break;
958 }
959 if (i == p2p->num_groups) {
960 p2p_dbg(p2p,
961 "PD request for unknown P2P Group ID - reject");
962 goto out;
963 }
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800964 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800965 } else {
966 allowed_config_methods |= WPS_CONFIG_P2PS;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700967
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800968 /*
969 * Set adv_id here, so in case of an error, a P2PS PD Response
970 * will be sent.
971 */
Sunil Ravic0f5d412024-09-11 22:12:49 +0000972 adv_id = WPA_GET_LE32(msg->adv_id);
973 if (p2ps_validate_pd_req(p2p, msg, sa) < 0) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800974 reject = P2P_SC_FAIL_INVALID_PARAMS;
975 goto out;
976 }
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800977
Sunil Ravic0f5d412024-09-11 22:12:49 +0000978 req_fcap = (struct p2ps_feature_capab *) msg->feature_cap;
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800979
Sunil Ravic0f5d412024-09-11 22:12:49 +0000980 os_memcpy(session_mac, msg->session_mac, ETH_ALEN);
981 os_memcpy(adv_mac, msg->adv_mac, ETH_ALEN);
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800982
Sunil Ravic0f5d412024-09-11 22:12:49 +0000983 session_id = WPA_GET_LE32(msg->session_id);
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800984
Sunil Ravic0f5d412024-09-11 22:12:49 +0000985 if (msg->conn_cap)
986 conncap = *msg->conn_cap;
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800987
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800988 /*
989 * We need to verify a P2PS config methog in an initial PD
990 * request or in a follow-on PD request with the status
991 * SUCCESS_DEFERRED.
992 */
Sunil Ravic0f5d412024-09-11 22:12:49 +0000993 if ((!msg->status || *msg->status == P2P_SC_SUCCESS_DEFERRED) &&
994 !(msg->wps_config_methods & allowed_config_methods)) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800995 p2p_dbg(p2p,
996 "Unsupported Config Methods in Provision Discovery Request");
997 goto out;
998 }
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800999
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001000 /*
1001 * TODO: since we don't support multiple PD, reject PD request
1002 * if we are in the middle of P2PS PD with some other peer
1003 */
1004 }
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001005
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001006 dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
1007 P2P_DEV_PD_PEER_KEYPAD |
1008 P2P_DEV_PD_PEER_P2PS);
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001009
Sunil Ravic0f5d412024-09-11 22:12:49 +00001010 if (msg->wps_config_methods & WPS_CONFIG_DISPLAY) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001011 p2p_dbg(p2p, "Peer " MACSTR
1012 " requested us to show a PIN on display", MAC2STR(sa));
1013 dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
1014 passwd_id = DEV_PW_USER_SPECIFIED;
Sunil Ravic0f5d412024-09-11 22:12:49 +00001015 } else if (msg->wps_config_methods & WPS_CONFIG_KEYPAD) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001016 p2p_dbg(p2p, "Peer " MACSTR
1017 " requested us to write its PIN using keypad",
1018 MAC2STR(sa));
1019 dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
1020 passwd_id = DEV_PW_REGISTRAR_SPECIFIED;
Sunil Ravic0f5d412024-09-11 22:12:49 +00001021 } else if (msg->wps_config_methods & WPS_CONFIG_P2PS) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001022 p2p_dbg(p2p, "Peer " MACSTR " requesting P2PS PIN",
1023 MAC2STR(sa));
1024 dev->flags |= P2P_DEV_PD_PEER_P2PS;
1025 passwd_id = DEV_PW_P2PS_DEFAULT;
1026 }
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001027
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001028 /* Remove stale persistent groups */
1029 if (p2p->cfg->remove_stale_groups) {
1030 p2p->cfg->remove_stale_groups(
1031 p2p->cfg->cb_ctx, dev->info.p2p_device_addr,
Sunil Ravic0f5d412024-09-11 22:12:49 +00001032 msg->persistent_dev,
1033 msg->persistent_ssid, msg->persistent_ssid_len);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001034 }
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001035
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001036 reject = P2P_SC_SUCCESS;
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001037
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001038 /*
1039 * End of a legacy P2P PD Request processing, from this point continue
1040 * with P2PS one.
1041 */
Sunil Ravic0f5d412024-09-11 22:12:49 +00001042 if (!msg->adv_id)
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001043 goto out;
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001044
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001045 remote_conncap = conncap;
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001046
Sunil Ravic0f5d412024-09-11 22:12:49 +00001047 if (!msg->status) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001048 unsigned int forced_freq, pref_freq;
1049
Sunil Ravic0f5d412024-09-11 22:12:49 +00001050 if (!ether_addr_equal(p2p->cfg->dev_addr, msg->adv_mac)) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001051 p2p_dbg(p2p,
1052 "P2PS PD adv mac does not match the local one");
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001053 reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
1054 goto out;
1055 }
1056
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001057 p2ps_adv = p2p_service_p2ps_id(p2p, adv_id);
1058 if (!p2ps_adv) {
1059 p2p_dbg(p2p, "P2PS PD invalid adv_id=0x%X", adv_id);
1060 reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
1061 goto out;
1062 }
1063 p2p_dbg(p2p, "adv_id: 0x%X, p2ps_adv: %p", adv_id, p2ps_adv);
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001064
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001065 auto_accept = p2ps_adv->auto_accept;
1066 conncap = p2p->cfg->p2ps_group_capability(p2p->cfg->cb_ctx,
1067 conncap, auto_accept,
1068 &forced_freq,
1069 &pref_freq);
1070
1071 p2p_dbg(p2p, "Conncap: local:%d remote:%d result:%d",
1072 auto_accept, remote_conncap, conncap);
1073
1074 p2p_prepare_channel(p2p, dev, forced_freq, pref_freq, 0);
1075
1076 resp_fcap.cpt = p2ps_own_preferred_cpt(p2ps_adv->cpt_priority,
1077 req_fcap->cpt);
1078
1079 p2p_dbg(p2p, "cpt: service:0x%x remote:0x%x result:0x%x",
1080 p2ps_adv->cpt_mask, req_fcap->cpt, resp_fcap.cpt);
1081
1082 if (!resp_fcap.cpt) {
1083 p2p_dbg(p2p,
1084 "Incompatible P2PS feature capability CPT bitmask");
1085 reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
1086 } else if (p2ps_adv->config_methods &&
Sunil Ravic0f5d412024-09-11 22:12:49 +00001087 !(msg->wps_config_methods &
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001088 p2ps_adv->config_methods)) {
1089 p2p_dbg(p2p,
1090 "Unsupported config methods in Provision Discovery Request (own=0x%x peer=0x%x)",
1091 p2ps_adv->config_methods,
Sunil Ravic0f5d412024-09-11 22:12:49 +00001092 msg->wps_config_methods);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001093 reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
1094 } else if (!p2ps_adv->state) {
1095 p2p_dbg(p2p, "P2PS state unavailable");
1096 reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
1097 } else if (!conncap) {
1098 p2p_dbg(p2p, "Conncap resolution failed");
1099 reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
1100 }
1101
Sunil Ravic0f5d412024-09-11 22:12:49 +00001102 if (msg->wps_config_methods & WPS_CONFIG_KEYPAD) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001103 p2p_dbg(p2p, "Keypad - always defer");
1104 auto_accept = 0;
1105 }
1106
1107 if ((remote_conncap & (P2PS_SETUP_NEW | P2PS_SETUP_CLIENT) ||
Sunil Ravic0f5d412024-09-11 22:12:49 +00001108 msg->persistent_dev) && conncap != P2PS_SETUP_NEW &&
1109 msg->channel_list && msg->channel_list_len &&
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001110 p2p_peer_channels_check(p2p, &p2p->channels, dev,
Sunil Ravic0f5d412024-09-11 22:12:49 +00001111 msg->channel_list,
1112 msg->channel_list_len) < 0) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001113 p2p_dbg(p2p,
1114 "No common channels - force deferred flow");
1115 auto_accept = 0;
1116 }
1117
1118 if (((remote_conncap & P2PS_SETUP_GROUP_OWNER) ||
Sunil Ravic0f5d412024-09-11 22:12:49 +00001119 msg->persistent_dev) && msg->operating_channel) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001120 struct p2p_channels intersect;
1121
1122 /*
1123 * There are cases where only the operating channel is
1124 * provided. This requires saving the channel as the
1125 * supported channel list, and verifying that it is
1126 * supported.
1127 */
1128 if (dev->channels.reg_classes == 0 ||
1129 !p2p_channels_includes(&dev->channels,
Sunil Ravic0f5d412024-09-11 22:12:49 +00001130 msg->operating_channel[3],
1131 msg->operating_channel[4])) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001132 struct p2p_channels *ch = &dev->channels;
1133
1134 os_memset(ch, 0, sizeof(*ch));
1135 ch->reg_class[0].reg_class =
Sunil Ravic0f5d412024-09-11 22:12:49 +00001136 msg->operating_channel[3];
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001137 ch->reg_class[0].channel[0] =
Sunil Ravic0f5d412024-09-11 22:12:49 +00001138 msg->operating_channel[4];
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001139 ch->reg_class[0].channels = 1;
1140 ch->reg_classes = 1;
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001141 }
1142
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001143 p2p_channels_intersect(&p2p->channels, &dev->channels,
1144 &intersect);
1145
1146 if (intersect.reg_classes == 0) {
1147 p2p_dbg(p2p,
1148 "No common channels - force deferred flow");
1149 auto_accept = 0;
1150 }
1151 }
1152
1153 if (auto_accept || reject != P2P_SC_SUCCESS) {
1154 struct p2ps_provision *tmp;
1155
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001156 if (p2ps_setup_p2ps_prov(p2p, adv_id, session_id,
Sunil Ravic0f5d412024-09-11 22:12:49 +00001157 msg->wps_config_methods,
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001158 session_mac, adv_mac) < 0) {
1159 reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
1160 goto out;
1161 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001162
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001163 tmp = p2p->p2ps_prov;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001164 tmp->force_freq = forced_freq;
1165 tmp->pref_freq = pref_freq;
1166 if (conncap) {
1167 tmp->conncap = conncap;
1168 tmp->status = P2P_SC_SUCCESS;
1169 } else {
1170 tmp->conncap = auto_accept;
1171 tmp->status = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001172 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001173
1174 if (reject != P2P_SC_SUCCESS)
1175 goto out;
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001176 }
1177 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001178
Sunil Ravic0f5d412024-09-11 22:12:49 +00001179 if (!msg->status && !auto_accept &&
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001180 (!p2p->p2ps_prov || p2p->p2ps_prov->adv_id != adv_id)) {
1181 struct p2ps_provision *tmp;
1182
1183 if (!conncap) {
1184 reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
1185 goto out;
1186 }
1187
1188 if (p2ps_setup_p2ps_prov(p2p, adv_id, session_id,
Sunil Ravic0f5d412024-09-11 22:12:49 +00001189 msg->wps_config_methods,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001190 session_mac, adv_mac) < 0) {
1191 reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
1192 goto out;
1193 }
1194 tmp = p2p->p2ps_prov;
1195 reject = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
1196 tmp->status = reject;
1197 }
1198
1199 /* Not a P2PS Follow-on PD */
Sunil Ravic0f5d412024-09-11 22:12:49 +00001200 if (!msg->status)
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001201 goto out;
1202
Sunil Ravic0f5d412024-09-11 22:12:49 +00001203 if (*msg->status && *msg->status != P2P_SC_SUCCESS_DEFERRED) {
1204 reject = *msg->status;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001205 goto out;
1206 }
1207
Sunil Ravic0f5d412024-09-11 22:12:49 +00001208 if (*msg->status != P2P_SC_SUCCESS_DEFERRED || !p2p->p2ps_prov)
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001209 goto out;
1210
1211 if (p2p->p2ps_prov->adv_id != adv_id ||
Sunil Ravic0f5d412024-09-11 22:12:49 +00001212 !ether_addr_equal(p2p->p2ps_prov->adv_mac, msg->adv_mac)) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001213 p2p_dbg(p2p,
1214 "P2PS Follow-on PD with mismatch Advertisement ID/MAC");
1215 goto out;
1216 }
1217
1218 if (p2p->p2ps_prov->session_id != session_id ||
Sunil Ravic0f5d412024-09-11 22:12:49 +00001219 !ether_addr_equal(p2p->p2ps_prov->session_mac, msg->session_mac)) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001220 p2p_dbg(p2p, "P2PS Follow-on PD with mismatch Session ID/MAC");
1221 goto out;
1222 }
1223
1224 method = p2p->p2ps_prov->method;
1225
1226 conncap = p2p->cfg->p2ps_group_capability(p2p->cfg->cb_ctx,
1227 remote_conncap,
1228 p2p->p2ps_prov->conncap,
1229 &p2p->p2ps_prov->force_freq,
1230 &p2p->p2ps_prov->pref_freq);
1231
1232 resp_fcap.cpt = p2ps_own_preferred_cpt(p2p->p2ps_prov->cpt_priority,
1233 req_fcap->cpt);
1234
1235 p2p_dbg(p2p, "cpt: local:0x%x remote:0x%x result:0x%x",
1236 p2p->p2ps_prov->cpt_mask, req_fcap->cpt, resp_fcap.cpt);
1237
1238 p2p_prepare_channel(p2p, dev, p2p->p2ps_prov->force_freq,
1239 p2p->p2ps_prov->pref_freq, 0);
1240
1241 /*
1242 * Ensure that if we asked for PIN originally, our method is consistent
1243 * with original request.
1244 */
1245 if (method & WPS_CONFIG_DISPLAY)
1246 method = WPS_CONFIG_KEYPAD;
1247 else if (method & WPS_CONFIG_KEYPAD)
1248 method = WPS_CONFIG_DISPLAY;
1249
Sunil Ravic0f5d412024-09-11 22:12:49 +00001250 if (!conncap || !(msg->wps_config_methods & method)) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001251 /*
1252 * Reject this "Deferred Accept*
1253 * if incompatible conncap or method
1254 */
1255 reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
1256 } else if (!resp_fcap.cpt) {
1257 p2p_dbg(p2p,
1258 "Incompatible P2PS feature capability CPT bitmask");
1259 reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
1260 } else if ((remote_conncap & (P2PS_SETUP_NEW | P2PS_SETUP_CLIENT) ||
Sunil Ravic0f5d412024-09-11 22:12:49 +00001261 msg->persistent_dev) && conncap != P2PS_SETUP_NEW &&
1262 msg->channel_list && msg->channel_list_len &&
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001263 p2p_peer_channels_check(p2p, &p2p->channels, dev,
Sunil Ravic0f5d412024-09-11 22:12:49 +00001264 msg->channel_list,
1265 msg->channel_list_len) < 0) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001266 p2p_dbg(p2p,
1267 "No common channels in Follow-On Provision Discovery Request");
1268 reject = P2P_SC_FAIL_NO_COMMON_CHANNELS;
1269 } else {
1270 reject = P2P_SC_SUCCESS;
1271 }
1272
1273 dev->oper_freq = 0;
1274 if (reject == P2P_SC_SUCCESS || reject == P2P_SC_SUCCESS_DEFERRED) {
1275 u8 tmp;
1276
Sunil Ravic0f5d412024-09-11 22:12:49 +00001277 if (msg->operating_channel)
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001278 dev->oper_freq =
Sunil Ravic0f5d412024-09-11 22:12:49 +00001279 p2p_channel_to_freq(msg->operating_channel[3],
1280 msg->operating_channel[4]);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001281
1282 if ((conncap & P2PS_SETUP_GROUP_OWNER) &&
1283 p2p_go_select_channel(p2p, dev, &tmp) < 0)
1284 reject = P2P_SC_FAIL_NO_COMMON_CHANNELS;
1285 }
1286
1287 p2p->p2ps_prov->status = reject;
1288 p2p->p2ps_prov->conncap = conncap;
1289
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001290out:
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001291 if (reject == P2P_SC_SUCCESS ||
1292 reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE)
Sunil Ravic0f5d412024-09-11 22:12:49 +00001293 config_methods = msg->wps_config_methods;
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001294 else
1295 config_methods = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001296
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001297 /*
1298 * Send PD Response for an initial PD Request or for follow-on
1299 * PD Request with P2P_SC_SUCCESS_DEFERRED status.
1300 */
Sunil Ravic0f5d412024-09-11 22:12:49 +00001301 if (!msg->status || *msg->status == P2P_SC_SUCCESS_DEFERRED) {
1302 resp = p2p_build_prov_disc_resp(p2p, dev, msg->dialog_token,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001303 reject, config_methods, adv_id,
Sunil Ravic0f5d412024-09-11 22:12:49 +00001304 msg->group_id,
1305 msg->group_id_len,
1306 msg->persistent_ssid,
1307 msg->persistent_ssid_len,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001308 (const u8 *) &resp_fcap,
1309 sizeof(resp_fcap));
Sunil Ravic0f5d412024-09-11 22:12:49 +00001310 if (!resp)
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001311 return;
Sunil Ravic0f5d412024-09-11 22:12:49 +00001312
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001313 p2p_dbg(p2p, "Sending Provision Discovery Response");
1314 if (rx_freq > 0)
1315 freq = rx_freq;
1316 else
1317 freq = p2p_channel_to_freq(p2p->cfg->reg_class,
1318 p2p->cfg->channel);
1319 if (freq < 0) {
1320 p2p_dbg(p2p, "Unknown regulatory class/channel");
1321 wpabuf_free(resp);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001322 return;
1323 }
1324 p2p->pending_action_state = P2P_PENDING_PD_RESPONSE;
1325 if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr,
1326 p2p->cfg->dev_addr,
1327 wpabuf_head(resp), wpabuf_len(resp),
Dmitry Shmidtb97e4282016-02-08 10:16:07 -08001328 50) < 0)
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001329 p2p_dbg(p2p, "Failed to send Action frame");
1330 else
1331 p2p->send_action_in_progress = 1;
1332
1333 wpabuf_free(resp);
1334 }
1335
Sunil Ravic0f5d412024-09-11 22:12:49 +00001336 if (!dev)
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001337 return;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001338
1339 freq = 0;
1340 if (reject == P2P_SC_SUCCESS && conncap == P2PS_SETUP_GROUP_OWNER) {
1341 freq = p2p_channel_to_freq(p2p->op_reg_class,
1342 p2p->op_channel);
1343 if (freq < 0)
1344 freq = 0;
1345 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001346
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001347 if (!p2p->cfg->p2ps_prov_complete) {
1348 /* Don't emit anything */
Sunil Ravic0f5d412024-09-11 22:12:49 +00001349 } else if (msg->status && *msg->status != P2P_SC_SUCCESS &&
1350 *msg->status != P2P_SC_SUCCESS_DEFERRED) {
1351 reject = *msg->status;
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001352 p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, reject,
1353 sa, adv_mac, session_mac,
1354 NULL, adv_id, session_id,
Sunil Ravic0f5d412024-09-11 22:12:49 +00001355 0, 0, msg->persistent_ssid,
1356 msg->persistent_ssid_len,
Dmitry Shmidtde47be72016-01-07 12:52:55 -08001357 0, 0, NULL, NULL, 0, freq,
1358 NULL, 0);
Sunil Ravic0f5d412024-09-11 22:12:49 +00001359 } else if (msg->status && *msg->status == P2P_SC_SUCCESS_DEFERRED &&
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001360 p2p->p2ps_prov) {
1361 p2p->p2ps_prov->status = reject;
1362 p2p->p2ps_prov->conncap = conncap;
1363
1364 if (reject != P2P_SC_SUCCESS)
1365 p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, reject,
1366 sa, adv_mac, session_mac,
1367 NULL, adv_id,
1368 session_id, conncap, 0,
Sunil Ravic0f5d412024-09-11 22:12:49 +00001369 msg->persistent_ssid,
1370 msg->persistent_ssid_len,
1371 0, 0, NULL, NULL, 0, freq,
Dmitry Shmidtde47be72016-01-07 12:52:55 -08001372 NULL, 0);
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001373 else
1374 p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx,
Sunil Ravic0f5d412024-09-11 22:12:49 +00001375 *msg->status,
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001376 sa, adv_mac, session_mac,
1377 group_mac, adv_id,
1378 session_id, conncap,
1379 passwd_id,
Sunil Ravic0f5d412024-09-11 22:12:49 +00001380 msg->persistent_ssid,
1381 msg->persistent_ssid_len,
1382 0, 0, NULL,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001383 (const u8 *) &resp_fcap,
Dmitry Shmidtde47be72016-01-07 12:52:55 -08001384 sizeof(resp_fcap), freq,
1385 NULL, 0);
Sunil Ravic0f5d412024-09-11 22:12:49 +00001386 } else if (msg->status && p2p->p2ps_prov) {
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001387 p2p->p2ps_prov->status = P2P_SC_SUCCESS;
Sunil Ravic0f5d412024-09-11 22:12:49 +00001388 p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, *msg->status, sa,
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001389 adv_mac, session_mac, group_mac,
1390 adv_id, session_id, conncap,
1391 passwd_id,
Sunil Ravic0f5d412024-09-11 22:12:49 +00001392 msg->persistent_ssid,
1393 msg->persistent_ssid_len,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001394 0, 0, NULL,
1395 (const u8 *) &resp_fcap,
Dmitry Shmidtde47be72016-01-07 12:52:55 -08001396 sizeof(resp_fcap), freq, NULL, 0);
Sunil Ravic0f5d412024-09-11 22:12:49 +00001397 } else if (msg->status) {
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001398 } else if (auto_accept && reject == P2P_SC_SUCCESS) {
1399 p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, P2P_SC_SUCCESS,
1400 sa, adv_mac, session_mac,
1401 group_mac, adv_id, session_id,
1402 conncap, passwd_id,
Sunil Ravic0f5d412024-09-11 22:12:49 +00001403 msg->persistent_ssid,
1404 msg->persistent_ssid_len,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001405 0, 0, NULL,
1406 (const u8 *) &resp_fcap,
Dmitry Shmidtde47be72016-01-07 12:52:55 -08001407 sizeof(resp_fcap), freq,
Sunil Ravic0f5d412024-09-11 22:12:49 +00001408 msg->group_id ?
1409 msg->group_id + ETH_ALEN : NULL,
1410 msg->group_id ?
1411 msg->group_id_len - ETH_ALEN : 0);
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001412 } else if (reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE &&
Sunil Ravic0f5d412024-09-11 22:12:49 +00001413 (!msg->session_info || !msg->session_info_len)) {
1414 p2p->p2ps_prov->method = msg->wps_config_methods;
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001415
1416 p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, P2P_SC_SUCCESS,
1417 sa, adv_mac, session_mac,
1418 group_mac, adv_id, session_id,
1419 conncap, passwd_id,
Sunil Ravic0f5d412024-09-11 22:12:49 +00001420 msg->persistent_ssid,
1421 msg->persistent_ssid_len,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001422 0, 1, NULL,
1423 (const u8 *) &resp_fcap,
Dmitry Shmidtde47be72016-01-07 12:52:55 -08001424 sizeof(resp_fcap), freq, NULL, 0);
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001425 } else if (reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) {
Sunil Ravic0f5d412024-09-11 22:12:49 +00001426 size_t buf_len = msg->session_info_len;
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001427 char *buf = os_malloc(2 * buf_len + 1);
1428
1429 if (buf) {
Sunil Ravic0f5d412024-09-11 22:12:49 +00001430 p2p->p2ps_prov->method = msg->wps_config_methods;
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001431
Sunil Ravic0f5d412024-09-11 22:12:49 +00001432 utf8_escape((char *) msg->session_info, buf_len,
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001433 buf, 2 * buf_len + 1);
1434
1435 p2p->cfg->p2ps_prov_complete(
1436 p2p->cfg->cb_ctx, P2P_SC_SUCCESS, sa,
1437 adv_mac, session_mac, group_mac, adv_id,
1438 session_id, conncap, passwd_id,
Sunil Ravic0f5d412024-09-11 22:12:49 +00001439 msg->persistent_ssid, msg->persistent_ssid_len,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001440 0, 1, buf,
1441 (const u8 *) &resp_fcap, sizeof(resp_fcap),
Dmitry Shmidtde47be72016-01-07 12:52:55 -08001442 freq, NULL, 0);
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001443
1444 os_free(buf);
1445 }
1446 }
1447
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001448 /*
1449 * prov_disc_req callback is used to generate P2P-PROV-DISC-ENTER-PIN,
1450 * P2P-PROV-DISC-SHOW-PIN, and P2P-PROV-DISC-PBC-REQ events.
1451 * Call it either on legacy P2P PD or on P2PS PD only if we need to
1452 * enter/show PIN.
1453 *
1454 * The callback is called in the following cases:
1455 * 1. Legacy P2P PD request, response status SUCCESS
1456 * 2. P2PS advertiser, method: DISPLAY, autoaccept: TRUE,
1457 * response status: SUCCESS
1458 * 3. P2PS advertiser, method DISPLAY, autoaccept: FALSE,
1459 * response status: INFO_CURRENTLY_UNAVAILABLE
1460 * 4. P2PS advertiser, method: KEYPAD, autoaccept==any,
1461 * response status: INFO_CURRENTLY_UNAVAILABLE
1462 * 5. P2PS follow-on with SUCCESS_DEFERRED,
1463 * advertiser role: DISPLAY, autoaccept: FALSE,
1464 * seeker: KEYPAD, response status: SUCCESS
1465 */
1466 if (p2p->cfg->prov_disc_req &&
Sunil Ravic0f5d412024-09-11 22:12:49 +00001467 ((reject == P2P_SC_SUCCESS && !msg->adv_id) ||
1468 (!msg->status &&
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001469 (reject == P2P_SC_SUCCESS ||
1470 reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) &&
1471 passwd_id == DEV_PW_USER_SPECIFIED) ||
Sunil Ravic0f5d412024-09-11 22:12:49 +00001472 (!msg->status &&
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001473 reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE &&
1474 passwd_id == DEV_PW_REGISTRAR_SPECIFIED) ||
1475 (reject == P2P_SC_SUCCESS &&
Sunil Ravic0f5d412024-09-11 22:12:49 +00001476 msg->status && *msg->status == P2P_SC_SUCCESS_DEFERRED &&
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001477 passwd_id == DEV_PW_REGISTRAR_SPECIFIED))) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001478 const u8 *dev_addr = sa;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001479
Sunil Ravic0f5d412024-09-11 22:12:49 +00001480 if (msg->p2p_device_addr)
1481 dev_addr = msg->p2p_device_addr;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001482 p2p->cfg->prov_disc_req(p2p->cfg->cb_ctx, sa,
Sunil Ravic0f5d412024-09-11 22:12:49 +00001483 msg->wps_config_methods,
1484 dev_addr, msg->pri_dev_type,
1485 msg->device_name, msg->config_methods,
1486 msg->capability ? msg->capability[0] :
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001487 0,
Sunil Ravic0f5d412024-09-11 22:12:49 +00001488 msg->capability ? msg->capability[1] :
1489 0,
1490 msg->group_id, msg->group_id_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001491 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001492
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001493 if (reject != P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE)
1494 p2ps_prov_free(p2p);
1495
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001496 if (reject == P2P_SC_SUCCESS) {
1497 switch (config_methods) {
1498 case WPS_CONFIG_DISPLAY:
1499 dev->wps_prov_info = WPS_CONFIG_KEYPAD;
1500 break;
1501 case WPS_CONFIG_KEYPAD:
1502 dev->wps_prov_info = WPS_CONFIG_DISPLAY;
1503 break;
1504 case WPS_CONFIG_PUSHBUTTON:
1505 dev->wps_prov_info = WPS_CONFIG_PUSHBUTTON;
1506 break;
1507 case WPS_CONFIG_P2PS:
1508 dev->wps_prov_info = WPS_CONFIG_P2PS;
1509 break;
1510 default:
1511 dev->wps_prov_info = 0;
1512 break;
1513 }
1514
Sunil Ravic0f5d412024-09-11 22:12:49 +00001515 if (msg->intended_addr)
1516 os_memcpy(dev->interface_addr, msg->intended_addr,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001517 ETH_ALEN);
1518 }
Sunil Ravic0f5d412024-09-11 22:12:49 +00001519}
1520
1521
1522void p2p_handle_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
1523 const u8 *data, size_t len, int rx_freq)
1524{
1525 struct p2p_message msg;
1526
1527 if (p2p_parse(data, len, &msg))
1528 return;
1529
1530 if (msg.pcea_info && msg.pbma_info)
1531 p2p_process_prov_disc_bootstrap_req(p2p, &msg, sa, data + 1,
1532 len - 1, rx_freq);
1533 else
1534 p2p_process_prov_disc_req(p2p, &msg, sa, data + 1, len - 1,
1535 rx_freq);
1536
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001537 p2p_parse_free(&msg);
1538}
1539
1540
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001541static int p2p_validate_p2ps_pd_resp(struct p2p_data *p2p,
1542 struct p2p_message *msg)
1543{
1544 u8 conn_cap_go = 0;
1545 u8 conn_cap_cli = 0;
1546 u32 session_id;
1547 u32 adv_id;
1548
1549#define P2PS_PD_RESP_CHECK(_val, _attr) \
1550 do { \
1551 if ((_val) && !msg->_attr) { \
1552 p2p_dbg(p2p, "P2PS PD Response missing " #_attr); \
1553 return -1; \
1554 } \
1555 } while (0)
1556
1557 P2PS_PD_RESP_CHECK(1, status);
1558 P2PS_PD_RESP_CHECK(1, adv_id);
1559 P2PS_PD_RESP_CHECK(1, adv_mac);
1560 P2PS_PD_RESP_CHECK(1, capability);
1561 P2PS_PD_RESP_CHECK(1, p2p_device_info);
1562 P2PS_PD_RESP_CHECK(1, session_id);
1563 P2PS_PD_RESP_CHECK(1, session_mac);
1564 P2PS_PD_RESP_CHECK(1, feature_cap);
1565
1566 session_id = WPA_GET_LE32(msg->session_id);
1567 adv_id = WPA_GET_LE32(msg->adv_id);
1568
1569 if (p2p->p2ps_prov->session_id != session_id) {
1570 p2p_dbg(p2p,
1571 "Ignore PD Response with unexpected Session ID");
1572 return -1;
1573 }
1574
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001575 if (!ether_addr_equal(p2p->p2ps_prov->session_mac, msg->session_mac)) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001576 p2p_dbg(p2p,
1577 "Ignore PD Response with unexpected Session MAC");
1578 return -1;
1579 }
1580
1581 if (p2p->p2ps_prov->adv_id != adv_id) {
1582 p2p_dbg(p2p,
1583 "Ignore PD Response with unexpected Advertisement ID");
1584 return -1;
1585 }
1586
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001587 if (!ether_addr_equal(p2p->p2ps_prov->adv_mac, msg->adv_mac)) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001588 p2p_dbg(p2p,
1589 "Ignore PD Response with unexpected Advertisement MAC");
1590 return -1;
1591 }
1592
1593 if (msg->listen_channel) {
1594 p2p_dbg(p2p,
1595 "Ignore malformed PD Response - unexpected Listen Channel");
1596 return -1;
1597 }
1598
1599 if (*msg->status == P2P_SC_SUCCESS &&
1600 !(!!msg->conn_cap ^ !!msg->persistent_dev)) {
1601 p2p_dbg(p2p,
1602 "Ignore malformed PD Response - either conn_cap or persistent group should be present");
1603 return -1;
1604 }
1605
1606 if (msg->persistent_dev && *msg->status != P2P_SC_SUCCESS) {
1607 p2p_dbg(p2p,
1608 "Ignore malformed PD Response - persistent group is present, but the status isn't success");
1609 return -1;
1610 }
1611
1612 if (msg->conn_cap) {
1613 conn_cap_go = *msg->conn_cap == P2PS_SETUP_GROUP_OWNER;
1614 conn_cap_cli = *msg->conn_cap == P2PS_SETUP_CLIENT;
1615 }
1616
1617 P2PS_PD_RESP_CHECK(msg->persistent_dev || conn_cap_go || conn_cap_cli,
1618 channel_list);
1619 P2PS_PD_RESP_CHECK(msg->persistent_dev || conn_cap_go || conn_cap_cli,
1620 config_timeout);
1621
1622 P2PS_PD_RESP_CHECK(conn_cap_go, group_id);
1623 P2PS_PD_RESP_CHECK(conn_cap_go, intended_addr);
1624 P2PS_PD_RESP_CHECK(conn_cap_go, operating_channel);
1625 /*
1626 * TODO: Also validate that operating channel is present if the device
1627 * is a GO in a persistent group. We can't do it here since we don't
1628 * know what is the role of the peer. It should be probably done in
1629 * p2ps_prov_complete callback, but currently operating channel isn't
1630 * passed to it.
1631 */
1632
1633#undef P2PS_PD_RESP_CHECK
1634
1635 return 0;
1636}
1637
1638
Sunil Ravic0f5d412024-09-11 22:12:49 +00001639static void p2p_process_prov_disc_bootstrap_resp(struct p2p_data *p2p,
1640 struct p2p_message *msg,
1641 const u8 *sa, const u8 *data,
1642 size_t len, int rx_freq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001643{
Sunil Ravic0f5d412024-09-11 22:12:49 +00001644 struct p2p_device *dev;
1645 enum p2p_status_code status = P2P_SC_SUCCESS;
1646 size_t cookie_len = 0;
1647 const u8 *pos, *cookie;
1648 u16 comeback_after;
1649
1650 /* Parse the P2P status present */
1651 if (msg->status)
1652 status = *msg->status;
1653
1654 p2p_dbg(p2p, "Received Provision Discovery Bootstrap Response from "
1655 MACSTR, MAC2STR(sa));
1656
1657 dev = p2p_get_device(p2p, sa);
1658 if (!dev || !dev->req_bootstrap_method) {
1659 p2p_dbg(p2p, "Ignore Provision Discovery Response from " MACSTR
1660 " with no pending request", MAC2STR(sa));
1661 return;
1662 }
1663
1664 p2p_update_peer_6ghz_capab(dev, msg);
1665
1666 if (dev->dialog_token != msg->dialog_token) {
1667 p2p_dbg(p2p,
1668 "Ignore Provision Discovery Response with unexpected Dialog Token %u (expected %u)",
1669 msg->dialog_token, dev->dialog_token);
1670 return;
1671 }
1672
1673 if (p2p->pending_action_state == P2P_PENDING_PD) {
1674 os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
1675 p2p->pending_action_state = P2P_NO_PENDING_ACTION;
1676 }
1677
1678 os_free(dev->bootstrap_params);
1679 dev->bootstrap_params = NULL;
1680
1681 /* If the response is from the peer to whom a user initiated request
1682 * was sent earlier, we reset that state information here. */
1683 if (p2p->user_initiated_pd &&
1684 ether_addr_equal(p2p->pending_pd_devaddr, sa))
1685 p2p_reset_pending_pd(p2p);
1686
1687 if (status == P2P_SC_COMEBACK) {
1688 /* PBMA comeback response */
1689 pos = msg->pbma_info;
1690 if (msg->pbma_info_len < 2 + 1)
1691 return;
1692 comeback_after = WPA_GET_LE16(pos);
1693 pos += 2;
1694 cookie_len = *pos++;
1695 if (msg->pbma_info_len < 2 + 1 + cookie_len) {
1696 p2p_dbg(p2p, "Truncated PBMA");
1697 return;
1698 }
1699 cookie = pos;
1700
1701 dev->bootstrap_params =
1702 os_zalloc(sizeof(struct p2p_bootstrap_params));
1703 if (!dev->bootstrap_params)
1704 return;
1705 dev->bootstrap_params->cookie_len = cookie_len;
1706 os_memcpy(dev->bootstrap_params->cookie, cookie, cookie_len);
1707 dev->bootstrap_params->comeback_after = comeback_after;
1708 dev->bootstrap_params->bootstrap_method =
1709 dev->req_bootstrap_method;
1710 dev->bootstrap_params->status = status;
1711
1712 p2p->cfg->register_bootstrap_comeback(p2p->cfg->cb_ctx, sa,
1713 comeback_after);
1714 p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
1715 return;
1716 }
1717
1718 p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
1719 if (dev->flags & P2P_DEV_PD_BEFORE_GO_NEG)
1720 dev->flags &= ~P2P_DEV_PD_BEFORE_GO_NEG;
1721
1722 if (p2p->cfg->bootstrap_completed)
1723 p2p->cfg->bootstrap_completed(p2p->cfg->cb_ctx, sa, status,
1724 rx_freq);
1725}
1726
1727
1728static void p2p_process_prov_disc_resp(struct p2p_data *p2p,
1729 struct p2p_message *msg, const u8 *sa,
1730 const u8 *data, size_t len)
1731{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001732 struct p2p_device *dev;
Dmitry Shmidt444d5672013-04-01 13:08:44 -07001733 u16 report_config_methods = 0, req_config_methods;
Sunil Ravic0f5d412024-09-11 22:12:49 +00001734 enum p2p_status_code status = P2P_SC_SUCCESS;
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001735 u32 adv_id = 0;
1736 u8 conncap = P2PS_SETUP_NEW;
1737 u8 adv_mac[ETH_ALEN];
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001738 const u8 *group_mac;
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001739 int passwd_id = DEV_PW_DEFAULT;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001740 int p2ps_seeker;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001741
Sunil Ravic0f5d412024-09-11 22:12:49 +00001742 if (p2p->p2ps_prov && p2p_validate_p2ps_pd_resp(p2p, msg))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001743 return;
1744
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001745 /* Parse the P2PS members present */
Sunil Ravic0f5d412024-09-11 22:12:49 +00001746 if (msg->status)
1747 status = *msg->status;
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001748
Sunil Ravic0f5d412024-09-11 22:12:49 +00001749 group_mac = msg->intended_addr;
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001750
Sunil Ravic0f5d412024-09-11 22:12:49 +00001751 if (msg->adv_mac)
1752 os_memcpy(adv_mac, msg->adv_mac, ETH_ALEN);
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001753 else
1754 os_memset(adv_mac, 0, ETH_ALEN);
1755
Sunil Ravic0f5d412024-09-11 22:12:49 +00001756 if (msg->adv_id)
1757 adv_id = WPA_GET_LE32(msg->adv_id);
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001758
Sunil Ravic0f5d412024-09-11 22:12:49 +00001759 if (msg->conn_cap) {
1760 conncap = *msg->conn_cap;
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001761
1762 /* Switch bits to local relative */
1763 switch (conncap) {
1764 case P2PS_SETUP_GROUP_OWNER:
1765 conncap = P2PS_SETUP_CLIENT;
1766 break;
1767 case P2PS_SETUP_CLIENT:
1768 conncap = P2PS_SETUP_GROUP_OWNER;
1769 break;
1770 }
1771 }
1772
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07001773 p2p_dbg(p2p, "Received Provision Discovery Response from " MACSTR
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001774 " with config methods 0x%x",
Sunil Ravic0f5d412024-09-11 22:12:49 +00001775 MAC2STR(sa), msg->wps_config_methods);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001776
1777 dev = p2p_get_device(p2p, sa);
1778 if (dev == NULL || !dev->req_config_methods) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07001779 p2p_dbg(p2p, "Ignore Provision Discovery Response from " MACSTR
1780 " with no pending request", MAC2STR(sa));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001781 return;
Sunil Ravic0f5d412024-09-11 22:12:49 +00001782 } else if (msg->wfd_subelems) {
Dmitry Shmidt31a29cc2016-03-09 15:58:17 -08001783 wpabuf_free(dev->info.wfd_subelems);
Sunil Ravic0f5d412024-09-11 22:12:49 +00001784 dev->info.wfd_subelems = wpabuf_dup(msg->wfd_subelems);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001785 }
1786
Sunil Ravic0f5d412024-09-11 22:12:49 +00001787 p2p_update_peer_6ghz_capab(dev, msg);
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00001788
Sunil Ravic0f5d412024-09-11 22:12:49 +00001789 if (dev->dialog_token != msg->dialog_token) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07001790 p2p_dbg(p2p, "Ignore Provision Discovery Response with unexpected Dialog Token %u (expected %u)",
Sunil Ravic0f5d412024-09-11 22:12:49 +00001791 msg->dialog_token, dev->dialog_token);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001792 return;
1793 }
1794
Dmitry Shmidt91c40cd2012-09-25 14:23:53 -07001795 if (p2p->pending_action_state == P2P_PENDING_PD) {
1796 os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
1797 p2p->pending_action_state = P2P_NO_PENDING_ACTION;
1798 }
1799
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001800 p2ps_seeker = p2p->p2ps_prov && p2p->p2ps_prov->pd_seeker;
1801
Jouni Malinen75ecf522011-06-27 15:19:46 -07001802 /*
Dmitry Shmidt444d5672013-04-01 13:08:44 -07001803 * Use a local copy of the requested config methods since
1804 * p2p_reset_pending_pd() can clear this in the peer entry.
1805 */
1806 req_config_methods = dev->req_config_methods;
1807
1808 /*
Jouni Malinen75ecf522011-06-27 15:19:46 -07001809 * If the response is from the peer to whom a user initiated request
1810 * was sent earlier, we reset that state info here.
1811 */
1812 if (p2p->user_initiated_pd &&
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001813 ether_addr_equal(p2p->pending_pd_devaddr, sa))
Jouni Malinen75ecf522011-06-27 15:19:46 -07001814 p2p_reset_pending_pd(p2p);
1815
Sunil Ravic0f5d412024-09-11 22:12:49 +00001816 if (msg->wps_config_methods != req_config_methods) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07001817 p2p_dbg(p2p, "Peer rejected our Provision Discovery Request (received config_methods 0x%x expected 0x%x",
Sunil Ravic0f5d412024-09-11 22:12:49 +00001818 msg->wps_config_methods, req_config_methods);
Jouni Malinen75ecf522011-06-27 15:19:46 -07001819 if (p2p->cfg->prov_disc_fail)
1820 p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa,
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001821 P2P_PROV_DISC_REJECTED,
1822 adv_id, adv_mac, NULL);
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07001823 p2ps_prov_free(p2p);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001824 goto out;
1825 }
1826
Dmitry Shmidt444d5672013-04-01 13:08:44 -07001827 report_config_methods = req_config_methods;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001828 dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001829 P2P_DEV_PD_PEER_KEYPAD |
1830 P2P_DEV_PD_PEER_P2PS);
Dmitry Shmidt444d5672013-04-01 13:08:44 -07001831 if (req_config_methods & WPS_CONFIG_DISPLAY) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07001832 p2p_dbg(p2p, "Peer " MACSTR
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001833 " accepted to show a PIN on display", MAC2STR(sa));
1834 dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001835 passwd_id = DEV_PW_REGISTRAR_SPECIFIED;
Sunil Ravic0f5d412024-09-11 22:12:49 +00001836 } else if (msg->wps_config_methods & WPS_CONFIG_KEYPAD) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07001837 p2p_dbg(p2p, "Peer " MACSTR
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001838 " accepted to write our PIN using keypad",
1839 MAC2STR(sa));
1840 dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001841 passwd_id = DEV_PW_USER_SPECIFIED;
Sunil Ravic0f5d412024-09-11 22:12:49 +00001842 } else if (msg->wps_config_methods & WPS_CONFIG_P2PS) {
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001843 p2p_dbg(p2p, "Peer " MACSTR " accepted P2PS PIN",
1844 MAC2STR(sa));
1845 dev->flags |= P2P_DEV_PD_PEER_P2PS;
1846 passwd_id = DEV_PW_P2PS_DEFAULT;
1847 }
1848
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001849 if ((status == P2P_SC_SUCCESS || status == P2P_SC_SUCCESS_DEFERRED) &&
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001850 p2p->p2ps_prov) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001851 dev->oper_freq = 0;
1852
1853 /*
1854 * Save the reported channel list and operating frequency.
1855 * Note that the specification mandates that the responder
1856 * should include in the channel list only channels reported by
Hai Shaloma20dcd72022-02-04 13:43:00 -08001857 * the initiator, so this is only a validity check, and if this
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001858 * fails the flow would continue, although it would probably
1859 * fail. Same is true for the operating channel.
1860 */
Sunil Ravic0f5d412024-09-11 22:12:49 +00001861 if (msg->channel_list && msg->channel_list_len &&
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001862 p2p_peer_channels_check(p2p, &p2p->channels, dev,
Sunil Ravic0f5d412024-09-11 22:12:49 +00001863 msg->channel_list,
1864 msg->channel_list_len) < 0)
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001865 p2p_dbg(p2p, "P2PS PD Response - no common channels");
1866
Sunil Ravic0f5d412024-09-11 22:12:49 +00001867 if (msg->operating_channel) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001868 if (p2p_channels_includes(&p2p->channels,
Sunil Ravic0f5d412024-09-11 22:12:49 +00001869 msg->operating_channel[3],
1870 msg->operating_channel[4]) &&
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001871 p2p_channels_includes(&dev->channels,
Sunil Ravic0f5d412024-09-11 22:12:49 +00001872 msg->operating_channel[3],
1873 msg->operating_channel[4])) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001874 dev->oper_freq =
1875 p2p_channel_to_freq(
Sunil Ravic0f5d412024-09-11 22:12:49 +00001876 msg->operating_channel[3],
1877 msg->operating_channel[4]);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001878 } else {
1879 p2p_dbg(p2p,
1880 "P2PS PD Response - invalid operating channel");
1881 }
1882 }
1883
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001884 if (p2p->cfg->p2ps_prov_complete) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001885 int freq = 0;
1886
1887 if (conncap == P2PS_SETUP_GROUP_OWNER) {
1888 u8 tmp;
1889
1890 /*
1891 * Re-select the operating channel as it is
1892 * possible that original channel is no longer
1893 * valid. This should not really fail.
1894 */
1895 if (p2p_go_select_channel(p2p, dev, &tmp) < 0)
1896 p2p_dbg(p2p,
1897 "P2PS PD channel selection failed");
1898
1899 freq = p2p_channel_to_freq(p2p->op_reg_class,
1900 p2p->op_channel);
1901 if (freq < 0)
1902 freq = 0;
1903 }
1904
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001905 p2p->cfg->p2ps_prov_complete(
1906 p2p->cfg->cb_ctx, status, sa, adv_mac,
1907 p2p->p2ps_prov->session_mac,
1908 group_mac, adv_id, p2p->p2ps_prov->session_id,
Sunil Ravic0f5d412024-09-11 22:12:49 +00001909 conncap, passwd_id, msg->persistent_ssid,
1910 msg->persistent_ssid_len, 1, 0, NULL,
1911 msg->feature_cap, msg->feature_cap_len, freq,
1912 msg->group_id ? msg->group_id + ETH_ALEN : NULL,
1913 msg->group_id ? msg->group_id_len - ETH_ALEN :
1914 0);
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001915 }
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07001916 p2ps_prov_free(p2p);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001917 } else if (status != P2P_SC_SUCCESS &&
1918 status != P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE &&
1919 status != P2P_SC_SUCCESS_DEFERRED && p2p->p2ps_prov) {
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001920 if (p2p->cfg->p2ps_prov_complete)
1921 p2p->cfg->p2ps_prov_complete(
1922 p2p->cfg->cb_ctx, status, sa, adv_mac,
1923 p2p->p2ps_prov->session_mac,
1924 group_mac, adv_id, p2p->p2ps_prov->session_id,
Dmitry Shmidtde47be72016-01-07 12:52:55 -08001925 0, 0, NULL, 0, 1, 0, NULL, NULL, 0, 0, NULL, 0);
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07001926 p2ps_prov_free(p2p);
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001927 }
1928
1929 if (status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) {
1930 if (p2p->cfg->remove_stale_groups) {
1931 p2p->cfg->remove_stale_groups(p2p->cfg->cb_ctx,
1932 dev->info.p2p_device_addr,
1933 NULL, NULL, 0);
1934 }
1935
Sunil Ravic0f5d412024-09-11 22:12:49 +00001936 if (msg->session_info && msg->session_info_len) {
1937 size_t info_len = msg->session_info_len;
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001938 char *deferred_sess_resp = os_malloc(2 * info_len + 1);
1939
1940 if (!deferred_sess_resp) {
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07001941 p2ps_prov_free(p2p);
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001942 goto out;
1943 }
Sunil Ravic0f5d412024-09-11 22:12:49 +00001944 utf8_escape((char *) msg->session_info, info_len,
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001945 deferred_sess_resp, 2 * info_len + 1);
1946
1947 if (p2p->cfg->prov_disc_fail)
1948 p2p->cfg->prov_disc_fail(
1949 p2p->cfg->cb_ctx, sa,
1950 P2P_PROV_DISC_INFO_UNAVAILABLE,
1951 adv_id, adv_mac,
1952 deferred_sess_resp);
1953 os_free(deferred_sess_resp);
1954 } else
1955 if (p2p->cfg->prov_disc_fail)
1956 p2p->cfg->prov_disc_fail(
1957 p2p->cfg->cb_ctx, sa,
1958 P2P_PROV_DISC_INFO_UNAVAILABLE,
1959 adv_id, adv_mac, NULL);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001960 } else if (status != P2P_SC_SUCCESS) {
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001961 p2p_dbg(p2p, "Peer rejected our Provision Discovery Request");
1962 if (p2p->cfg->prov_disc_fail)
1963 p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001964 P2P_PROV_DISC_REJECTED,
1965 adv_id, adv_mac, NULL);
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07001966 p2ps_prov_free(p2p);
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001967 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001968 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001969
1970 /* Store the provisioning info */
Sunil Ravic0f5d412024-09-11 22:12:49 +00001971 dev->wps_prov_info = msg->wps_config_methods;
1972 if (msg->intended_addr)
1973 os_memcpy(dev->interface_addr, msg->intended_addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001974
1975out:
1976 dev->req_config_methods = 0;
1977 p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001978 if (dev->flags & P2P_DEV_PD_BEFORE_GO_NEG) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07001979 p2p_dbg(p2p, "Start GO Neg after the PD-before-GO-Neg workaround with "
1980 MACSTR, MAC2STR(dev->info.p2p_device_addr));
Dmitry Shmidt04949592012-07-19 12:16:46 -07001981 dev->flags &= ~P2P_DEV_PD_BEFORE_GO_NEG;
1982 p2p_connect_send(p2p, dev);
1983 return;
1984 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001985
1986 /*
1987 * prov_disc_resp callback is used to generate P2P-PROV-DISC-ENTER-PIN,
1988 * P2P-PROV-DISC-SHOW-PIN, and P2P-PROV-DISC-PBC-REQ events.
1989 * Call it only for a legacy P2P PD or for P2PS PD scenarios where
1990 * show/enter PIN events are needed.
1991 *
1992 * The callback is called in the following cases:
1993 * 1. Legacy P2P PD response with a status SUCCESS
1994 * 2. P2PS, advertiser method: DISPLAY, autoaccept: true,
1995 * response status: SUCCESS, local method KEYPAD
1996 * 3. P2PS, advertiser method: KEYPAD,Seeker side,
1997 * response status: INFO_CURRENTLY_UNAVAILABLE,
1998 * local method: DISPLAY
1999 */
2000 if (p2p->cfg->prov_disc_resp &&
2001 ((status == P2P_SC_SUCCESS && !adv_id) ||
2002 (p2ps_seeker && status == P2P_SC_SUCCESS &&
2003 passwd_id == DEV_PW_REGISTRAR_SPECIFIED) ||
2004 (p2ps_seeker &&
2005 status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE &&
2006 passwd_id == DEV_PW_USER_SPECIFIED)))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002007 p2p->cfg->prov_disc_resp(p2p->cfg->cb_ctx, sa,
2008 report_config_methods);
Dmitry Shmidt37d4d6a2013-03-18 13:09:42 -07002009
2010 if (p2p->state == P2P_PD_DURING_FIND) {
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08002011 p2p_stop_listen_for_freq(p2p, 0);
Dmitry Shmidt37d4d6a2013-03-18 13:09:42 -07002012 p2p_continue_find(p2p);
2013 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002014}
2015
2016
Sunil Ravic0f5d412024-09-11 22:12:49 +00002017void p2p_handle_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
2018 const u8 *data, size_t len, int rx_freq)
2019{
2020 struct p2p_message msg;
2021
2022 if (p2p_parse(data, len, &msg))
2023 return;
2024
2025 if (msg.pcea_info && msg.pbma_info)
2026 p2p_process_prov_disc_bootstrap_resp(p2p, &msg, sa, data + 1,
2027 len - 1, rx_freq);
2028 else
2029 p2p_process_prov_disc_resp(p2p, &msg, sa, data + 1, len - 1);
2030
2031 p2p_parse_free(&msg);
2032}
2033
2034
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002035int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002036 int join, int force_freq)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002037{
2038 struct wpabuf *req;
2039 int freq;
Dmitry Shmidt497c1d52011-07-21 15:19:46 -07002040
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002041 if (force_freq > 0)
2042 freq = force_freq;
2043 else
2044 freq = dev->listen_freq > 0 ? dev->listen_freq :
2045 dev->oper_freq;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002046 if (freq <= 0) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07002047 p2p_dbg(p2p, "No Listen/Operating frequency known for the peer "
2048 MACSTR " to send Provision Discovery Request",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002049 MAC2STR(dev->info.p2p_device_addr));
2050 return -1;
2051 }
2052
2053 if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) {
2054 if (!(dev->info.dev_capab &
2055 P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07002056 p2p_dbg(p2p, "Cannot use PD with P2P Device " MACSTR
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002057 " that is in a group and is not discoverable",
2058 MAC2STR(dev->info.p2p_device_addr));
2059 return -1;
2060 }
2061 /* TODO: use device discoverability request through GO */
2062 }
2063
Sunil Ravic0f5d412024-09-11 22:12:49 +00002064 if (!dev->p2p2 && p2p->p2ps_prov) {
Dmitry Shmidt216983b2015-02-06 10:50:36 -08002065 if (p2p->p2ps_prov->status == P2P_SC_SUCCESS_DEFERRED) {
2066 if (p2p->p2ps_prov->method == WPS_CONFIG_DISPLAY)
2067 dev->req_config_methods = WPS_CONFIG_KEYPAD;
2068 else if (p2p->p2ps_prov->method == WPS_CONFIG_KEYPAD)
2069 dev->req_config_methods = WPS_CONFIG_DISPLAY;
2070 else
2071 dev->req_config_methods = WPS_CONFIG_P2PS;
2072 } else {
2073 /* Order of preference, based on peer's capabilities */
2074 if (p2p->p2ps_prov->method)
2075 dev->req_config_methods =
2076 p2p->p2ps_prov->method;
2077 else if (dev->info.config_methods & WPS_CONFIG_P2PS)
2078 dev->req_config_methods = WPS_CONFIG_P2PS;
2079 else if (dev->info.config_methods & WPS_CONFIG_DISPLAY)
2080 dev->req_config_methods = WPS_CONFIG_DISPLAY;
2081 else
2082 dev->req_config_methods = WPS_CONFIG_KEYPAD;
2083 }
2084 p2p_dbg(p2p,
2085 "Building PD Request based on P2PS config method 0x%x status %d --> req_config_methods 0x%x",
2086 p2p->p2ps_prov->method, p2p->p2ps_prov->status,
2087 dev->req_config_methods);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002088
2089 if (p2p_prepare_channel(p2p, dev, p2p->p2ps_prov->force_freq,
2090 p2p->p2ps_prov->pref_freq, 1) < 0)
2091 return -1;
Dmitry Shmidt216983b2015-02-06 10:50:36 -08002092 }
2093
Sunil Ravic0f5d412024-09-11 22:12:49 +00002094 if (dev->p2p2)
2095 req = p2p_build_prov_disc_bootstrap_req(p2p, dev);
2096 else
2097 req = p2p_build_prov_disc_req(p2p, dev, join);
2098
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002099 if (req == NULL)
2100 return -1;
2101
Dmitry Shmidt04949592012-07-19 12:16:46 -07002102 if (p2p->state != P2P_IDLE)
2103 p2p_stop_listen_for_freq(p2p, freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002104 p2p->pending_action_state = P2P_PENDING_PD;
2105 if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
2106 p2p->cfg->dev_addr, dev->info.p2p_device_addr,
2107 wpabuf_head(req), wpabuf_len(req), 200) < 0) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07002108 p2p_dbg(p2p, "Failed to send Action frame");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002109 wpabuf_free(req);
2110 return -1;
2111 }
2112
Jouni Malinen75ecf522011-06-27 15:19:46 -07002113 os_memcpy(p2p->pending_pd_devaddr, dev->info.p2p_device_addr, ETH_ALEN);
2114
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002115 wpabuf_free(req);
2116 return 0;
2117}
2118
2119
2120int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
Dmitry Shmidt216983b2015-02-06 10:50:36 -08002121 struct p2ps_provision *p2ps_prov,
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002122 u16 config_methods, int join, int force_freq,
2123 int user_initiated_pd)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002124{
2125 struct p2p_device *dev;
2126
2127 dev = p2p_get_device(p2p, peer_addr);
2128 if (dev == NULL)
2129 dev = p2p_get_device_interface(p2p, peer_addr);
2130 if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07002131 p2p_dbg(p2p, "Provision Discovery Request destination " MACSTR
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002132 " not yet known", MAC2STR(peer_addr));
Dmitry Shmidt216983b2015-02-06 10:50:36 -08002133 os_free(p2ps_prov);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002134 return -1;
2135 }
2136
Sunil Ravic0f5d412024-09-11 22:12:49 +00002137 if (dev->p2p2 && dev->req_bootstrap_method) {
2138 p2p_dbg(p2p, "Provision Discovery Request with " MACSTR
2139 " (bootstrap methods 0x%x)",
2140 MAC2STR(peer_addr), dev->req_bootstrap_method);
2141 goto out;
2142 }
2143
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07002144 p2p_dbg(p2p, "Provision Discovery Request with " MACSTR
2145 " (config methods 0x%x)",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002146 MAC2STR(peer_addr), config_methods);
Sunil Ravic0f5d412024-09-11 22:12:49 +00002147
Dmitry Shmidt216983b2015-02-06 10:50:36 -08002148 if (config_methods == 0 && !p2ps_prov) {
2149 os_free(p2ps_prov);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002150 return -1;
Dmitry Shmidt216983b2015-02-06 10:50:36 -08002151 }
Sunil Ravic0f5d412024-09-11 22:12:49 +00002152 dev->req_config_methods = config_methods;
Dmitry Shmidt216983b2015-02-06 10:50:36 -08002153
2154 if (p2ps_prov && p2ps_prov->status == P2P_SC_SUCCESS_DEFERRED &&
2155 p2p->p2ps_prov) {
2156 /* Use cached method from deferred provisioning */
2157 p2ps_prov->method = p2p->p2ps_prov->method;
2158 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002159
Sunil Ravic0f5d412024-09-11 22:12:49 +00002160out:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002161 /* Reset provisioning info */
2162 dev->wps_prov_info = 0;
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07002163 p2ps_prov_free(p2p);
Dmitry Shmidt216983b2015-02-06 10:50:36 -08002164 p2p->p2ps_prov = p2ps_prov;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002165
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002166 if (join)
2167 dev->flags |= P2P_DEV_PD_FOR_JOIN;
2168 else
2169 dev->flags &= ~P2P_DEV_PD_FOR_JOIN;
2170
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08002171 if (p2p->state != P2P_IDLE && p2p->state != P2P_SEARCH &&
2172 p2p->state != P2P_LISTEN_ONLY) {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07002173 p2p_dbg(p2p, "Busy with other operations; postpone Provision Discovery Request with "
Sunil Ravic0f5d412024-09-11 22:12:49 +00002174 MACSTR, MAC2STR(peer_addr));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002175 return 0;
2176 }
2177
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08002178 p2p->user_initiated_pd = user_initiated_pd;
Dmitry Shmidt051af732013-10-22 13:52:46 -07002179 p2p->pd_force_freq = force_freq;
Jouni Malinen75ecf522011-06-27 15:19:46 -07002180
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002181 if (p2p->user_initiated_pd)
Jouni Malinen75ecf522011-06-27 15:19:46 -07002182 p2p->pd_retries = MAX_PROV_DISC_REQ_RETRIES;
2183
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08002184 /*
2185 * Assign dialog token here to use the same value in each retry within
2186 * the same PD exchange.
2187 */
2188 dev->dialog_token++;
2189 if (dev->dialog_token == 0)
2190 dev->dialog_token = 1;
2191
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002192 return p2p_send_prov_disc_req(p2p, dev, join, force_freq);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002193}
Jouni Malinen75ecf522011-06-27 15:19:46 -07002194
2195
2196void p2p_reset_pending_pd(struct p2p_data *p2p)
2197{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002198 struct p2p_device *dev;
2199
2200 dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
Sunil Ravib0ac25f2024-07-12 01:42:03 +00002201 if (!ether_addr_equal(p2p->pending_pd_devaddr,
2202 dev->info.p2p_device_addr))
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002203 continue;
2204 if (!dev->req_config_methods)
2205 continue;
2206 if (dev->flags & P2P_DEV_PD_FOR_JOIN)
2207 continue;
2208 /* Reset the config methods of the device */
2209 dev->req_config_methods = 0;
2210 }
2211
Jouni Malinen75ecf522011-06-27 15:19:46 -07002212 p2p->user_initiated_pd = 0;
2213 os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
2214 p2p->pd_retries = 0;
Dmitry Shmidt051af732013-10-22 13:52:46 -07002215 p2p->pd_force_freq = 0;
Jouni Malinen75ecf522011-06-27 15:19:46 -07002216}
Dmitry Shmidta3dc3092015-06-23 11:21:28 -07002217
2218
2219void p2ps_prov_free(struct p2p_data *p2p)
2220{
2221 os_free(p2p->p2ps_prov);
2222 p2p->p2ps_prov = NULL;
2223}