1f05cddf9SRui Paulo /*
2f05cddf9SRui Paulo * Wi-Fi Direct - P2P provision discovery
3f05cddf9SRui Paulo * Copyright (c) 2009-2010, Atheros Communications
4f05cddf9SRui Paulo *
5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo * See README for more details.
7f05cddf9SRui Paulo */
8f05cddf9SRui Paulo
9f05cddf9SRui Paulo #include "includes.h"
10f05cddf9SRui Paulo
11f05cddf9SRui Paulo #include "common.h"
12f05cddf9SRui Paulo #include "common/ieee802_11_defs.h"
135b9c547cSRui Paulo #include "common/wpa_ctrl.h"
14f05cddf9SRui Paulo #include "wps/wps_defs.h"
15f05cddf9SRui Paulo #include "p2p_i.h"
16f05cddf9SRui Paulo #include "p2p.h"
17f05cddf9SRui Paulo
18f05cddf9SRui Paulo
19f05cddf9SRui Paulo /*
20f05cddf9SRui Paulo * Number of retries to attempt for provision discovery requests
21f05cddf9SRui Paulo * in case the peer is not listening.
22f05cddf9SRui Paulo */
23f05cddf9SRui Paulo #define MAX_PROV_DISC_REQ_RETRIES 120
24f05cddf9SRui Paulo
25f05cddf9SRui Paulo
p2p_build_wps_ie_config_methods(struct wpabuf * buf,u16 config_methods)26f05cddf9SRui Paulo static void p2p_build_wps_ie_config_methods(struct wpabuf *buf,
27f05cddf9SRui Paulo u16 config_methods)
28f05cddf9SRui Paulo {
29f05cddf9SRui Paulo u8 *len;
30f05cddf9SRui Paulo wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
31f05cddf9SRui Paulo len = wpabuf_put(buf, 1);
32f05cddf9SRui Paulo wpabuf_put_be32(buf, WPS_DEV_OUI_WFA);
33f05cddf9SRui Paulo
34f05cddf9SRui Paulo /* Config Methods */
35f05cddf9SRui Paulo wpabuf_put_be16(buf, ATTR_CONFIG_METHODS);
36f05cddf9SRui Paulo wpabuf_put_be16(buf, 2);
37f05cddf9SRui Paulo wpabuf_put_be16(buf, config_methods);
38f05cddf9SRui Paulo
39f05cddf9SRui Paulo p2p_buf_update_ie_hdr(buf, len);
40f05cddf9SRui Paulo }
41f05cddf9SRui Paulo
42f05cddf9SRui Paulo
p2ps_add_new_group_info(struct p2p_data * p2p,struct p2p_device * dev,struct wpabuf * buf)43780fb4a2SCy Schubert static void p2ps_add_new_group_info(struct p2p_data *p2p,
44780fb4a2SCy Schubert struct p2p_device *dev,
45780fb4a2SCy Schubert struct wpabuf *buf)
465b9c547cSRui Paulo {
475b9c547cSRui Paulo int found;
485b9c547cSRui Paulo u8 intended_addr[ETH_ALEN];
49325151a3SRui Paulo u8 ssid[SSID_MAX_LEN];
505b9c547cSRui Paulo size_t ssid_len;
515b9c547cSRui Paulo int group_iface;
52780fb4a2SCy Schubert unsigned int force_freq;
535b9c547cSRui Paulo
545b9c547cSRui Paulo if (!p2p->cfg->get_go_info)
555b9c547cSRui Paulo return;
565b9c547cSRui Paulo
575b9c547cSRui Paulo found = p2p->cfg->get_go_info(
585b9c547cSRui Paulo p2p->cfg->cb_ctx, intended_addr, ssid,
59780fb4a2SCy Schubert &ssid_len, &group_iface, &force_freq);
605b9c547cSRui Paulo if (found) {
61780fb4a2SCy Schubert if (force_freq > 0) {
62780fb4a2SCy Schubert p2p->p2ps_prov->force_freq = force_freq;
63780fb4a2SCy Schubert p2p->p2ps_prov->pref_freq = 0;
64780fb4a2SCy Schubert
65780fb4a2SCy Schubert if (dev)
66780fb4a2SCy Schubert p2p_prepare_channel(p2p, dev, force_freq, 0, 0);
67780fb4a2SCy Schubert }
685b9c547cSRui Paulo p2p_buf_add_group_id(buf, p2p->cfg->dev_addr,
695b9c547cSRui Paulo ssid, ssid_len);
70325151a3SRui Paulo
71325151a3SRui Paulo if (group_iface)
72325151a3SRui Paulo p2p_buf_add_intended_addr(buf, p2p->intended_addr);
73325151a3SRui Paulo else
745b9c547cSRui Paulo p2p_buf_add_intended_addr(buf, intended_addr);
755b9c547cSRui Paulo } else {
765b9c547cSRui Paulo if (!p2p->ssid_set) {
775b9c547cSRui Paulo p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len);
785b9c547cSRui Paulo p2p->ssid_set = 1;
795b9c547cSRui Paulo }
805b9c547cSRui Paulo
815b9c547cSRui Paulo /* Add pre-composed P2P Group ID */
825b9c547cSRui Paulo p2p_buf_add_group_id(buf, p2p->cfg->dev_addr,
835b9c547cSRui Paulo p2p->ssid, p2p->ssid_len);
845b9c547cSRui Paulo
855b9c547cSRui Paulo if (group_iface)
865b9c547cSRui Paulo p2p_buf_add_intended_addr(
875b9c547cSRui Paulo buf, p2p->intended_addr);
885b9c547cSRui Paulo else
895b9c547cSRui Paulo p2p_buf_add_intended_addr(
905b9c547cSRui Paulo buf, p2p->cfg->dev_addr);
915b9c547cSRui Paulo }
925b9c547cSRui Paulo }
935b9c547cSRui Paulo
945b9c547cSRui Paulo
p2ps_add_pd_req_attrs(struct p2p_data * p2p,struct p2p_device * dev,struct wpabuf * buf,u16 config_methods)955b9c547cSRui Paulo static void p2ps_add_pd_req_attrs(struct p2p_data *p2p, struct p2p_device *dev,
965b9c547cSRui Paulo struct wpabuf *buf, u16 config_methods)
975b9c547cSRui Paulo {
985b9c547cSRui Paulo struct p2ps_provision *prov = p2p->p2ps_prov;
99325151a3SRui Paulo struct p2ps_feature_capab fcap = { prov->cpt_mask, 0 };
1005b9c547cSRui Paulo int shared_group = 0;
101325151a3SRui Paulo u8 ssid[SSID_MAX_LEN];
1025b9c547cSRui Paulo size_t ssid_len;
1035b9c547cSRui Paulo u8 go_dev_addr[ETH_ALEN];
104325151a3SRui Paulo u8 intended_addr[ETH_ALEN];
105780fb4a2SCy Schubert int follow_on_req_fail = prov->status >= 0 &&
106780fb4a2SCy Schubert prov->status != P2P_SC_SUCCESS_DEFERRED;
1075b9c547cSRui Paulo
1085b9c547cSRui Paulo /* If we might be explicite group owner, add GO details */
109780fb4a2SCy Schubert if (!follow_on_req_fail &&
110780fb4a2SCy Schubert (prov->conncap & (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW)))
111780fb4a2SCy Schubert p2ps_add_new_group_info(p2p, dev, buf);
1125b9c547cSRui Paulo
1135b9c547cSRui Paulo if (prov->status >= 0)
1145b9c547cSRui Paulo p2p_buf_add_status(buf, (u8) prov->status);
1155b9c547cSRui Paulo else
1165b9c547cSRui Paulo prov->method = config_methods;
1175b9c547cSRui Paulo
118780fb4a2SCy Schubert if (!follow_on_req_fail) {
1195b9c547cSRui Paulo if (p2p->cfg->get_persistent_group) {
1205b9c547cSRui Paulo shared_group = p2p->cfg->get_persistent_group(
121780fb4a2SCy Schubert p2p->cfg->cb_ctx, dev->info.p2p_device_addr,
122780fb4a2SCy Schubert NULL, 0, go_dev_addr, ssid, &ssid_len,
123780fb4a2SCy Schubert intended_addr);
1245b9c547cSRui Paulo }
1255b9c547cSRui Paulo
1265b9c547cSRui Paulo if (shared_group ||
127*a90b9d01SCy Schubert (prov->conncap & (P2PS_SETUP_CLIENT | P2PS_SETUP_NEW))) {
128*a90b9d01SCy Schubert bool is_6ghz_capab;
129*a90b9d01SCy Schubert
130*a90b9d01SCy Schubert is_6ghz_capab = is_p2p_6ghz_capable(p2p) &&
131*a90b9d01SCy Schubert p2p_is_peer_6ghz_capab(
132*a90b9d01SCy Schubert p2p, dev->info.p2p_device_addr);
133780fb4a2SCy Schubert p2p_buf_add_channel_list(buf, p2p->cfg->country,
134*a90b9d01SCy Schubert &p2p->channels, is_6ghz_capab);
135*a90b9d01SCy Schubert }
1365b9c547cSRui Paulo
137780fb4a2SCy Schubert if ((shared_group && !is_zero_ether_addr(intended_addr)) ||
138780fb4a2SCy Schubert (prov->conncap & (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW)))
1395b9c547cSRui Paulo p2p_buf_add_operating_channel(buf, p2p->cfg->country,
1405b9c547cSRui Paulo p2p->op_reg_class,
1415b9c547cSRui Paulo p2p->op_channel);
1425b9c547cSRui Paulo }
1435b9c547cSRui Paulo
144780fb4a2SCy Schubert if (prov->status < 0 && prov->info[0])
1455b9c547cSRui Paulo p2p_buf_add_session_info(buf, prov->info);
1465b9c547cSRui Paulo
147780fb4a2SCy Schubert if (!follow_on_req_fail)
1485b9c547cSRui Paulo p2p_buf_add_connection_capability(buf, prov->conncap);
1495b9c547cSRui Paulo
1505b9c547cSRui Paulo p2p_buf_add_advertisement_id(buf, prov->adv_id, prov->adv_mac);
1515b9c547cSRui Paulo
152780fb4a2SCy Schubert if (!follow_on_req_fail) {
1535b9c547cSRui Paulo if (shared_group || prov->conncap == P2PS_SETUP_NEW ||
1545b9c547cSRui Paulo prov->conncap ==
1555b9c547cSRui Paulo (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW) ||
1565b9c547cSRui Paulo prov->conncap ==
1575b9c547cSRui Paulo (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_CLIENT)) {
1585b9c547cSRui Paulo /* Add Config Timeout */
1595b9c547cSRui Paulo p2p_buf_add_config_timeout(buf, p2p->go_timeout,
1605b9c547cSRui Paulo p2p->client_timeout);
1615b9c547cSRui Paulo }
1625b9c547cSRui Paulo
163780fb4a2SCy Schubert p2p_buf_add_listen_channel(buf, p2p->cfg->country,
164780fb4a2SCy Schubert p2p->cfg->reg_class,
1655b9c547cSRui Paulo p2p->cfg->channel);
166780fb4a2SCy Schubert }
1675b9c547cSRui Paulo
1685b9c547cSRui Paulo p2p_buf_add_session_id(buf, prov->session_id, prov->session_mac);
1695b9c547cSRui Paulo
170325151a3SRui Paulo p2p_buf_add_feature_capability(buf, sizeof(fcap), (const u8 *) &fcap);
1715b9c547cSRui Paulo
172325151a3SRui Paulo if (shared_group) {
1735b9c547cSRui Paulo p2p_buf_add_persistent_group_info(buf, go_dev_addr,
1745b9c547cSRui Paulo ssid, ssid_len);
175325151a3SRui Paulo /* Add intended interface address if it is not added yet */
176325151a3SRui Paulo if ((prov->conncap == P2PS_SETUP_NONE ||
177325151a3SRui Paulo prov->conncap == P2PS_SETUP_CLIENT) &&
178325151a3SRui Paulo !is_zero_ether_addr(intended_addr))
179325151a3SRui Paulo p2p_buf_add_intended_addr(buf, intended_addr);
180325151a3SRui Paulo }
1815b9c547cSRui Paulo }
1825b9c547cSRui Paulo
1835b9c547cSRui Paulo
p2p_build_prov_disc_req(struct p2p_data * p2p,struct p2p_device * dev,int join)184f05cddf9SRui Paulo static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p,
1855b9c547cSRui Paulo struct p2p_device *dev,
1865b9c547cSRui Paulo int join)
187f05cddf9SRui Paulo {
188f05cddf9SRui Paulo struct wpabuf *buf;
189f05cddf9SRui Paulo u8 *len;
190f05cddf9SRui Paulo size_t extra = 0;
1915b9c547cSRui Paulo u8 dialog_token = dev->dialog_token;
1925b9c547cSRui Paulo u16 config_methods = dev->req_config_methods;
1935b9c547cSRui Paulo struct p2p_device *go = join ? dev : NULL;
1945b9c547cSRui Paulo u8 group_capab;
195f05cddf9SRui Paulo
196f05cddf9SRui Paulo #ifdef CONFIG_WIFI_DISPLAY
197f05cddf9SRui Paulo if (p2p->wfd_ie_prov_disc_req)
198f05cddf9SRui Paulo extra = wpabuf_len(p2p->wfd_ie_prov_disc_req);
199f05cddf9SRui Paulo #endif /* CONFIG_WIFI_DISPLAY */
200f05cddf9SRui Paulo
2015b9c547cSRui Paulo if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ])
2025b9c547cSRui Paulo extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ]);
2035b9c547cSRui Paulo
2045b9c547cSRui Paulo if (p2p->p2ps_prov)
2055b9c547cSRui Paulo extra += os_strlen(p2p->p2ps_prov->info) + 1 +
2065b9c547cSRui Paulo sizeof(struct p2ps_provision);
2075b9c547cSRui Paulo
208f05cddf9SRui Paulo buf = wpabuf_alloc(1000 + extra);
209f05cddf9SRui Paulo if (buf == NULL)
210f05cddf9SRui Paulo return NULL;
211f05cddf9SRui Paulo
212f05cddf9SRui Paulo p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_REQ, dialog_token);
213f05cddf9SRui Paulo
214f05cddf9SRui Paulo len = p2p_buf_add_ie_hdr(buf);
2155b9c547cSRui Paulo
2165b9c547cSRui Paulo group_capab = 0;
2175b9c547cSRui Paulo if (p2p->p2ps_prov) {
2185b9c547cSRui Paulo group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP;
2195b9c547cSRui Paulo group_capab |= P2P_GROUP_CAPAB_PERSISTENT_RECONN;
2205b9c547cSRui Paulo if (p2p->cross_connect)
2215b9c547cSRui Paulo group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
2225b9c547cSRui Paulo if (p2p->cfg->p2p_intra_bss)
2235b9c547cSRui Paulo group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST;
2245b9c547cSRui Paulo }
225f05cddf9SRui Paulo p2p_buf_add_capability(buf, p2p->dev_capab &
2265b9c547cSRui Paulo ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY,
2275b9c547cSRui Paulo group_capab);
228f05cddf9SRui Paulo p2p_buf_add_device_info(buf, p2p, NULL);
2295b9c547cSRui Paulo if (p2p->p2ps_prov) {
2305b9c547cSRui Paulo p2ps_add_pd_req_attrs(p2p, dev, buf, config_methods);
2315b9c547cSRui Paulo } else if (go) {
232f05cddf9SRui Paulo p2p_buf_add_group_id(buf, go->info.p2p_device_addr,
233f05cddf9SRui Paulo go->oper_ssid, go->oper_ssid_len);
234f05cddf9SRui Paulo }
235f05cddf9SRui Paulo p2p_buf_update_ie_hdr(buf, len);
236f05cddf9SRui Paulo
237f05cddf9SRui Paulo /* WPS IE with Config Methods attribute */
238f05cddf9SRui Paulo p2p_build_wps_ie_config_methods(buf, config_methods);
239f05cddf9SRui Paulo
240f05cddf9SRui Paulo #ifdef CONFIG_WIFI_DISPLAY
241f05cddf9SRui Paulo if (p2p->wfd_ie_prov_disc_req)
242f05cddf9SRui Paulo wpabuf_put_buf(buf, p2p->wfd_ie_prov_disc_req);
243f05cddf9SRui Paulo #endif /* CONFIG_WIFI_DISPLAY */
244f05cddf9SRui Paulo
2455b9c547cSRui Paulo if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ])
2465b9c547cSRui Paulo wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ]);
2475b9c547cSRui Paulo
248f05cddf9SRui Paulo return buf;
249f05cddf9SRui Paulo }
250f05cddf9SRui Paulo
251f05cddf9SRui Paulo
p2p_build_prov_disc_resp(struct p2p_data * p2p,struct p2p_device * dev,u8 dialog_token,enum p2p_status_code status,u16 config_methods,u32 adv_id,const u8 * group_id,size_t group_id_len,const u8 * persist_ssid,size_t persist_ssid_len,const u8 * fcap,u16 fcap_len)252f05cddf9SRui Paulo static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
2535b9c547cSRui Paulo struct p2p_device *dev,
254f05cddf9SRui Paulo u8 dialog_token,
2555b9c547cSRui Paulo enum p2p_status_code status,
256f05cddf9SRui Paulo u16 config_methods,
2575b9c547cSRui Paulo u32 adv_id,
258f05cddf9SRui Paulo const u8 *group_id,
2595b9c547cSRui Paulo size_t group_id_len,
2605b9c547cSRui Paulo const u8 *persist_ssid,
261325151a3SRui Paulo size_t persist_ssid_len,
262325151a3SRui Paulo const u8 *fcap,
263325151a3SRui Paulo u16 fcap_len)
264f05cddf9SRui Paulo {
265f05cddf9SRui Paulo struct wpabuf *buf;
266f05cddf9SRui Paulo size_t extra = 0;
2675b9c547cSRui Paulo int persist = 0;
268f05cddf9SRui Paulo
269f05cddf9SRui Paulo #ifdef CONFIG_WIFI_DISPLAY
270f05cddf9SRui Paulo struct wpabuf *wfd_ie = p2p->wfd_ie_prov_disc_resp;
271f05cddf9SRui Paulo if (wfd_ie && group_id) {
272f05cddf9SRui Paulo size_t i;
273f05cddf9SRui Paulo for (i = 0; i < p2p->num_groups; i++) {
274f05cddf9SRui Paulo struct p2p_group *g = p2p->groups[i];
275f05cddf9SRui Paulo struct wpabuf *ie;
276f05cddf9SRui Paulo if (!p2p_group_is_group_id_match(g, group_id,
277f05cddf9SRui Paulo group_id_len))
278f05cddf9SRui Paulo continue;
279f05cddf9SRui Paulo ie = p2p_group_get_wfd_ie(g);
280f05cddf9SRui Paulo if (ie) {
281f05cddf9SRui Paulo wfd_ie = ie;
282f05cddf9SRui Paulo break;
283f05cddf9SRui Paulo }
284f05cddf9SRui Paulo }
285f05cddf9SRui Paulo }
286f05cddf9SRui Paulo if (wfd_ie)
287f05cddf9SRui Paulo extra = wpabuf_len(wfd_ie);
288f05cddf9SRui Paulo #endif /* CONFIG_WIFI_DISPLAY */
289f05cddf9SRui Paulo
2905b9c547cSRui Paulo if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP])
2915b9c547cSRui Paulo extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP]);
2925b9c547cSRui Paulo
2935b9c547cSRui Paulo buf = wpabuf_alloc(1000 + extra);
294f05cddf9SRui Paulo if (buf == NULL)
295f05cddf9SRui Paulo return NULL;
296f05cddf9SRui Paulo
297f05cddf9SRui Paulo p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_RESP, dialog_token);
298f05cddf9SRui Paulo
2995b9c547cSRui Paulo /* Add P2P IE for P2PS */
3005b9c547cSRui Paulo if (p2p->p2ps_prov && p2p->p2ps_prov->adv_id == adv_id) {
3015b9c547cSRui Paulo u8 *len = p2p_buf_add_ie_hdr(buf);
3025b9c547cSRui Paulo struct p2ps_provision *prov = p2p->p2ps_prov;
3035b9c547cSRui Paulo u8 group_capab;
304780fb4a2SCy Schubert u8 conncap = 0;
305780fb4a2SCy Schubert
306780fb4a2SCy Schubert if (status == P2P_SC_SUCCESS ||
307780fb4a2SCy Schubert status == P2P_SC_SUCCESS_DEFERRED)
308780fb4a2SCy Schubert conncap = prov->conncap;
3095b9c547cSRui Paulo
3105b9c547cSRui Paulo if (!status && prov->status != -1)
3115b9c547cSRui Paulo status = prov->status;
3125b9c547cSRui Paulo
3135b9c547cSRui Paulo p2p_buf_add_status(buf, status);
3145b9c547cSRui Paulo group_capab = P2P_GROUP_CAPAB_PERSISTENT_GROUP |
3155b9c547cSRui Paulo P2P_GROUP_CAPAB_PERSISTENT_RECONN;
3165b9c547cSRui Paulo if (p2p->cross_connect)
3175b9c547cSRui Paulo group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
3185b9c547cSRui Paulo if (p2p->cfg->p2p_intra_bss)
3195b9c547cSRui Paulo group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST;
3205b9c547cSRui Paulo p2p_buf_add_capability(buf, p2p->dev_capab &
3215b9c547cSRui Paulo ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY,
3225b9c547cSRui Paulo group_capab);
3235b9c547cSRui Paulo p2p_buf_add_device_info(buf, p2p, NULL);
3245b9c547cSRui Paulo
325780fb4a2SCy Schubert if (persist_ssid && p2p->cfg->get_persistent_group && dev &&
3265b9c547cSRui Paulo (status == P2P_SC_SUCCESS ||
3275b9c547cSRui Paulo status == P2P_SC_SUCCESS_DEFERRED)) {
328325151a3SRui Paulo u8 ssid[SSID_MAX_LEN];
3295b9c547cSRui Paulo size_t ssid_len;
3305b9c547cSRui Paulo u8 go_dev_addr[ETH_ALEN];
331325151a3SRui Paulo u8 intended_addr[ETH_ALEN];
3325b9c547cSRui Paulo
3335b9c547cSRui Paulo persist = p2p->cfg->get_persistent_group(
3345b9c547cSRui Paulo p2p->cfg->cb_ctx,
3355b9c547cSRui Paulo dev->info.p2p_device_addr,
3365b9c547cSRui Paulo persist_ssid, persist_ssid_len, go_dev_addr,
337325151a3SRui Paulo ssid, &ssid_len, intended_addr);
338325151a3SRui Paulo if (persist) {
3395b9c547cSRui Paulo p2p_buf_add_persistent_group_info(
3405b9c547cSRui Paulo buf, go_dev_addr, ssid, ssid_len);
341325151a3SRui Paulo if (!is_zero_ether_addr(intended_addr))
342325151a3SRui Paulo p2p_buf_add_intended_addr(
343325151a3SRui Paulo buf, intended_addr);
344325151a3SRui Paulo }
3455b9c547cSRui Paulo }
3465b9c547cSRui Paulo
347780fb4a2SCy Schubert if (!persist && (conncap & P2PS_SETUP_GROUP_OWNER))
348780fb4a2SCy Schubert p2ps_add_new_group_info(p2p, dev, buf);
3495b9c547cSRui Paulo
3505b9c547cSRui Paulo /* Add Operating Channel if conncap indicates GO */
351780fb4a2SCy Schubert if (persist || (conncap & P2PS_SETUP_GROUP_OWNER)) {
3525b9c547cSRui Paulo if (p2p->op_reg_class && p2p->op_channel)
3535b9c547cSRui Paulo p2p_buf_add_operating_channel(
3545b9c547cSRui Paulo buf, p2p->cfg->country,
3555b9c547cSRui Paulo p2p->op_reg_class,
3565b9c547cSRui Paulo p2p->op_channel);
3575b9c547cSRui Paulo else
3585b9c547cSRui Paulo p2p_buf_add_operating_channel(
3595b9c547cSRui Paulo buf, p2p->cfg->country,
3605b9c547cSRui Paulo p2p->cfg->op_reg_class,
3615b9c547cSRui Paulo p2p->cfg->op_channel);
3625b9c547cSRui Paulo }
3635b9c547cSRui Paulo
364780fb4a2SCy Schubert if (persist ||
365*a90b9d01SCy Schubert (conncap & (P2PS_SETUP_CLIENT | P2PS_SETUP_GROUP_OWNER))) {
366*a90b9d01SCy Schubert bool is_6ghz_capab;
367*a90b9d01SCy Schubert
368*a90b9d01SCy Schubert is_6ghz_capab = is_p2p_6ghz_capable(p2p) && dev &&
369*a90b9d01SCy Schubert p2p_is_peer_6ghz_capab(
370*a90b9d01SCy Schubert p2p, dev->info.p2p_device_addr);
3715b9c547cSRui Paulo p2p_buf_add_channel_list(buf, p2p->cfg->country,
372*a90b9d01SCy Schubert &p2p->channels, is_6ghz_capab);
373*a90b9d01SCy Schubert }
3745b9c547cSRui Paulo
375780fb4a2SCy Schubert if (!persist && conncap)
376780fb4a2SCy Schubert p2p_buf_add_connection_capability(buf, conncap);
3775b9c547cSRui Paulo
3785b9c547cSRui Paulo p2p_buf_add_advertisement_id(buf, adv_id, prov->adv_mac);
3795b9c547cSRui Paulo
380780fb4a2SCy Schubert if (persist ||
381780fb4a2SCy Schubert (conncap & (P2PS_SETUP_CLIENT | P2PS_SETUP_GROUP_OWNER)))
3825b9c547cSRui Paulo p2p_buf_add_config_timeout(buf, p2p->go_timeout,
3835b9c547cSRui Paulo p2p->client_timeout);
3845b9c547cSRui Paulo
3855b9c547cSRui Paulo p2p_buf_add_session_id(buf, prov->session_id,
3865b9c547cSRui Paulo prov->session_mac);
3875b9c547cSRui Paulo
388325151a3SRui Paulo p2p_buf_add_feature_capability(buf, fcap_len, fcap);
3895b9c547cSRui Paulo p2p_buf_update_ie_hdr(buf, len);
3905b9c547cSRui Paulo } else if (status != P2P_SC_SUCCESS || adv_id) {
3915b9c547cSRui Paulo u8 *len = p2p_buf_add_ie_hdr(buf);
3925b9c547cSRui Paulo
3935b9c547cSRui Paulo p2p_buf_add_status(buf, status);
3945b9c547cSRui Paulo
3955b9c547cSRui Paulo if (p2p->p2ps_prov)
3965b9c547cSRui Paulo p2p_buf_add_advertisement_id(buf, adv_id,
3975b9c547cSRui Paulo p2p->p2ps_prov->adv_mac);
3985b9c547cSRui Paulo
3995b9c547cSRui Paulo p2p_buf_update_ie_hdr(buf, len);
4005b9c547cSRui Paulo }
4015b9c547cSRui Paulo
402f05cddf9SRui Paulo /* WPS IE with Config Methods attribute */
403f05cddf9SRui Paulo p2p_build_wps_ie_config_methods(buf, config_methods);
404f05cddf9SRui Paulo
405f05cddf9SRui Paulo #ifdef CONFIG_WIFI_DISPLAY
406f05cddf9SRui Paulo if (wfd_ie)
407f05cddf9SRui Paulo wpabuf_put_buf(buf, wfd_ie);
408f05cddf9SRui Paulo #endif /* CONFIG_WIFI_DISPLAY */
409f05cddf9SRui Paulo
4105b9c547cSRui Paulo if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP])
4115b9c547cSRui Paulo wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP]);
4125b9c547cSRui Paulo
413f05cddf9SRui Paulo return buf;
414f05cddf9SRui Paulo }
415f05cddf9SRui Paulo
416f05cddf9SRui Paulo
p2ps_setup_p2ps_prov(struct p2p_data * p2p,u32 adv_id,u32 session_id,u16 method,const u8 * session_mac,const u8 * adv_mac)4175b9c547cSRui Paulo static int p2ps_setup_p2ps_prov(struct p2p_data *p2p, u32 adv_id,
4185b9c547cSRui Paulo u32 session_id, u16 method,
4195b9c547cSRui Paulo const u8 *session_mac, const u8 *adv_mac)
4205b9c547cSRui Paulo {
4215b9c547cSRui Paulo struct p2ps_provision *tmp;
4225b9c547cSRui Paulo
4235b9c547cSRui Paulo if (!p2p->p2ps_prov) {
4245b9c547cSRui Paulo p2p->p2ps_prov = os_zalloc(sizeof(struct p2ps_provision) + 1);
4255b9c547cSRui Paulo if (!p2p->p2ps_prov)
4265b9c547cSRui Paulo return -1;
4275b9c547cSRui Paulo } else {
4285b9c547cSRui Paulo os_memset(p2p->p2ps_prov, 0, sizeof(struct p2ps_provision) + 1);
4295b9c547cSRui Paulo }
4305b9c547cSRui Paulo
4315b9c547cSRui Paulo tmp = p2p->p2ps_prov;
4325b9c547cSRui Paulo tmp->adv_id = adv_id;
4335b9c547cSRui Paulo tmp->session_id = session_id;
4345b9c547cSRui Paulo tmp->method = method;
4355b9c547cSRui Paulo os_memcpy(tmp->session_mac, session_mac, ETH_ALEN);
4365b9c547cSRui Paulo os_memcpy(tmp->adv_mac, adv_mac, ETH_ALEN);
4375b9c547cSRui Paulo tmp->info[0] = '\0';
4385b9c547cSRui Paulo
4395b9c547cSRui Paulo return 0;
4405b9c547cSRui Paulo }
4415b9c547cSRui Paulo
4425b9c547cSRui Paulo
p2ps_own_preferred_cpt(const u8 * cpt_priority,u8 req_cpt_mask)443325151a3SRui Paulo static u8 p2ps_own_preferred_cpt(const u8 *cpt_priority, u8 req_cpt_mask)
444325151a3SRui Paulo {
445325151a3SRui Paulo int i;
446325151a3SRui Paulo
447325151a3SRui Paulo for (i = 0; cpt_priority[i]; i++)
448325151a3SRui Paulo if (req_cpt_mask & cpt_priority[i])
449325151a3SRui Paulo return cpt_priority[i];
450325151a3SRui Paulo
451325151a3SRui Paulo return 0;
452325151a3SRui Paulo }
453325151a3SRui Paulo
454325151a3SRui Paulo
455780fb4a2SCy Schubert /* Check if the message contains a valid P2PS PD Request */
p2ps_validate_pd_req(struct p2p_data * p2p,struct p2p_message * msg,const u8 * addr)456780fb4a2SCy Schubert static int p2ps_validate_pd_req(struct p2p_data *p2p, struct p2p_message *msg,
457780fb4a2SCy Schubert const u8 *addr)
458780fb4a2SCy Schubert {
459780fb4a2SCy Schubert u8 group_id = 0;
460780fb4a2SCy Schubert u8 intended_addr = 0;
461780fb4a2SCy Schubert u8 operating_channel = 0;
462780fb4a2SCy Schubert u8 channel_list = 0;
463780fb4a2SCy Schubert u8 config_timeout = 0;
464780fb4a2SCy Schubert u8 listen_channel = 0;
465780fb4a2SCy Schubert
466780fb4a2SCy Schubert #define P2PS_PD_REQ_CHECK(_val, _attr) \
467780fb4a2SCy Schubert do { \
468780fb4a2SCy Schubert if ((_val) && !msg->_attr) { \
469780fb4a2SCy Schubert p2p_dbg(p2p, "Not P2PS PD Request. Missing %s", #_attr); \
470780fb4a2SCy Schubert return -1; \
471780fb4a2SCy Schubert } \
472780fb4a2SCy Schubert } while (0)
473780fb4a2SCy Schubert
474780fb4a2SCy Schubert P2PS_PD_REQ_CHECK(1, adv_id);
475780fb4a2SCy Schubert P2PS_PD_REQ_CHECK(1, session_id);
476780fb4a2SCy Schubert P2PS_PD_REQ_CHECK(1, session_mac);
477780fb4a2SCy Schubert P2PS_PD_REQ_CHECK(1, adv_mac);
478780fb4a2SCy Schubert P2PS_PD_REQ_CHECK(1, capability);
479780fb4a2SCy Schubert P2PS_PD_REQ_CHECK(1, p2p_device_info);
480780fb4a2SCy Schubert P2PS_PD_REQ_CHECK(1, feature_cap);
481780fb4a2SCy Schubert
482780fb4a2SCy Schubert /*
483780fb4a2SCy Schubert * We don't need to check Connection Capability, Persistent Group,
484780fb4a2SCy Schubert * and related attributes for follow-on PD Request with a status
485780fb4a2SCy Schubert * other than SUCCESS_DEFERRED.
486780fb4a2SCy Schubert */
487780fb4a2SCy Schubert if (msg->status && *msg->status != P2P_SC_SUCCESS_DEFERRED)
488780fb4a2SCy Schubert return 0;
489780fb4a2SCy Schubert
490780fb4a2SCy Schubert P2PS_PD_REQ_CHECK(1, conn_cap);
491780fb4a2SCy Schubert
492780fb4a2SCy Schubert /*
493780fb4a2SCy Schubert * Note 1: A feature capability attribute structure can be changed
494780fb4a2SCy Schubert * in the future. The assumption is that such modifications are
495780fb4a2SCy Schubert * backward compatible, therefore we allow processing of msg.feature_cap
496780fb4a2SCy Schubert * exceeding the size of the p2ps_feature_capab structure.
497780fb4a2SCy Schubert * Note 2: Verification of msg.feature_cap_len below has to be changed
498780fb4a2SCy Schubert * to allow 2 byte feature capability processing if
499780fb4a2SCy Schubert * struct p2ps_feature_capab is extended to include additional fields
500780fb4a2SCy Schubert * and it affects the structure size.
501780fb4a2SCy Schubert */
502780fb4a2SCy Schubert if (msg->feature_cap_len < sizeof(struct p2ps_feature_capab)) {
503780fb4a2SCy Schubert p2p_dbg(p2p, "P2PS: Invalid feature capability len");
504780fb4a2SCy Schubert return -1;
505780fb4a2SCy Schubert }
506780fb4a2SCy Schubert
507780fb4a2SCy Schubert switch (*msg->conn_cap) {
508780fb4a2SCy Schubert case P2PS_SETUP_NEW:
509780fb4a2SCy Schubert group_id = 1;
510780fb4a2SCy Schubert intended_addr = 1;
511780fb4a2SCy Schubert operating_channel = 1;
512780fb4a2SCy Schubert channel_list = 1;
513780fb4a2SCy Schubert config_timeout = 1;
514780fb4a2SCy Schubert listen_channel = 1;
515780fb4a2SCy Schubert break;
516780fb4a2SCy Schubert case P2PS_SETUP_CLIENT:
517780fb4a2SCy Schubert channel_list = 1;
518780fb4a2SCy Schubert listen_channel = 1;
519780fb4a2SCy Schubert break;
520780fb4a2SCy Schubert case P2PS_SETUP_GROUP_OWNER:
521780fb4a2SCy Schubert group_id = 1;
522780fb4a2SCy Schubert intended_addr = 1;
523780fb4a2SCy Schubert operating_channel = 1;
524780fb4a2SCy Schubert break;
525780fb4a2SCy Schubert case P2PS_SETUP_NEW | P2PS_SETUP_GROUP_OWNER:
526780fb4a2SCy Schubert group_id = 1;
527780fb4a2SCy Schubert operating_channel = 1;
528780fb4a2SCy Schubert intended_addr = 1;
529780fb4a2SCy Schubert channel_list = 1;
530780fb4a2SCy Schubert config_timeout = 1;
531780fb4a2SCy Schubert break;
532780fb4a2SCy Schubert case P2PS_SETUP_CLIENT | P2PS_SETUP_GROUP_OWNER:
533780fb4a2SCy Schubert group_id = 1;
534780fb4a2SCy Schubert intended_addr = 1;
535780fb4a2SCy Schubert operating_channel = 1;
536780fb4a2SCy Schubert channel_list = 1;
537780fb4a2SCy Schubert config_timeout = 1;
538780fb4a2SCy Schubert break;
539780fb4a2SCy Schubert default:
540780fb4a2SCy Schubert p2p_dbg(p2p, "Invalid P2PS PD connection capability");
541780fb4a2SCy Schubert return -1;
542780fb4a2SCy Schubert }
543780fb4a2SCy Schubert
544780fb4a2SCy Schubert if (msg->persistent_dev) {
545780fb4a2SCy Schubert channel_list = 1;
546780fb4a2SCy Schubert config_timeout = 1;
547*a90b9d01SCy Schubert if (ether_addr_equal(msg->persistent_dev, addr)) {
548780fb4a2SCy Schubert intended_addr = 1;
549780fb4a2SCy Schubert operating_channel = 1;
550780fb4a2SCy Schubert }
551780fb4a2SCy Schubert }
552780fb4a2SCy Schubert
553780fb4a2SCy Schubert P2PS_PD_REQ_CHECK(group_id, group_id);
554780fb4a2SCy Schubert P2PS_PD_REQ_CHECK(intended_addr, intended_addr);
555780fb4a2SCy Schubert P2PS_PD_REQ_CHECK(operating_channel, operating_channel);
556780fb4a2SCy Schubert P2PS_PD_REQ_CHECK(channel_list, channel_list);
557780fb4a2SCy Schubert P2PS_PD_REQ_CHECK(config_timeout, config_timeout);
558780fb4a2SCy Schubert P2PS_PD_REQ_CHECK(listen_channel, listen_channel);
559780fb4a2SCy Schubert
560780fb4a2SCy Schubert #undef P2PS_PD_REQ_CHECK
561780fb4a2SCy Schubert
562780fb4a2SCy Schubert return 0;
563780fb4a2SCy Schubert }
564780fb4a2SCy Schubert
565780fb4a2SCy Schubert
p2p_process_prov_disc_req(struct p2p_data * p2p,const u8 * sa,const u8 * data,size_t len,int rx_freq)566f05cddf9SRui Paulo void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
567f05cddf9SRui Paulo const u8 *data, size_t len, int rx_freq)
568f05cddf9SRui Paulo {
569f05cddf9SRui Paulo struct p2p_message msg;
570f05cddf9SRui Paulo struct p2p_device *dev;
571f05cddf9SRui Paulo int freq;
5725b9c547cSRui Paulo enum p2p_status_code reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
573f05cddf9SRui Paulo struct wpabuf *resp;
5745b9c547cSRui Paulo u32 adv_id = 0;
5755b9c547cSRui Paulo struct p2ps_advertisement *p2ps_adv = NULL;
5765b9c547cSRui Paulo u8 conncap = P2PS_SETUP_NEW;
5775b9c547cSRui Paulo u8 auto_accept = 0;
5785b9c547cSRui Paulo u32 session_id = 0;
579780fb4a2SCy Schubert u8 session_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
580780fb4a2SCy Schubert u8 adv_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
581325151a3SRui Paulo const u8 *group_mac;
5825b9c547cSRui Paulo int passwd_id = DEV_PW_DEFAULT;
5835b9c547cSRui Paulo u16 config_methods;
584325151a3SRui Paulo u16 allowed_config_methods = WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
585325151a3SRui Paulo struct p2ps_feature_capab resp_fcap = { 0, 0 };
586780fb4a2SCy Schubert struct p2ps_feature_capab *req_fcap = NULL;
587780fb4a2SCy Schubert u8 remote_conncap;
588780fb4a2SCy Schubert u16 method;
589f05cddf9SRui Paulo
590f05cddf9SRui Paulo if (p2p_parse(data, len, &msg))
591f05cddf9SRui Paulo return;
592f05cddf9SRui Paulo
5935b9c547cSRui Paulo p2p_dbg(p2p, "Received Provision Discovery Request from " MACSTR
594f05cddf9SRui Paulo " with config methods 0x%x (freq=%d)",
595f05cddf9SRui Paulo MAC2STR(sa), msg.wps_config_methods, rx_freq);
596325151a3SRui Paulo group_mac = msg.intended_addr;
597f05cddf9SRui Paulo
598f05cddf9SRui Paulo dev = p2p_get_device(p2p, sa);
599f05cddf9SRui Paulo if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
6005b9c547cSRui Paulo p2p_dbg(p2p, "Provision Discovery Request from unknown peer "
6015b9c547cSRui Paulo MACSTR, MAC2STR(sa));
602f05cddf9SRui Paulo
6035b9c547cSRui Paulo if (p2p_add_device(p2p, sa, rx_freq, NULL, 0, data + 1, len - 1,
604f05cddf9SRui Paulo 0)) {
6055b9c547cSRui Paulo p2p_dbg(p2p, "Provision Discovery Request add device failed "
6065b9c547cSRui Paulo MACSTR, MAC2STR(sa));
607780fb4a2SCy Schubert goto out;
608780fb4a2SCy Schubert }
609780fb4a2SCy Schubert
610780fb4a2SCy Schubert dev = p2p_get_device(p2p, sa);
611780fb4a2SCy Schubert if (!dev) {
612780fb4a2SCy Schubert p2p_dbg(p2p,
613780fb4a2SCy Schubert "Provision Discovery device not found "
614780fb4a2SCy Schubert MACSTR, MAC2STR(sa));
615780fb4a2SCy Schubert goto out;
616780fb4a2SCy Schubert }
617f05cddf9SRui Paulo } else if (msg.wfd_subelems) {
618f05cddf9SRui Paulo wpabuf_free(dev->info.wfd_subelems);
619f05cddf9SRui Paulo dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
620f05cddf9SRui Paulo }
621f05cddf9SRui Paulo
622*a90b9d01SCy Schubert p2p_update_peer_6ghz_capab(dev, &msg);
623*a90b9d01SCy Schubert
624780fb4a2SCy Schubert if (!msg.adv_id) {
625325151a3SRui Paulo allowed_config_methods |= WPS_CONFIG_PUSHBUTTON;
626325151a3SRui Paulo if (!(msg.wps_config_methods & allowed_config_methods)) {
627780fb4a2SCy Schubert p2p_dbg(p2p,
628780fb4a2SCy Schubert "Unsupported Config Methods in Provision Discovery Request");
629f05cddf9SRui Paulo goto out;
630f05cddf9SRui Paulo }
631f05cddf9SRui Paulo
6325b9c547cSRui Paulo /* Legacy (non-P2PS) - Unknown groups allowed for P2PS */
633780fb4a2SCy Schubert if (msg.group_id) {
634f05cddf9SRui Paulo size_t i;
635780fb4a2SCy Schubert
636f05cddf9SRui Paulo for (i = 0; i < p2p->num_groups; i++) {
637780fb4a2SCy Schubert if (p2p_group_is_group_id_match(
638780fb4a2SCy Schubert p2p->groups[i],
639780fb4a2SCy Schubert msg.group_id, msg.group_id_len))
640f05cddf9SRui Paulo break;
641f05cddf9SRui Paulo }
642f05cddf9SRui Paulo if (i == p2p->num_groups) {
643780fb4a2SCy Schubert p2p_dbg(p2p,
644780fb4a2SCy Schubert "PD request for unknown P2P Group ID - reject");
645f05cddf9SRui Paulo goto out;
646f05cddf9SRui Paulo }
647f05cddf9SRui Paulo }
648780fb4a2SCy Schubert } else {
649780fb4a2SCy Schubert allowed_config_methods |= WPS_CONFIG_P2PS;
650f05cddf9SRui Paulo
651780fb4a2SCy Schubert /*
652780fb4a2SCy Schubert * Set adv_id here, so in case of an error, a P2PS PD Response
653780fb4a2SCy Schubert * will be sent.
654780fb4a2SCy Schubert */
655780fb4a2SCy Schubert adv_id = WPA_GET_LE32(msg.adv_id);
656780fb4a2SCy Schubert if (p2ps_validate_pd_req(p2p, &msg, sa) < 0) {
657780fb4a2SCy Schubert reject = P2P_SC_FAIL_INVALID_PARAMS;
658780fb4a2SCy Schubert goto out;
659780fb4a2SCy Schubert }
660780fb4a2SCy Schubert
661780fb4a2SCy Schubert req_fcap = (struct p2ps_feature_capab *) msg.feature_cap;
662780fb4a2SCy Schubert
663780fb4a2SCy Schubert os_memcpy(session_mac, msg.session_mac, ETH_ALEN);
664780fb4a2SCy Schubert os_memcpy(adv_mac, msg.adv_mac, ETH_ALEN);
665780fb4a2SCy Schubert
666780fb4a2SCy Schubert session_id = WPA_GET_LE32(msg.session_id);
667780fb4a2SCy Schubert
668780fb4a2SCy Schubert if (msg.conn_cap)
669780fb4a2SCy Schubert conncap = *msg.conn_cap;
670780fb4a2SCy Schubert
671780fb4a2SCy Schubert /*
672780fb4a2SCy Schubert * We need to verify a P2PS config methog in an initial PD
673780fb4a2SCy Schubert * request or in a follow-on PD request with the status
674780fb4a2SCy Schubert * SUCCESS_DEFERRED.
675780fb4a2SCy Schubert */
676780fb4a2SCy Schubert if ((!msg.status || *msg.status == P2P_SC_SUCCESS_DEFERRED) &&
677780fb4a2SCy Schubert !(msg.wps_config_methods & allowed_config_methods)) {
678780fb4a2SCy Schubert p2p_dbg(p2p,
679780fb4a2SCy Schubert "Unsupported Config Methods in Provision Discovery Request");
680780fb4a2SCy Schubert goto out;
681780fb4a2SCy Schubert }
682780fb4a2SCy Schubert
683780fb4a2SCy Schubert /*
684780fb4a2SCy Schubert * TODO: since we don't support multiple PD, reject PD request
685780fb4a2SCy Schubert * if we are in the middle of P2PS PD with some other peer
686780fb4a2SCy Schubert */
687780fb4a2SCy Schubert }
688780fb4a2SCy Schubert
689f05cddf9SRui Paulo dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
6905b9c547cSRui Paulo P2P_DEV_PD_PEER_KEYPAD |
6915b9c547cSRui Paulo P2P_DEV_PD_PEER_P2PS);
6925b9c547cSRui Paulo
693780fb4a2SCy Schubert if (msg.wps_config_methods & WPS_CONFIG_DISPLAY) {
694780fb4a2SCy Schubert p2p_dbg(p2p, "Peer " MACSTR
695780fb4a2SCy Schubert " requested us to show a PIN on display", MAC2STR(sa));
696780fb4a2SCy Schubert dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
697780fb4a2SCy Schubert passwd_id = DEV_PW_USER_SPECIFIED;
698780fb4a2SCy Schubert } else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
699780fb4a2SCy Schubert p2p_dbg(p2p, "Peer " MACSTR
700780fb4a2SCy Schubert " requested us to write its PIN using keypad",
701780fb4a2SCy Schubert MAC2STR(sa));
702780fb4a2SCy Schubert dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
703780fb4a2SCy Schubert passwd_id = DEV_PW_REGISTRAR_SPECIFIED;
704780fb4a2SCy Schubert } else if (msg.wps_config_methods & WPS_CONFIG_P2PS) {
705780fb4a2SCy Schubert p2p_dbg(p2p, "Peer " MACSTR " requesting P2PS PIN",
706780fb4a2SCy Schubert MAC2STR(sa));
707780fb4a2SCy Schubert dev->flags |= P2P_DEV_PD_PEER_P2PS;
708780fb4a2SCy Schubert passwd_id = DEV_PW_P2PS_DEFAULT;
709780fb4a2SCy Schubert }
710780fb4a2SCy Schubert
7115b9c547cSRui Paulo /* Remove stale persistent groups */
7125b9c547cSRui Paulo if (p2p->cfg->remove_stale_groups) {
7135b9c547cSRui Paulo p2p->cfg->remove_stale_groups(
7145b9c547cSRui Paulo p2p->cfg->cb_ctx, dev->info.p2p_device_addr,
7155b9c547cSRui Paulo msg.persistent_dev,
7165b9c547cSRui Paulo msg.persistent_ssid, msg.persistent_ssid_len);
7175b9c547cSRui Paulo }
718f05cddf9SRui Paulo
7195b9c547cSRui Paulo reject = P2P_SC_SUCCESS;
7205b9c547cSRui Paulo
721780fb4a2SCy Schubert /*
722780fb4a2SCy Schubert * End of a legacy P2P PD Request processing, from this point continue
723780fb4a2SCy Schubert * with P2PS one.
724325151a3SRui Paulo */
725780fb4a2SCy Schubert if (!msg.adv_id)
726780fb4a2SCy Schubert goto out;
7275b9c547cSRui Paulo
7285b9c547cSRui Paulo remote_conncap = conncap;
7295b9c547cSRui Paulo
730780fb4a2SCy Schubert if (!msg.status) {
731780fb4a2SCy Schubert unsigned int forced_freq, pref_freq;
732780fb4a2SCy Schubert
733*a90b9d01SCy Schubert if (!ether_addr_equal(p2p->cfg->dev_addr, msg.adv_mac)) {
734780fb4a2SCy Schubert p2p_dbg(p2p,
735780fb4a2SCy Schubert "P2PS PD adv mac does not match the local one");
736780fb4a2SCy Schubert reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
737780fb4a2SCy Schubert goto out;
738780fb4a2SCy Schubert }
739780fb4a2SCy Schubert
740780fb4a2SCy Schubert p2ps_adv = p2p_service_p2ps_id(p2p, adv_id);
741780fb4a2SCy Schubert if (!p2ps_adv) {
742780fb4a2SCy Schubert p2p_dbg(p2p, "P2PS PD invalid adv_id=0x%X", adv_id);
743780fb4a2SCy Schubert reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
744780fb4a2SCy Schubert goto out;
745780fb4a2SCy Schubert }
746780fb4a2SCy Schubert p2p_dbg(p2p, "adv_id: 0x%X, p2ps_adv: %p", adv_id, p2ps_adv);
747780fb4a2SCy Schubert
7485b9c547cSRui Paulo auto_accept = p2ps_adv->auto_accept;
749780fb4a2SCy Schubert conncap = p2p->cfg->p2ps_group_capability(p2p->cfg->cb_ctx,
750780fb4a2SCy Schubert conncap, auto_accept,
751780fb4a2SCy Schubert &forced_freq,
752780fb4a2SCy Schubert &pref_freq);
7535b9c547cSRui Paulo
7545b9c547cSRui Paulo p2p_dbg(p2p, "Conncap: local:%d remote:%d result:%d",
7555b9c547cSRui Paulo auto_accept, remote_conncap, conncap);
7565b9c547cSRui Paulo
757780fb4a2SCy Schubert p2p_prepare_channel(p2p, dev, forced_freq, pref_freq, 0);
758780fb4a2SCy Schubert
759780fb4a2SCy Schubert resp_fcap.cpt = p2ps_own_preferred_cpt(p2ps_adv->cpt_priority,
760325151a3SRui Paulo req_fcap->cpt);
761325151a3SRui Paulo
762780fb4a2SCy Schubert p2p_dbg(p2p, "cpt: service:0x%x remote:0x%x result:0x%x",
763780fb4a2SCy Schubert p2ps_adv->cpt_mask, req_fcap->cpt, resp_fcap.cpt);
764325151a3SRui Paulo
765325151a3SRui Paulo if (!resp_fcap.cpt) {
766325151a3SRui Paulo p2p_dbg(p2p,
767325151a3SRui Paulo "Incompatible P2PS feature capability CPT bitmask");
768325151a3SRui Paulo reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
769325151a3SRui Paulo } else if (p2ps_adv->config_methods &&
7705b9c547cSRui Paulo !(msg.wps_config_methods &
7715b9c547cSRui Paulo p2ps_adv->config_methods)) {
7725b9c547cSRui Paulo p2p_dbg(p2p,
7735b9c547cSRui Paulo "Unsupported config methods in Provision Discovery Request (own=0x%x peer=0x%x)",
7745b9c547cSRui Paulo p2ps_adv->config_methods,
7755b9c547cSRui Paulo msg.wps_config_methods);
7765b9c547cSRui Paulo reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
7775b9c547cSRui Paulo } else if (!p2ps_adv->state) {
7785b9c547cSRui Paulo p2p_dbg(p2p, "P2PS state unavailable");
7795b9c547cSRui Paulo reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
7805b9c547cSRui Paulo } else if (!conncap) {
7815b9c547cSRui Paulo p2p_dbg(p2p, "Conncap resolution failed");
7825b9c547cSRui Paulo reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
7835b9c547cSRui Paulo }
7845b9c547cSRui Paulo
7855b9c547cSRui Paulo if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
7865b9c547cSRui Paulo p2p_dbg(p2p, "Keypad - always defer");
7875b9c547cSRui Paulo auto_accept = 0;
7885b9c547cSRui Paulo }
7895b9c547cSRui Paulo
790780fb4a2SCy Schubert if ((remote_conncap & (P2PS_SETUP_NEW | P2PS_SETUP_CLIENT) ||
791780fb4a2SCy Schubert msg.persistent_dev) && conncap != P2PS_SETUP_NEW &&
792780fb4a2SCy Schubert msg.channel_list && msg.channel_list_len &&
793780fb4a2SCy Schubert p2p_peer_channels_check(p2p, &p2p->channels, dev,
794780fb4a2SCy Schubert msg.channel_list,
795780fb4a2SCy Schubert msg.channel_list_len) < 0) {
796780fb4a2SCy Schubert p2p_dbg(p2p,
797780fb4a2SCy Schubert "No common channels - force deferred flow");
798780fb4a2SCy Schubert auto_accept = 0;
799780fb4a2SCy Schubert }
800780fb4a2SCy Schubert
801780fb4a2SCy Schubert if (((remote_conncap & P2PS_SETUP_GROUP_OWNER) ||
802780fb4a2SCy Schubert msg.persistent_dev) && msg.operating_channel) {
803780fb4a2SCy Schubert struct p2p_channels intersect;
804780fb4a2SCy Schubert
805780fb4a2SCy Schubert /*
806780fb4a2SCy Schubert * There are cases where only the operating channel is
807780fb4a2SCy Schubert * provided. This requires saving the channel as the
808780fb4a2SCy Schubert * supported channel list, and verifying that it is
809780fb4a2SCy Schubert * supported.
810780fb4a2SCy Schubert */
811780fb4a2SCy Schubert if (dev->channels.reg_classes == 0 ||
812780fb4a2SCy Schubert !p2p_channels_includes(&dev->channels,
813780fb4a2SCy Schubert msg.operating_channel[3],
814780fb4a2SCy Schubert msg.operating_channel[4])) {
815780fb4a2SCy Schubert struct p2p_channels *ch = &dev->channels;
816780fb4a2SCy Schubert
817780fb4a2SCy Schubert os_memset(ch, 0, sizeof(*ch));
818780fb4a2SCy Schubert ch->reg_class[0].reg_class =
819780fb4a2SCy Schubert msg.operating_channel[3];
820780fb4a2SCy Schubert ch->reg_class[0].channel[0] =
821780fb4a2SCy Schubert msg.operating_channel[4];
822780fb4a2SCy Schubert ch->reg_class[0].channels = 1;
823780fb4a2SCy Schubert ch->reg_classes = 1;
824780fb4a2SCy Schubert }
825780fb4a2SCy Schubert
826780fb4a2SCy Schubert p2p_channels_intersect(&p2p->channels, &dev->channels,
827780fb4a2SCy Schubert &intersect);
828780fb4a2SCy Schubert
829780fb4a2SCy Schubert if (intersect.reg_classes == 0) {
830780fb4a2SCy Schubert p2p_dbg(p2p,
831780fb4a2SCy Schubert "No common channels - force deferred flow");
832780fb4a2SCy Schubert auto_accept = 0;
833780fb4a2SCy Schubert }
834780fb4a2SCy Schubert }
835780fb4a2SCy Schubert
8365b9c547cSRui Paulo if (auto_accept || reject != P2P_SC_SUCCESS) {
8375b9c547cSRui Paulo struct p2ps_provision *tmp;
8385b9c547cSRui Paulo
839780fb4a2SCy Schubert if (p2ps_setup_p2ps_prov(p2p, adv_id, session_id,
8405b9c547cSRui Paulo msg.wps_config_methods,
8415b9c547cSRui Paulo session_mac, adv_mac) < 0) {
8425b9c547cSRui Paulo reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
8435b9c547cSRui Paulo goto out;
8445b9c547cSRui Paulo }
8455b9c547cSRui Paulo
8465b9c547cSRui Paulo tmp = p2p->p2ps_prov;
847780fb4a2SCy Schubert tmp->force_freq = forced_freq;
848780fb4a2SCy Schubert tmp->pref_freq = pref_freq;
8495b9c547cSRui Paulo if (conncap) {
8505b9c547cSRui Paulo tmp->conncap = conncap;
8515b9c547cSRui Paulo tmp->status = P2P_SC_SUCCESS;
8525b9c547cSRui Paulo } else {
8535b9c547cSRui Paulo tmp->conncap = auto_accept;
8545b9c547cSRui Paulo tmp->status = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
8555b9c547cSRui Paulo }
8565b9c547cSRui Paulo
8575b9c547cSRui Paulo if (reject != P2P_SC_SUCCESS)
8585b9c547cSRui Paulo goto out;
8595b9c547cSRui Paulo }
8605b9c547cSRui Paulo }
8615b9c547cSRui Paulo
8625b9c547cSRui Paulo if (!msg.status && !auto_accept &&
8635b9c547cSRui Paulo (!p2p->p2ps_prov || p2p->p2ps_prov->adv_id != adv_id)) {
8645b9c547cSRui Paulo struct p2ps_provision *tmp;
8655b9c547cSRui Paulo
8665b9c547cSRui Paulo if (!conncap) {
8675b9c547cSRui Paulo reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
8685b9c547cSRui Paulo goto out;
8695b9c547cSRui Paulo }
8705b9c547cSRui Paulo
8715b9c547cSRui Paulo if (p2ps_setup_p2ps_prov(p2p, adv_id, session_id,
8725b9c547cSRui Paulo msg.wps_config_methods,
8735b9c547cSRui Paulo session_mac, adv_mac) < 0) {
8745b9c547cSRui Paulo reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
8755b9c547cSRui Paulo goto out;
8765b9c547cSRui Paulo }
8775b9c547cSRui Paulo tmp = p2p->p2ps_prov;
8785b9c547cSRui Paulo reject = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
8795b9c547cSRui Paulo tmp->status = reject;
8805b9c547cSRui Paulo }
8815b9c547cSRui Paulo
882780fb4a2SCy Schubert /* Not a P2PS Follow-on PD */
883780fb4a2SCy Schubert if (!msg.status)
884780fb4a2SCy Schubert goto out;
885780fb4a2SCy Schubert
886780fb4a2SCy Schubert if (*msg.status && *msg.status != P2P_SC_SUCCESS_DEFERRED) {
8875b9c547cSRui Paulo reject = *msg.status;
888780fb4a2SCy Schubert goto out;
889780fb4a2SCy Schubert }
8905b9c547cSRui Paulo
891780fb4a2SCy Schubert if (*msg.status != P2P_SC_SUCCESS_DEFERRED || !p2p->p2ps_prov)
892780fb4a2SCy Schubert goto out;
8935b9c547cSRui Paulo
894780fb4a2SCy Schubert if (p2p->p2ps_prov->adv_id != adv_id ||
895*a90b9d01SCy Schubert !ether_addr_equal(p2p->p2ps_prov->adv_mac, msg.adv_mac)) {
8965b9c547cSRui Paulo p2p_dbg(p2p,
897780fb4a2SCy Schubert "P2PS Follow-on PD with mismatch Advertisement ID/MAC");
898780fb4a2SCy Schubert goto out;
899780fb4a2SCy Schubert }
9005b9c547cSRui Paulo
901780fb4a2SCy Schubert if (p2p->p2ps_prov->session_id != session_id ||
902*a90b9d01SCy Schubert !ether_addr_equal(p2p->p2ps_prov->session_mac, msg.session_mac)) {
903780fb4a2SCy Schubert p2p_dbg(p2p, "P2PS Follow-on PD with mismatch Session ID/MAC");
904780fb4a2SCy Schubert goto out;
905780fb4a2SCy Schubert }
906780fb4a2SCy Schubert
907780fb4a2SCy Schubert method = p2p->p2ps_prov->method;
908780fb4a2SCy Schubert
909780fb4a2SCy Schubert conncap = p2p->cfg->p2ps_group_capability(p2p->cfg->cb_ctx,
910780fb4a2SCy Schubert remote_conncap,
911780fb4a2SCy Schubert p2p->p2ps_prov->conncap,
912780fb4a2SCy Schubert &p2p->p2ps_prov->force_freq,
913780fb4a2SCy Schubert &p2p->p2ps_prov->pref_freq);
914780fb4a2SCy Schubert
915780fb4a2SCy Schubert resp_fcap.cpt = p2ps_own_preferred_cpt(p2p->p2ps_prov->cpt_priority,
916325151a3SRui Paulo req_fcap->cpt);
917325151a3SRui Paulo
918780fb4a2SCy Schubert p2p_dbg(p2p, "cpt: local:0x%x remote:0x%x result:0x%x",
919780fb4a2SCy Schubert p2p->p2ps_prov->cpt_mask, req_fcap->cpt, resp_fcap.cpt);
920780fb4a2SCy Schubert
921780fb4a2SCy Schubert p2p_prepare_channel(p2p, dev, p2p->p2ps_prov->force_freq,
922780fb4a2SCy Schubert p2p->p2ps_prov->pref_freq, 0);
923325151a3SRui Paulo
9245b9c547cSRui Paulo /*
925780fb4a2SCy Schubert * Ensure that if we asked for PIN originally, our method is consistent
926780fb4a2SCy Schubert * with original request.
9275b9c547cSRui Paulo */
9285b9c547cSRui Paulo if (method & WPS_CONFIG_DISPLAY)
9295b9c547cSRui Paulo method = WPS_CONFIG_KEYPAD;
9305b9c547cSRui Paulo else if (method & WPS_CONFIG_KEYPAD)
9315b9c547cSRui Paulo method = WPS_CONFIG_DISPLAY;
9325b9c547cSRui Paulo
933780fb4a2SCy Schubert if (!conncap || !(msg.wps_config_methods & method)) {
934325151a3SRui Paulo /*
935325151a3SRui Paulo * Reject this "Deferred Accept*
936325151a3SRui Paulo * if incompatible conncap or method
937325151a3SRui Paulo */
938780fb4a2SCy Schubert reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
939325151a3SRui Paulo } else if (!resp_fcap.cpt) {
940325151a3SRui Paulo p2p_dbg(p2p,
941325151a3SRui Paulo "Incompatible P2PS feature capability CPT bitmask");
942780fb4a2SCy Schubert reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
943780fb4a2SCy Schubert } else if ((remote_conncap & (P2PS_SETUP_NEW | P2PS_SETUP_CLIENT) ||
944780fb4a2SCy Schubert msg.persistent_dev) && conncap != P2PS_SETUP_NEW &&
945780fb4a2SCy Schubert msg.channel_list && msg.channel_list_len &&
946780fb4a2SCy Schubert p2p_peer_channels_check(p2p, &p2p->channels, dev,
947780fb4a2SCy Schubert msg.channel_list,
948780fb4a2SCy Schubert msg.channel_list_len) < 0) {
949780fb4a2SCy Schubert p2p_dbg(p2p,
950780fb4a2SCy Schubert "No common channels in Follow-On Provision Discovery Request");
951780fb4a2SCy Schubert reject = P2P_SC_FAIL_NO_COMMON_CHANNELS;
952325151a3SRui Paulo } else {
9535b9c547cSRui Paulo reject = P2P_SC_SUCCESS;
954325151a3SRui Paulo }
9555b9c547cSRui Paulo
956780fb4a2SCy Schubert dev->oper_freq = 0;
957780fb4a2SCy Schubert if (reject == P2P_SC_SUCCESS || reject == P2P_SC_SUCCESS_DEFERRED) {
958780fb4a2SCy Schubert u8 tmp;
959780fb4a2SCy Schubert
960780fb4a2SCy Schubert if (msg.operating_channel)
961780fb4a2SCy Schubert dev->oper_freq =
962780fb4a2SCy Schubert p2p_channel_to_freq(msg.operating_channel[3],
963780fb4a2SCy Schubert msg.operating_channel[4]);
964780fb4a2SCy Schubert
965780fb4a2SCy Schubert if ((conncap & P2PS_SETUP_GROUP_OWNER) &&
966780fb4a2SCy Schubert p2p_go_select_channel(p2p, dev, &tmp) < 0)
967780fb4a2SCy Schubert reject = P2P_SC_FAIL_NO_COMMON_CHANNELS;
968780fb4a2SCy Schubert }
969780fb4a2SCy Schubert
9705b9c547cSRui Paulo p2p->p2ps_prov->status = reject;
9715b9c547cSRui Paulo p2p->p2ps_prov->conncap = conncap;
972f05cddf9SRui Paulo
973f05cddf9SRui Paulo out:
9745b9c547cSRui Paulo if (reject == P2P_SC_SUCCESS ||
9755b9c547cSRui Paulo reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE)
9765b9c547cSRui Paulo config_methods = msg.wps_config_methods;
9775b9c547cSRui Paulo else
9785b9c547cSRui Paulo config_methods = 0;
979780fb4a2SCy Schubert
980780fb4a2SCy Schubert /*
981780fb4a2SCy Schubert * Send PD Response for an initial PD Request or for follow-on
982780fb4a2SCy Schubert * PD Request with P2P_SC_SUCCESS_DEFERRED status.
983780fb4a2SCy Schubert */
984780fb4a2SCy Schubert if (!msg.status || *msg.status == P2P_SC_SUCCESS_DEFERRED) {
985780fb4a2SCy Schubert resp = p2p_build_prov_disc_resp(p2p, dev, msg.dialog_token,
986780fb4a2SCy Schubert reject, config_methods, adv_id,
9875b9c547cSRui Paulo msg.group_id, msg.group_id_len,
9885b9c547cSRui Paulo msg.persistent_ssid,
989325151a3SRui Paulo msg.persistent_ssid_len,
990325151a3SRui Paulo (const u8 *) &resp_fcap,
991325151a3SRui Paulo sizeof(resp_fcap));
992780fb4a2SCy Schubert if (!resp) {
993f05cddf9SRui Paulo p2p_parse_free(&msg);
994f05cddf9SRui Paulo return;
995f05cddf9SRui Paulo }
9965b9c547cSRui Paulo p2p_dbg(p2p, "Sending Provision Discovery Response");
997f05cddf9SRui Paulo if (rx_freq > 0)
998f05cddf9SRui Paulo freq = rx_freq;
999f05cddf9SRui Paulo else
10005b9c547cSRui Paulo freq = p2p_channel_to_freq(p2p->cfg->reg_class,
1001f05cddf9SRui Paulo p2p->cfg->channel);
1002f05cddf9SRui Paulo if (freq < 0) {
10035b9c547cSRui Paulo p2p_dbg(p2p, "Unknown regulatory class/channel");
1004f05cddf9SRui Paulo wpabuf_free(resp);
1005f05cddf9SRui Paulo p2p_parse_free(&msg);
1006f05cddf9SRui Paulo return;
1007f05cddf9SRui Paulo }
10085b9c547cSRui Paulo p2p->pending_action_state = P2P_PENDING_PD_RESPONSE;
1009f05cddf9SRui Paulo if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr,
1010f05cddf9SRui Paulo p2p->cfg->dev_addr,
1011780fb4a2SCy Schubert wpabuf_head(resp), wpabuf_len(resp),
1012780fb4a2SCy Schubert 50) < 0)
10135b9c547cSRui Paulo p2p_dbg(p2p, "Failed to send Action frame");
1014780fb4a2SCy Schubert else
10155b9c547cSRui Paulo p2p->send_action_in_progress = 1;
1016f05cddf9SRui Paulo
1017f05cddf9SRui Paulo wpabuf_free(resp);
1018780fb4a2SCy Schubert }
1019780fb4a2SCy Schubert
1020780fb4a2SCy Schubert if (!dev) {
1021780fb4a2SCy Schubert p2p_parse_free(&msg);
1022780fb4a2SCy Schubert return;
1023780fb4a2SCy Schubert }
1024780fb4a2SCy Schubert
1025780fb4a2SCy Schubert freq = 0;
1026780fb4a2SCy Schubert if (reject == P2P_SC_SUCCESS && conncap == P2PS_SETUP_GROUP_OWNER) {
1027780fb4a2SCy Schubert freq = p2p_channel_to_freq(p2p->op_reg_class,
1028780fb4a2SCy Schubert p2p->op_channel);
1029780fb4a2SCy Schubert if (freq < 0)
1030780fb4a2SCy Schubert freq = 0;
1031780fb4a2SCy Schubert }
1032f05cddf9SRui Paulo
10335b9c547cSRui Paulo if (!p2p->cfg->p2ps_prov_complete) {
10345b9c547cSRui Paulo /* Don't emit anything */
10355b9c547cSRui Paulo } else if (msg.status && *msg.status != P2P_SC_SUCCESS &&
10365b9c547cSRui Paulo *msg.status != P2P_SC_SUCCESS_DEFERRED) {
10375b9c547cSRui Paulo reject = *msg.status;
10385b9c547cSRui Paulo p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, reject,
10395b9c547cSRui Paulo sa, adv_mac, session_mac,
10405b9c547cSRui Paulo NULL, adv_id, session_id,
10415b9c547cSRui Paulo 0, 0, msg.persistent_ssid,
10425b9c547cSRui Paulo msg.persistent_ssid_len,
1043780fb4a2SCy Schubert 0, 0, NULL, NULL, 0, freq,
1044780fb4a2SCy Schubert NULL, 0);
10455b9c547cSRui Paulo } else if (msg.status && *msg.status == P2P_SC_SUCCESS_DEFERRED &&
10465b9c547cSRui Paulo p2p->p2ps_prov) {
10475b9c547cSRui Paulo p2p->p2ps_prov->status = reject;
10485b9c547cSRui Paulo p2p->p2ps_prov->conncap = conncap;
10495b9c547cSRui Paulo
10505b9c547cSRui Paulo if (reject != P2P_SC_SUCCESS)
10515b9c547cSRui Paulo p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, reject,
10525b9c547cSRui Paulo sa, adv_mac, session_mac,
10535b9c547cSRui Paulo NULL, adv_id,
10545b9c547cSRui Paulo session_id, conncap, 0,
10555b9c547cSRui Paulo msg.persistent_ssid,
10565b9c547cSRui Paulo msg.persistent_ssid_len, 0,
1057780fb4a2SCy Schubert 0, NULL, NULL, 0, freq,
1058780fb4a2SCy Schubert NULL, 0);
10595b9c547cSRui Paulo else
10605b9c547cSRui Paulo p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx,
10615b9c547cSRui Paulo *msg.status,
10625b9c547cSRui Paulo sa, adv_mac, session_mac,
10635b9c547cSRui Paulo group_mac, adv_id,
10645b9c547cSRui Paulo session_id, conncap,
10655b9c547cSRui Paulo passwd_id,
10665b9c547cSRui Paulo msg.persistent_ssid,
10675b9c547cSRui Paulo msg.persistent_ssid_len, 0,
1068325151a3SRui Paulo 0, NULL,
1069325151a3SRui Paulo (const u8 *) &resp_fcap,
1070780fb4a2SCy Schubert sizeof(resp_fcap), freq,
1071780fb4a2SCy Schubert NULL, 0);
10725b9c547cSRui Paulo } else if (msg.status && p2p->p2ps_prov) {
10735b9c547cSRui Paulo p2p->p2ps_prov->status = P2P_SC_SUCCESS;
10745b9c547cSRui Paulo p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, *msg.status, sa,
10755b9c547cSRui Paulo adv_mac, session_mac, group_mac,
10765b9c547cSRui Paulo adv_id, session_id, conncap,
10775b9c547cSRui Paulo passwd_id,
10785b9c547cSRui Paulo msg.persistent_ssid,
10795b9c547cSRui Paulo msg.persistent_ssid_len,
1080325151a3SRui Paulo 0, 0, NULL,
1081325151a3SRui Paulo (const u8 *) &resp_fcap,
1082780fb4a2SCy Schubert sizeof(resp_fcap), freq, NULL, 0);
10835b9c547cSRui Paulo } else if (msg.status) {
10845b9c547cSRui Paulo } else if (auto_accept && reject == P2P_SC_SUCCESS) {
10855b9c547cSRui Paulo p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, P2P_SC_SUCCESS,
10865b9c547cSRui Paulo sa, adv_mac, session_mac,
10875b9c547cSRui Paulo group_mac, adv_id, session_id,
10885b9c547cSRui Paulo conncap, passwd_id,
10895b9c547cSRui Paulo msg.persistent_ssid,
10905b9c547cSRui Paulo msg.persistent_ssid_len,
1091325151a3SRui Paulo 0, 0, NULL,
1092325151a3SRui Paulo (const u8 *) &resp_fcap,
1093780fb4a2SCy Schubert sizeof(resp_fcap), freq,
1094780fb4a2SCy Schubert msg.group_id ?
1095780fb4a2SCy Schubert msg.group_id + ETH_ALEN : NULL,
1096780fb4a2SCy Schubert msg.group_id ?
1097780fb4a2SCy Schubert msg.group_id_len - ETH_ALEN : 0);
10985b9c547cSRui Paulo } else if (reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE &&
10995b9c547cSRui Paulo (!msg.session_info || !msg.session_info_len)) {
11005b9c547cSRui Paulo p2p->p2ps_prov->method = msg.wps_config_methods;
11015b9c547cSRui Paulo
11025b9c547cSRui Paulo p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, P2P_SC_SUCCESS,
11035b9c547cSRui Paulo sa, adv_mac, session_mac,
11045b9c547cSRui Paulo group_mac, adv_id, session_id,
11055b9c547cSRui Paulo conncap, passwd_id,
11065b9c547cSRui Paulo msg.persistent_ssid,
11075b9c547cSRui Paulo msg.persistent_ssid_len,
1108325151a3SRui Paulo 0, 1, NULL,
1109325151a3SRui Paulo (const u8 *) &resp_fcap,
1110780fb4a2SCy Schubert sizeof(resp_fcap), freq, NULL, 0);
11115b9c547cSRui Paulo } else if (reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) {
11125b9c547cSRui Paulo size_t buf_len = msg.session_info_len;
11135b9c547cSRui Paulo char *buf = os_malloc(2 * buf_len + 1);
11145b9c547cSRui Paulo
11155b9c547cSRui Paulo if (buf) {
11165b9c547cSRui Paulo p2p->p2ps_prov->method = msg.wps_config_methods;
11175b9c547cSRui Paulo
11185b9c547cSRui Paulo utf8_escape((char *) msg.session_info, buf_len,
11195b9c547cSRui Paulo buf, 2 * buf_len + 1);
11205b9c547cSRui Paulo
11215b9c547cSRui Paulo p2p->cfg->p2ps_prov_complete(
11225b9c547cSRui Paulo p2p->cfg->cb_ctx, P2P_SC_SUCCESS, sa,
11235b9c547cSRui Paulo adv_mac, session_mac, group_mac, adv_id,
11245b9c547cSRui Paulo session_id, conncap, passwd_id,
11255b9c547cSRui Paulo msg.persistent_ssid, msg.persistent_ssid_len,
1126325151a3SRui Paulo 0, 1, buf,
1127780fb4a2SCy Schubert (const u8 *) &resp_fcap, sizeof(resp_fcap),
1128780fb4a2SCy Schubert freq, NULL, 0);
11295b9c547cSRui Paulo
11305b9c547cSRui Paulo os_free(buf);
11315b9c547cSRui Paulo }
11325b9c547cSRui Paulo }
11335b9c547cSRui Paulo
1134325151a3SRui Paulo /*
1135325151a3SRui Paulo * prov_disc_req callback is used to generate P2P-PROV-DISC-ENTER-PIN,
1136325151a3SRui Paulo * P2P-PROV-DISC-SHOW-PIN, and P2P-PROV-DISC-PBC-REQ events.
1137325151a3SRui Paulo * Call it either on legacy P2P PD or on P2PS PD only if we need to
1138325151a3SRui Paulo * enter/show PIN.
1139325151a3SRui Paulo *
1140325151a3SRui Paulo * The callback is called in the following cases:
1141325151a3SRui Paulo * 1. Legacy P2P PD request, response status SUCCESS
1142325151a3SRui Paulo * 2. P2PS advertiser, method: DISPLAY, autoaccept: TRUE,
1143325151a3SRui Paulo * response status: SUCCESS
1144325151a3SRui Paulo * 3. P2PS advertiser, method DISPLAY, autoaccept: FALSE,
1145325151a3SRui Paulo * response status: INFO_CURRENTLY_UNAVAILABLE
1146325151a3SRui Paulo * 4. P2PS advertiser, method: KEYPAD, autoaccept==any,
1147325151a3SRui Paulo * response status: INFO_CURRENTLY_UNAVAILABLE
1148325151a3SRui Paulo * 5. P2PS follow-on with SUCCESS_DEFERRED,
1149325151a3SRui Paulo * advertiser role: DISPLAY, autoaccept: FALSE,
1150325151a3SRui Paulo * seeker: KEYPAD, response status: SUCCESS
1151325151a3SRui Paulo */
1152325151a3SRui Paulo if (p2p->cfg->prov_disc_req &&
1153325151a3SRui Paulo ((reject == P2P_SC_SUCCESS && !msg.adv_id) ||
1154325151a3SRui Paulo (!msg.status &&
1155325151a3SRui Paulo (reject == P2P_SC_SUCCESS ||
1156325151a3SRui Paulo reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) &&
1157325151a3SRui Paulo passwd_id == DEV_PW_USER_SPECIFIED) ||
1158325151a3SRui Paulo (!msg.status &&
1159325151a3SRui Paulo reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE &&
1160325151a3SRui Paulo passwd_id == DEV_PW_REGISTRAR_SPECIFIED) ||
1161325151a3SRui Paulo (reject == P2P_SC_SUCCESS &&
1162325151a3SRui Paulo msg.status && *msg.status == P2P_SC_SUCCESS_DEFERRED &&
1163325151a3SRui Paulo passwd_id == DEV_PW_REGISTRAR_SPECIFIED))) {
1164f05cddf9SRui Paulo const u8 *dev_addr = sa;
1165325151a3SRui Paulo
1166f05cddf9SRui Paulo if (msg.p2p_device_addr)
1167f05cddf9SRui Paulo dev_addr = msg.p2p_device_addr;
1168f05cddf9SRui Paulo p2p->cfg->prov_disc_req(p2p->cfg->cb_ctx, sa,
1169f05cddf9SRui Paulo msg.wps_config_methods,
1170f05cddf9SRui Paulo dev_addr, msg.pri_dev_type,
1171f05cddf9SRui Paulo msg.device_name, msg.config_methods,
1172f05cddf9SRui Paulo msg.capability ? msg.capability[0] : 0,
1173f05cddf9SRui Paulo msg.capability ? msg.capability[1] :
1174f05cddf9SRui Paulo 0,
1175f05cddf9SRui Paulo msg.group_id, msg.group_id_len);
1176f05cddf9SRui Paulo }
1177325151a3SRui Paulo
117885732ac8SCy Schubert if (reject != P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE)
117985732ac8SCy Schubert p2ps_prov_free(p2p);
118085732ac8SCy Schubert
1181780fb4a2SCy Schubert if (reject == P2P_SC_SUCCESS) {
1182325151a3SRui Paulo switch (config_methods) {
1183325151a3SRui Paulo case WPS_CONFIG_DISPLAY:
1184325151a3SRui Paulo dev->wps_prov_info = WPS_CONFIG_KEYPAD;
1185325151a3SRui Paulo break;
1186325151a3SRui Paulo case WPS_CONFIG_KEYPAD:
1187325151a3SRui Paulo dev->wps_prov_info = WPS_CONFIG_DISPLAY;
1188325151a3SRui Paulo break;
1189325151a3SRui Paulo case WPS_CONFIG_PUSHBUTTON:
1190325151a3SRui Paulo dev->wps_prov_info = WPS_CONFIG_PUSHBUTTON;
1191325151a3SRui Paulo break;
1192325151a3SRui Paulo case WPS_CONFIG_P2PS:
1193325151a3SRui Paulo dev->wps_prov_info = WPS_CONFIG_P2PS;
1194325151a3SRui Paulo break;
1195325151a3SRui Paulo default:
1196325151a3SRui Paulo dev->wps_prov_info = 0;
1197325151a3SRui Paulo break;
1198325151a3SRui Paulo }
1199325151a3SRui Paulo
1200325151a3SRui Paulo if (msg.intended_addr)
1201325151a3SRui Paulo os_memcpy(dev->interface_addr, msg.intended_addr,
1202325151a3SRui Paulo ETH_ALEN);
1203325151a3SRui Paulo }
1204f05cddf9SRui Paulo p2p_parse_free(&msg);
1205f05cddf9SRui Paulo }
1206f05cddf9SRui Paulo
1207f05cddf9SRui Paulo
p2p_validate_p2ps_pd_resp(struct p2p_data * p2p,struct p2p_message * msg)1208325151a3SRui Paulo static int p2p_validate_p2ps_pd_resp(struct p2p_data *p2p,
1209325151a3SRui Paulo struct p2p_message *msg)
1210325151a3SRui Paulo {
1211325151a3SRui Paulo u8 conn_cap_go = 0;
1212325151a3SRui Paulo u8 conn_cap_cli = 0;
1213325151a3SRui Paulo u32 session_id;
1214325151a3SRui Paulo u32 adv_id;
1215325151a3SRui Paulo
1216325151a3SRui Paulo #define P2PS_PD_RESP_CHECK(_val, _attr) \
1217325151a3SRui Paulo do { \
1218325151a3SRui Paulo if ((_val) && !msg->_attr) { \
1219325151a3SRui Paulo p2p_dbg(p2p, "P2PS PD Response missing " #_attr); \
1220325151a3SRui Paulo return -1; \
1221325151a3SRui Paulo } \
1222325151a3SRui Paulo } while (0)
1223325151a3SRui Paulo
1224325151a3SRui Paulo P2PS_PD_RESP_CHECK(1, status);
1225325151a3SRui Paulo P2PS_PD_RESP_CHECK(1, adv_id);
1226325151a3SRui Paulo P2PS_PD_RESP_CHECK(1, adv_mac);
1227325151a3SRui Paulo P2PS_PD_RESP_CHECK(1, capability);
1228325151a3SRui Paulo P2PS_PD_RESP_CHECK(1, p2p_device_info);
1229325151a3SRui Paulo P2PS_PD_RESP_CHECK(1, session_id);
1230325151a3SRui Paulo P2PS_PD_RESP_CHECK(1, session_mac);
1231325151a3SRui Paulo P2PS_PD_RESP_CHECK(1, feature_cap);
1232325151a3SRui Paulo
1233325151a3SRui Paulo session_id = WPA_GET_LE32(msg->session_id);
1234325151a3SRui Paulo adv_id = WPA_GET_LE32(msg->adv_id);
1235325151a3SRui Paulo
1236325151a3SRui Paulo if (p2p->p2ps_prov->session_id != session_id) {
1237325151a3SRui Paulo p2p_dbg(p2p,
1238325151a3SRui Paulo "Ignore PD Response with unexpected Session ID");
1239325151a3SRui Paulo return -1;
1240325151a3SRui Paulo }
1241325151a3SRui Paulo
1242*a90b9d01SCy Schubert if (!ether_addr_equal(p2p->p2ps_prov->session_mac, msg->session_mac)) {
1243325151a3SRui Paulo p2p_dbg(p2p,
1244325151a3SRui Paulo "Ignore PD Response with unexpected Session MAC");
1245325151a3SRui Paulo return -1;
1246325151a3SRui Paulo }
1247325151a3SRui Paulo
1248325151a3SRui Paulo if (p2p->p2ps_prov->adv_id != adv_id) {
1249325151a3SRui Paulo p2p_dbg(p2p,
1250325151a3SRui Paulo "Ignore PD Response with unexpected Advertisement ID");
1251325151a3SRui Paulo return -1;
1252325151a3SRui Paulo }
1253325151a3SRui Paulo
1254*a90b9d01SCy Schubert if (!ether_addr_equal(p2p->p2ps_prov->adv_mac, msg->adv_mac)) {
1255325151a3SRui Paulo p2p_dbg(p2p,
1256325151a3SRui Paulo "Ignore PD Response with unexpected Advertisement MAC");
1257325151a3SRui Paulo return -1;
1258325151a3SRui Paulo }
1259325151a3SRui Paulo
1260325151a3SRui Paulo if (msg->listen_channel) {
1261325151a3SRui Paulo p2p_dbg(p2p,
1262325151a3SRui Paulo "Ignore malformed PD Response - unexpected Listen Channel");
1263325151a3SRui Paulo return -1;
1264325151a3SRui Paulo }
1265325151a3SRui Paulo
1266325151a3SRui Paulo if (*msg->status == P2P_SC_SUCCESS &&
1267325151a3SRui Paulo !(!!msg->conn_cap ^ !!msg->persistent_dev)) {
1268325151a3SRui Paulo p2p_dbg(p2p,
1269325151a3SRui Paulo "Ignore malformed PD Response - either conn_cap or persistent group should be present");
1270325151a3SRui Paulo return -1;
1271325151a3SRui Paulo }
1272325151a3SRui Paulo
1273325151a3SRui Paulo if (msg->persistent_dev && *msg->status != P2P_SC_SUCCESS) {
1274325151a3SRui Paulo p2p_dbg(p2p,
1275325151a3SRui Paulo "Ignore malformed PD Response - persistent group is present, but the status isn't success");
1276325151a3SRui Paulo return -1;
1277325151a3SRui Paulo }
1278325151a3SRui Paulo
1279325151a3SRui Paulo if (msg->conn_cap) {
1280325151a3SRui Paulo conn_cap_go = *msg->conn_cap == P2PS_SETUP_GROUP_OWNER;
1281325151a3SRui Paulo conn_cap_cli = *msg->conn_cap == P2PS_SETUP_CLIENT;
1282325151a3SRui Paulo }
1283325151a3SRui Paulo
1284325151a3SRui Paulo P2PS_PD_RESP_CHECK(msg->persistent_dev || conn_cap_go || conn_cap_cli,
1285325151a3SRui Paulo channel_list);
1286325151a3SRui Paulo P2PS_PD_RESP_CHECK(msg->persistent_dev || conn_cap_go || conn_cap_cli,
1287325151a3SRui Paulo config_timeout);
1288325151a3SRui Paulo
1289325151a3SRui Paulo P2PS_PD_RESP_CHECK(conn_cap_go, group_id);
1290325151a3SRui Paulo P2PS_PD_RESP_CHECK(conn_cap_go, intended_addr);
1291325151a3SRui Paulo P2PS_PD_RESP_CHECK(conn_cap_go, operating_channel);
1292325151a3SRui Paulo /*
1293325151a3SRui Paulo * TODO: Also validate that operating channel is present if the device
1294325151a3SRui Paulo * is a GO in a persistent group. We can't do it here since we don't
1295325151a3SRui Paulo * know what is the role of the peer. It should be probably done in
1296325151a3SRui Paulo * p2ps_prov_complete callback, but currently operating channel isn't
1297325151a3SRui Paulo * passed to it.
1298325151a3SRui Paulo */
1299325151a3SRui Paulo
1300325151a3SRui Paulo #undef P2PS_PD_RESP_CHECK
1301325151a3SRui Paulo
1302325151a3SRui Paulo return 0;
1303325151a3SRui Paulo }
1304325151a3SRui Paulo
1305325151a3SRui Paulo
p2p_process_prov_disc_resp(struct p2p_data * p2p,const u8 * sa,const u8 * data,size_t len)1306f05cddf9SRui Paulo void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
1307f05cddf9SRui Paulo const u8 *data, size_t len)
1308f05cddf9SRui Paulo {
1309f05cddf9SRui Paulo struct p2p_message msg;
1310f05cddf9SRui Paulo struct p2p_device *dev;
13115b9c547cSRui Paulo u16 report_config_methods = 0, req_config_methods;
13125b9c547cSRui Paulo u8 status = P2P_SC_SUCCESS;
13135b9c547cSRui Paulo u32 adv_id = 0;
13145b9c547cSRui Paulo u8 conncap = P2PS_SETUP_NEW;
13155b9c547cSRui Paulo u8 adv_mac[ETH_ALEN];
1316325151a3SRui Paulo const u8 *group_mac;
13175b9c547cSRui Paulo int passwd_id = DEV_PW_DEFAULT;
1318325151a3SRui Paulo int p2ps_seeker;
1319f05cddf9SRui Paulo
1320f05cddf9SRui Paulo if (p2p_parse(data, len, &msg))
1321f05cddf9SRui Paulo return;
1322f05cddf9SRui Paulo
1323325151a3SRui Paulo if (p2p->p2ps_prov && p2p_validate_p2ps_pd_resp(p2p, &msg)) {
1324325151a3SRui Paulo p2p_parse_free(&msg);
1325325151a3SRui Paulo return;
1326325151a3SRui Paulo }
1327325151a3SRui Paulo
13285b9c547cSRui Paulo /* Parse the P2PS members present */
13295b9c547cSRui Paulo if (msg.status)
13305b9c547cSRui Paulo status = *msg.status;
13315b9c547cSRui Paulo
1332325151a3SRui Paulo group_mac = msg.intended_addr;
13335b9c547cSRui Paulo
13345b9c547cSRui Paulo if (msg.adv_mac)
13355b9c547cSRui Paulo os_memcpy(adv_mac, msg.adv_mac, ETH_ALEN);
13365b9c547cSRui Paulo else
13375b9c547cSRui Paulo os_memset(adv_mac, 0, ETH_ALEN);
13385b9c547cSRui Paulo
13395b9c547cSRui Paulo if (msg.adv_id)
13405b9c547cSRui Paulo adv_id = WPA_GET_LE32(msg.adv_id);
13415b9c547cSRui Paulo
13425b9c547cSRui Paulo if (msg.conn_cap) {
13435b9c547cSRui Paulo conncap = *msg.conn_cap;
13445b9c547cSRui Paulo
13455b9c547cSRui Paulo /* Switch bits to local relative */
13465b9c547cSRui Paulo switch (conncap) {
13475b9c547cSRui Paulo case P2PS_SETUP_GROUP_OWNER:
13485b9c547cSRui Paulo conncap = P2PS_SETUP_CLIENT;
13495b9c547cSRui Paulo break;
13505b9c547cSRui Paulo case P2PS_SETUP_CLIENT:
13515b9c547cSRui Paulo conncap = P2PS_SETUP_GROUP_OWNER;
13525b9c547cSRui Paulo break;
13535b9c547cSRui Paulo }
13545b9c547cSRui Paulo }
13555b9c547cSRui Paulo
13565b9c547cSRui Paulo p2p_dbg(p2p, "Received Provision Discovery Response from " MACSTR
1357f05cddf9SRui Paulo " with config methods 0x%x",
1358f05cddf9SRui Paulo MAC2STR(sa), msg.wps_config_methods);
1359f05cddf9SRui Paulo
1360f05cddf9SRui Paulo dev = p2p_get_device(p2p, sa);
1361f05cddf9SRui Paulo if (dev == NULL || !dev->req_config_methods) {
13625b9c547cSRui Paulo p2p_dbg(p2p, "Ignore Provision Discovery Response from " MACSTR
13635b9c547cSRui Paulo " with no pending request", MAC2STR(sa));
1364f05cddf9SRui Paulo p2p_parse_free(&msg);
1365f05cddf9SRui Paulo return;
1366780fb4a2SCy Schubert } else if (msg.wfd_subelems) {
1367780fb4a2SCy Schubert wpabuf_free(dev->info.wfd_subelems);
1368780fb4a2SCy Schubert dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
1369f05cddf9SRui Paulo }
1370f05cddf9SRui Paulo
1371*a90b9d01SCy Schubert p2p_update_peer_6ghz_capab(dev, &msg);
1372*a90b9d01SCy Schubert
1373f05cddf9SRui Paulo if (dev->dialog_token != msg.dialog_token) {
13745b9c547cSRui Paulo p2p_dbg(p2p, "Ignore Provision Discovery Response with unexpected Dialog Token %u (expected %u)",
1375f05cddf9SRui Paulo msg.dialog_token, dev->dialog_token);
1376f05cddf9SRui Paulo p2p_parse_free(&msg);
1377f05cddf9SRui Paulo return;
1378f05cddf9SRui Paulo }
1379f05cddf9SRui Paulo
1380f05cddf9SRui Paulo if (p2p->pending_action_state == P2P_PENDING_PD) {
1381f05cddf9SRui Paulo os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
1382f05cddf9SRui Paulo p2p->pending_action_state = P2P_NO_PENDING_ACTION;
1383f05cddf9SRui Paulo }
1384f05cddf9SRui Paulo
1385325151a3SRui Paulo p2ps_seeker = p2p->p2ps_prov && p2p->p2ps_prov->pd_seeker;
1386325151a3SRui Paulo
1387f05cddf9SRui Paulo /*
13885b9c547cSRui Paulo * Use a local copy of the requested config methods since
13895b9c547cSRui Paulo * p2p_reset_pending_pd() can clear this in the peer entry.
13905b9c547cSRui Paulo */
13915b9c547cSRui Paulo req_config_methods = dev->req_config_methods;
13925b9c547cSRui Paulo
13935b9c547cSRui Paulo /*
1394f05cddf9SRui Paulo * If the response is from the peer to whom a user initiated request
1395f05cddf9SRui Paulo * was sent earlier, we reset that state info here.
1396f05cddf9SRui Paulo */
1397f05cddf9SRui Paulo if (p2p->user_initiated_pd &&
1398*a90b9d01SCy Schubert ether_addr_equal(p2p->pending_pd_devaddr, sa))
1399f05cddf9SRui Paulo p2p_reset_pending_pd(p2p);
1400f05cddf9SRui Paulo
14015b9c547cSRui Paulo if (msg.wps_config_methods != req_config_methods) {
14025b9c547cSRui Paulo p2p_dbg(p2p, "Peer rejected our Provision Discovery Request (received config_methods 0x%x expected 0x%x",
14035b9c547cSRui Paulo msg.wps_config_methods, req_config_methods);
1404f05cddf9SRui Paulo if (p2p->cfg->prov_disc_fail)
1405f05cddf9SRui Paulo p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa,
14065b9c547cSRui Paulo P2P_PROV_DISC_REJECTED,
14075b9c547cSRui Paulo adv_id, adv_mac, NULL);
1408f05cddf9SRui Paulo p2p_parse_free(&msg);
1409325151a3SRui Paulo p2ps_prov_free(p2p);
1410f05cddf9SRui Paulo goto out;
1411f05cddf9SRui Paulo }
1412f05cddf9SRui Paulo
14135b9c547cSRui Paulo report_config_methods = req_config_methods;
1414f05cddf9SRui Paulo dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
14155b9c547cSRui Paulo P2P_DEV_PD_PEER_KEYPAD |
14165b9c547cSRui Paulo P2P_DEV_PD_PEER_P2PS);
14175b9c547cSRui Paulo if (req_config_methods & WPS_CONFIG_DISPLAY) {
14185b9c547cSRui Paulo p2p_dbg(p2p, "Peer " MACSTR
1419f05cddf9SRui Paulo " accepted to show a PIN on display", MAC2STR(sa));
1420f05cddf9SRui Paulo dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
14215b9c547cSRui Paulo passwd_id = DEV_PW_REGISTRAR_SPECIFIED;
1422f05cddf9SRui Paulo } else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
14235b9c547cSRui Paulo p2p_dbg(p2p, "Peer " MACSTR
1424f05cddf9SRui Paulo " accepted to write our PIN using keypad",
1425f05cddf9SRui Paulo MAC2STR(sa));
1426f05cddf9SRui Paulo dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
14275b9c547cSRui Paulo passwd_id = DEV_PW_USER_SPECIFIED;
14285b9c547cSRui Paulo } else if (msg.wps_config_methods & WPS_CONFIG_P2PS) {
14295b9c547cSRui Paulo p2p_dbg(p2p, "Peer " MACSTR " accepted P2PS PIN",
14305b9c547cSRui Paulo MAC2STR(sa));
14315b9c547cSRui Paulo dev->flags |= P2P_DEV_PD_PEER_P2PS;
14325b9c547cSRui Paulo passwd_id = DEV_PW_P2PS_DEFAULT;
14335b9c547cSRui Paulo }
14345b9c547cSRui Paulo
1435780fb4a2SCy Schubert if ((status == P2P_SC_SUCCESS || status == P2P_SC_SUCCESS_DEFERRED) &&
14365b9c547cSRui Paulo p2p->p2ps_prov) {
1437780fb4a2SCy Schubert dev->oper_freq = 0;
1438780fb4a2SCy Schubert
1439780fb4a2SCy Schubert /*
1440780fb4a2SCy Schubert * Save the reported channel list and operating frequency.
1441780fb4a2SCy Schubert * Note that the specification mandates that the responder
1442780fb4a2SCy Schubert * should include in the channel list only channels reported by
14434b72b91aSCy Schubert * the initiator, so this is only a validity check, and if this
1444780fb4a2SCy Schubert * fails the flow would continue, although it would probably
1445780fb4a2SCy Schubert * fail. Same is true for the operating channel.
1446780fb4a2SCy Schubert */
1447780fb4a2SCy Schubert if (msg.channel_list && msg.channel_list_len &&
1448780fb4a2SCy Schubert p2p_peer_channels_check(p2p, &p2p->channels, dev,
1449780fb4a2SCy Schubert msg.channel_list,
1450780fb4a2SCy Schubert msg.channel_list_len) < 0)
1451780fb4a2SCy Schubert p2p_dbg(p2p, "P2PS PD Response - no common channels");
1452780fb4a2SCy Schubert
1453780fb4a2SCy Schubert if (msg.operating_channel) {
1454780fb4a2SCy Schubert if (p2p_channels_includes(&p2p->channels,
1455780fb4a2SCy Schubert msg.operating_channel[3],
1456780fb4a2SCy Schubert msg.operating_channel[4]) &&
1457780fb4a2SCy Schubert p2p_channels_includes(&dev->channels,
1458780fb4a2SCy Schubert msg.operating_channel[3],
1459780fb4a2SCy Schubert msg.operating_channel[4])) {
1460780fb4a2SCy Schubert dev->oper_freq =
1461780fb4a2SCy Schubert p2p_channel_to_freq(
1462780fb4a2SCy Schubert msg.operating_channel[3],
1463780fb4a2SCy Schubert msg.operating_channel[4]);
1464780fb4a2SCy Schubert } else {
1465780fb4a2SCy Schubert p2p_dbg(p2p,
1466780fb4a2SCy Schubert "P2PS PD Response - invalid operating channel");
1467780fb4a2SCy Schubert }
1468780fb4a2SCy Schubert }
1469780fb4a2SCy Schubert
14705b9c547cSRui Paulo if (p2p->cfg->p2ps_prov_complete) {
1471780fb4a2SCy Schubert int freq = 0;
1472780fb4a2SCy Schubert
1473780fb4a2SCy Schubert if (conncap == P2PS_SETUP_GROUP_OWNER) {
1474780fb4a2SCy Schubert u8 tmp;
1475780fb4a2SCy Schubert
1476780fb4a2SCy Schubert /*
1477780fb4a2SCy Schubert * Re-select the operating channel as it is
1478780fb4a2SCy Schubert * possible that original channel is no longer
1479780fb4a2SCy Schubert * valid. This should not really fail.
1480780fb4a2SCy Schubert */
1481780fb4a2SCy Schubert if (p2p_go_select_channel(p2p, dev, &tmp) < 0)
1482780fb4a2SCy Schubert p2p_dbg(p2p,
1483780fb4a2SCy Schubert "P2PS PD channel selection failed");
1484780fb4a2SCy Schubert
1485780fb4a2SCy Schubert freq = p2p_channel_to_freq(p2p->op_reg_class,
1486780fb4a2SCy Schubert p2p->op_channel);
1487780fb4a2SCy Schubert if (freq < 0)
1488780fb4a2SCy Schubert freq = 0;
1489780fb4a2SCy Schubert }
1490780fb4a2SCy Schubert
14915b9c547cSRui Paulo p2p->cfg->p2ps_prov_complete(
14925b9c547cSRui Paulo p2p->cfg->cb_ctx, status, sa, adv_mac,
14935b9c547cSRui Paulo p2p->p2ps_prov->session_mac,
14945b9c547cSRui Paulo group_mac, adv_id, p2p->p2ps_prov->session_id,
14955b9c547cSRui Paulo conncap, passwd_id, msg.persistent_ssid,
1496325151a3SRui Paulo msg.persistent_ssid_len, 1, 0, NULL,
1497780fb4a2SCy Schubert msg.feature_cap, msg.feature_cap_len, freq,
1498780fb4a2SCy Schubert msg.group_id ? msg.group_id + ETH_ALEN : NULL,
1499780fb4a2SCy Schubert msg.group_id ? msg.group_id_len - ETH_ALEN : 0);
15005b9c547cSRui Paulo }
1501325151a3SRui Paulo p2ps_prov_free(p2p);
1502325151a3SRui Paulo } else if (status != P2P_SC_SUCCESS &&
15035b9c547cSRui Paulo status != P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE &&
15045b9c547cSRui Paulo status != P2P_SC_SUCCESS_DEFERRED && p2p->p2ps_prov) {
15055b9c547cSRui Paulo if (p2p->cfg->p2ps_prov_complete)
15065b9c547cSRui Paulo p2p->cfg->p2ps_prov_complete(
15075b9c547cSRui Paulo p2p->cfg->cb_ctx, status, sa, adv_mac,
15085b9c547cSRui Paulo p2p->p2ps_prov->session_mac,
15095b9c547cSRui Paulo group_mac, adv_id, p2p->p2ps_prov->session_id,
1510780fb4a2SCy Schubert 0, 0, NULL, 0, 1, 0, NULL, NULL, 0, 0, NULL, 0);
1511325151a3SRui Paulo p2ps_prov_free(p2p);
15125b9c547cSRui Paulo }
15135b9c547cSRui Paulo
15145b9c547cSRui Paulo if (status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) {
15155b9c547cSRui Paulo if (p2p->cfg->remove_stale_groups) {
15165b9c547cSRui Paulo p2p->cfg->remove_stale_groups(p2p->cfg->cb_ctx,
15175b9c547cSRui Paulo dev->info.p2p_device_addr,
15185b9c547cSRui Paulo NULL, NULL, 0);
15195b9c547cSRui Paulo }
15205b9c547cSRui Paulo
15215b9c547cSRui Paulo if (msg.session_info && msg.session_info_len) {
15225b9c547cSRui Paulo size_t info_len = msg.session_info_len;
15235b9c547cSRui Paulo char *deferred_sess_resp = os_malloc(2 * info_len + 1);
15245b9c547cSRui Paulo
15255b9c547cSRui Paulo if (!deferred_sess_resp) {
15265b9c547cSRui Paulo p2p_parse_free(&msg);
1527325151a3SRui Paulo p2ps_prov_free(p2p);
15285b9c547cSRui Paulo goto out;
15295b9c547cSRui Paulo }
15305b9c547cSRui Paulo utf8_escape((char *) msg.session_info, info_len,
15315b9c547cSRui Paulo deferred_sess_resp, 2 * info_len + 1);
15325b9c547cSRui Paulo
15335b9c547cSRui Paulo if (p2p->cfg->prov_disc_fail)
15345b9c547cSRui Paulo p2p->cfg->prov_disc_fail(
15355b9c547cSRui Paulo p2p->cfg->cb_ctx, sa,
15365b9c547cSRui Paulo P2P_PROV_DISC_INFO_UNAVAILABLE,
15375b9c547cSRui Paulo adv_id, adv_mac,
15385b9c547cSRui Paulo deferred_sess_resp);
15395b9c547cSRui Paulo os_free(deferred_sess_resp);
15405b9c547cSRui Paulo } else
15415b9c547cSRui Paulo if (p2p->cfg->prov_disc_fail)
15425b9c547cSRui Paulo p2p->cfg->prov_disc_fail(
15435b9c547cSRui Paulo p2p->cfg->cb_ctx, sa,
15445b9c547cSRui Paulo P2P_PROV_DISC_INFO_UNAVAILABLE,
15455b9c547cSRui Paulo adv_id, adv_mac, NULL);
1546325151a3SRui Paulo } else if (status != P2P_SC_SUCCESS) {
15475b9c547cSRui Paulo p2p_dbg(p2p, "Peer rejected our Provision Discovery Request");
15485b9c547cSRui Paulo if (p2p->cfg->prov_disc_fail)
15495b9c547cSRui Paulo p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa,
1550325151a3SRui Paulo P2P_PROV_DISC_REJECTED,
1551325151a3SRui Paulo adv_id, adv_mac, NULL);
15525b9c547cSRui Paulo p2p_parse_free(&msg);
1553325151a3SRui Paulo p2ps_prov_free(p2p);
15545b9c547cSRui Paulo goto out;
1555f05cddf9SRui Paulo }
1556f05cddf9SRui Paulo
1557f05cddf9SRui Paulo /* Store the provisioning info */
1558f05cddf9SRui Paulo dev->wps_prov_info = msg.wps_config_methods;
1559325151a3SRui Paulo if (msg.intended_addr)
1560325151a3SRui Paulo os_memcpy(dev->interface_addr, msg.intended_addr, ETH_ALEN);
1561f05cddf9SRui Paulo
1562f05cddf9SRui Paulo p2p_parse_free(&msg);
1563f05cddf9SRui Paulo
1564f05cddf9SRui Paulo out:
1565f05cddf9SRui Paulo dev->req_config_methods = 0;
1566f05cddf9SRui Paulo p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
1567f05cddf9SRui Paulo if (dev->flags & P2P_DEV_PD_BEFORE_GO_NEG) {
15685b9c547cSRui Paulo p2p_dbg(p2p, "Start GO Neg after the PD-before-GO-Neg workaround with "
15695b9c547cSRui Paulo MACSTR, MAC2STR(dev->info.p2p_device_addr));
1570f05cddf9SRui Paulo dev->flags &= ~P2P_DEV_PD_BEFORE_GO_NEG;
1571f05cddf9SRui Paulo p2p_connect_send(p2p, dev);
1572f05cddf9SRui Paulo return;
1573f05cddf9SRui Paulo }
1574325151a3SRui Paulo
1575325151a3SRui Paulo /*
1576325151a3SRui Paulo * prov_disc_resp callback is used to generate P2P-PROV-DISC-ENTER-PIN,
1577325151a3SRui Paulo * P2P-PROV-DISC-SHOW-PIN, and P2P-PROV-DISC-PBC-REQ events.
1578325151a3SRui Paulo * Call it only for a legacy P2P PD or for P2PS PD scenarios where
1579325151a3SRui Paulo * show/enter PIN events are needed.
1580325151a3SRui Paulo *
1581325151a3SRui Paulo * The callback is called in the following cases:
1582325151a3SRui Paulo * 1. Legacy P2P PD response with a status SUCCESS
1583325151a3SRui Paulo * 2. P2PS, advertiser method: DISPLAY, autoaccept: true,
1584325151a3SRui Paulo * response status: SUCCESS, local method KEYPAD
1585325151a3SRui Paulo * 3. P2PS, advertiser method: KEYPAD,Seeker side,
1586325151a3SRui Paulo * response status: INFO_CURRENTLY_UNAVAILABLE,
1587325151a3SRui Paulo * local method: DISPLAY
1588325151a3SRui Paulo */
1589325151a3SRui Paulo if (p2p->cfg->prov_disc_resp &&
1590325151a3SRui Paulo ((status == P2P_SC_SUCCESS && !adv_id) ||
1591325151a3SRui Paulo (p2ps_seeker && status == P2P_SC_SUCCESS &&
1592325151a3SRui Paulo passwd_id == DEV_PW_REGISTRAR_SPECIFIED) ||
1593325151a3SRui Paulo (p2ps_seeker &&
1594325151a3SRui Paulo status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE &&
1595325151a3SRui Paulo passwd_id == DEV_PW_USER_SPECIFIED)))
1596f05cddf9SRui Paulo p2p->cfg->prov_disc_resp(p2p->cfg->cb_ctx, sa,
1597f05cddf9SRui Paulo report_config_methods);
15985b9c547cSRui Paulo
15995b9c547cSRui Paulo if (p2p->state == P2P_PD_DURING_FIND) {
160085732ac8SCy Schubert p2p_stop_listen_for_freq(p2p, 0);
16015b9c547cSRui Paulo p2p_continue_find(p2p);
16025b9c547cSRui Paulo }
1603f05cddf9SRui Paulo }
1604f05cddf9SRui Paulo
1605f05cddf9SRui Paulo
p2p_send_prov_disc_req(struct p2p_data * p2p,struct p2p_device * dev,int join,int force_freq)1606f05cddf9SRui Paulo int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
1607f05cddf9SRui Paulo int join, int force_freq)
1608f05cddf9SRui Paulo {
1609f05cddf9SRui Paulo struct wpabuf *req;
1610f05cddf9SRui Paulo int freq;
1611f05cddf9SRui Paulo
1612f05cddf9SRui Paulo if (force_freq > 0)
1613f05cddf9SRui Paulo freq = force_freq;
1614f05cddf9SRui Paulo else
1615f05cddf9SRui Paulo freq = dev->listen_freq > 0 ? dev->listen_freq :
1616f05cddf9SRui Paulo dev->oper_freq;
1617f05cddf9SRui Paulo if (freq <= 0) {
16185b9c547cSRui Paulo p2p_dbg(p2p, "No Listen/Operating frequency known for the peer "
16195b9c547cSRui Paulo MACSTR " to send Provision Discovery Request",
1620f05cddf9SRui Paulo MAC2STR(dev->info.p2p_device_addr));
1621f05cddf9SRui Paulo return -1;
1622f05cddf9SRui Paulo }
1623f05cddf9SRui Paulo
1624f05cddf9SRui Paulo if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) {
1625f05cddf9SRui Paulo if (!(dev->info.dev_capab &
1626f05cddf9SRui Paulo P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) {
16275b9c547cSRui Paulo p2p_dbg(p2p, "Cannot use PD with P2P Device " MACSTR
1628f05cddf9SRui Paulo " that is in a group and is not discoverable",
1629f05cddf9SRui Paulo MAC2STR(dev->info.p2p_device_addr));
1630f05cddf9SRui Paulo return -1;
1631f05cddf9SRui Paulo }
1632f05cddf9SRui Paulo /* TODO: use device discoverability request through GO */
1633f05cddf9SRui Paulo }
1634f05cddf9SRui Paulo
16355b9c547cSRui Paulo if (p2p->p2ps_prov) {
16365b9c547cSRui Paulo if (p2p->p2ps_prov->status == P2P_SC_SUCCESS_DEFERRED) {
16375b9c547cSRui Paulo if (p2p->p2ps_prov->method == WPS_CONFIG_DISPLAY)
16385b9c547cSRui Paulo dev->req_config_methods = WPS_CONFIG_KEYPAD;
16395b9c547cSRui Paulo else if (p2p->p2ps_prov->method == WPS_CONFIG_KEYPAD)
16405b9c547cSRui Paulo dev->req_config_methods = WPS_CONFIG_DISPLAY;
16415b9c547cSRui Paulo else
16425b9c547cSRui Paulo dev->req_config_methods = WPS_CONFIG_P2PS;
16435b9c547cSRui Paulo } else {
16445b9c547cSRui Paulo /* Order of preference, based on peer's capabilities */
16455b9c547cSRui Paulo if (p2p->p2ps_prov->method)
16465b9c547cSRui Paulo dev->req_config_methods =
16475b9c547cSRui Paulo p2p->p2ps_prov->method;
16485b9c547cSRui Paulo else if (dev->info.config_methods & WPS_CONFIG_P2PS)
16495b9c547cSRui Paulo dev->req_config_methods = WPS_CONFIG_P2PS;
16505b9c547cSRui Paulo else if (dev->info.config_methods & WPS_CONFIG_DISPLAY)
16515b9c547cSRui Paulo dev->req_config_methods = WPS_CONFIG_DISPLAY;
16525b9c547cSRui Paulo else
16535b9c547cSRui Paulo dev->req_config_methods = WPS_CONFIG_KEYPAD;
16545b9c547cSRui Paulo }
16555b9c547cSRui Paulo p2p_dbg(p2p,
16565b9c547cSRui Paulo "Building PD Request based on P2PS config method 0x%x status %d --> req_config_methods 0x%x",
16575b9c547cSRui Paulo p2p->p2ps_prov->method, p2p->p2ps_prov->status,
16585b9c547cSRui Paulo dev->req_config_methods);
1659780fb4a2SCy Schubert
1660780fb4a2SCy Schubert if (p2p_prepare_channel(p2p, dev, p2p->p2ps_prov->force_freq,
1661780fb4a2SCy Schubert p2p->p2ps_prov->pref_freq, 1) < 0)
1662780fb4a2SCy Schubert return -1;
16635b9c547cSRui Paulo }
16645b9c547cSRui Paulo
16655b9c547cSRui Paulo req = p2p_build_prov_disc_req(p2p, dev, join);
1666f05cddf9SRui Paulo if (req == NULL)
1667f05cddf9SRui Paulo return -1;
1668f05cddf9SRui Paulo
1669f05cddf9SRui Paulo if (p2p->state != P2P_IDLE)
1670f05cddf9SRui Paulo p2p_stop_listen_for_freq(p2p, freq);
1671f05cddf9SRui Paulo p2p->pending_action_state = P2P_PENDING_PD;
1672f05cddf9SRui Paulo if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
1673f05cddf9SRui Paulo p2p->cfg->dev_addr, dev->info.p2p_device_addr,
1674f05cddf9SRui Paulo wpabuf_head(req), wpabuf_len(req), 200) < 0) {
16755b9c547cSRui Paulo p2p_dbg(p2p, "Failed to send Action frame");
1676f05cddf9SRui Paulo wpabuf_free(req);
1677f05cddf9SRui Paulo return -1;
1678f05cddf9SRui Paulo }
1679f05cddf9SRui Paulo
1680f05cddf9SRui Paulo os_memcpy(p2p->pending_pd_devaddr, dev->info.p2p_device_addr, ETH_ALEN);
1681f05cddf9SRui Paulo
1682f05cddf9SRui Paulo wpabuf_free(req);
1683f05cddf9SRui Paulo return 0;
1684f05cddf9SRui Paulo }
1685f05cddf9SRui Paulo
1686f05cddf9SRui Paulo
p2p_prov_disc_req(struct p2p_data * p2p,const u8 * peer_addr,struct p2ps_provision * p2ps_prov,u16 config_methods,int join,int force_freq,int user_initiated_pd)1687f05cddf9SRui Paulo int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
16885b9c547cSRui Paulo struct p2ps_provision *p2ps_prov,
1689f05cddf9SRui Paulo u16 config_methods, int join, int force_freq,
1690f05cddf9SRui Paulo int user_initiated_pd)
1691f05cddf9SRui Paulo {
1692f05cddf9SRui Paulo struct p2p_device *dev;
1693f05cddf9SRui Paulo
1694f05cddf9SRui Paulo dev = p2p_get_device(p2p, peer_addr);
1695f05cddf9SRui Paulo if (dev == NULL)
1696f05cddf9SRui Paulo dev = p2p_get_device_interface(p2p, peer_addr);
1697f05cddf9SRui Paulo if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
16985b9c547cSRui Paulo p2p_dbg(p2p, "Provision Discovery Request destination " MACSTR
1699f05cddf9SRui Paulo " not yet known", MAC2STR(peer_addr));
17005b9c547cSRui Paulo os_free(p2ps_prov);
1701f05cddf9SRui Paulo return -1;
1702f05cddf9SRui Paulo }
1703f05cddf9SRui Paulo
17045b9c547cSRui Paulo p2p_dbg(p2p, "Provision Discovery Request with " MACSTR
17055b9c547cSRui Paulo " (config methods 0x%x)",
1706f05cddf9SRui Paulo MAC2STR(peer_addr), config_methods);
17075b9c547cSRui Paulo if (config_methods == 0 && !p2ps_prov) {
17085b9c547cSRui Paulo os_free(p2ps_prov);
1709f05cddf9SRui Paulo return -1;
17105b9c547cSRui Paulo }
17115b9c547cSRui Paulo
17125b9c547cSRui Paulo if (p2ps_prov && p2ps_prov->status == P2P_SC_SUCCESS_DEFERRED &&
17135b9c547cSRui Paulo p2p->p2ps_prov) {
17145b9c547cSRui Paulo /* Use cached method from deferred provisioning */
17155b9c547cSRui Paulo p2ps_prov->method = p2p->p2ps_prov->method;
17165b9c547cSRui Paulo }
1717f05cddf9SRui Paulo
1718f05cddf9SRui Paulo /* Reset provisioning info */
1719f05cddf9SRui Paulo dev->wps_prov_info = 0;
1720325151a3SRui Paulo p2ps_prov_free(p2p);
17215b9c547cSRui Paulo p2p->p2ps_prov = p2ps_prov;
1722f05cddf9SRui Paulo
1723f05cddf9SRui Paulo dev->req_config_methods = config_methods;
1724f05cddf9SRui Paulo if (join)
1725f05cddf9SRui Paulo dev->flags |= P2P_DEV_PD_FOR_JOIN;
1726f05cddf9SRui Paulo else
1727f05cddf9SRui Paulo dev->flags &= ~P2P_DEV_PD_FOR_JOIN;
1728f05cddf9SRui Paulo
1729f05cddf9SRui Paulo if (p2p->state != P2P_IDLE && p2p->state != P2P_SEARCH &&
1730f05cddf9SRui Paulo p2p->state != P2P_LISTEN_ONLY) {
17315b9c547cSRui Paulo p2p_dbg(p2p, "Busy with other operations; postpone Provision Discovery Request with "
17325b9c547cSRui Paulo MACSTR " (config methods 0x%x)",
1733f05cddf9SRui Paulo MAC2STR(peer_addr), config_methods);
1734f05cddf9SRui Paulo return 0;
1735f05cddf9SRui Paulo }
1736f05cddf9SRui Paulo
1737f05cddf9SRui Paulo p2p->user_initiated_pd = user_initiated_pd;
17385b9c547cSRui Paulo p2p->pd_force_freq = force_freq;
1739f05cddf9SRui Paulo
1740f05cddf9SRui Paulo if (p2p->user_initiated_pd)
1741f05cddf9SRui Paulo p2p->pd_retries = MAX_PROV_DISC_REQ_RETRIES;
1742f05cddf9SRui Paulo
1743f05cddf9SRui Paulo /*
1744f05cddf9SRui Paulo * Assign dialog token here to use the same value in each retry within
1745f05cddf9SRui Paulo * the same PD exchange.
1746f05cddf9SRui Paulo */
1747f05cddf9SRui Paulo dev->dialog_token++;
1748f05cddf9SRui Paulo if (dev->dialog_token == 0)
1749f05cddf9SRui Paulo dev->dialog_token = 1;
1750f05cddf9SRui Paulo
1751f05cddf9SRui Paulo return p2p_send_prov_disc_req(p2p, dev, join, force_freq);
1752f05cddf9SRui Paulo }
1753f05cddf9SRui Paulo
1754f05cddf9SRui Paulo
p2p_reset_pending_pd(struct p2p_data * p2p)1755f05cddf9SRui Paulo void p2p_reset_pending_pd(struct p2p_data *p2p)
1756f05cddf9SRui Paulo {
1757f05cddf9SRui Paulo struct p2p_device *dev;
1758f05cddf9SRui Paulo
1759f05cddf9SRui Paulo dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
1760*a90b9d01SCy Schubert if (!ether_addr_equal(p2p->pending_pd_devaddr,
1761*a90b9d01SCy Schubert dev->info.p2p_device_addr))
1762f05cddf9SRui Paulo continue;
1763f05cddf9SRui Paulo if (!dev->req_config_methods)
1764f05cddf9SRui Paulo continue;
1765f05cddf9SRui Paulo if (dev->flags & P2P_DEV_PD_FOR_JOIN)
1766f05cddf9SRui Paulo continue;
1767f05cddf9SRui Paulo /* Reset the config methods of the device */
1768f05cddf9SRui Paulo dev->req_config_methods = 0;
1769f05cddf9SRui Paulo }
1770f05cddf9SRui Paulo
1771f05cddf9SRui Paulo p2p->user_initiated_pd = 0;
1772f05cddf9SRui Paulo os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
1773f05cddf9SRui Paulo p2p->pd_retries = 0;
17745b9c547cSRui Paulo p2p->pd_force_freq = 0;
1775f05cddf9SRui Paulo }
1776325151a3SRui Paulo
1777325151a3SRui Paulo
p2ps_prov_free(struct p2p_data * p2p)1778325151a3SRui Paulo void p2ps_prov_free(struct p2p_data *p2p)
1779325151a3SRui Paulo {
1780325151a3SRui Paulo os_free(p2p->p2ps_prov);
1781325151a3SRui Paulo p2p->p2ps_prov = NULL;
1782325151a3SRui Paulo }
1783