LCOV - code coverage report
Current view: top level - src/p2p - p2p_pd.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1422976643 Lines: 527 647 81.5 %
Date: 2015-02-03 Functions: 11 11 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Wi-Fi Direct - P2P provision discovery
       3             :  * Copyright (c) 2009-2010, Atheros Communications
       4             :  *
       5             :  * This software may be distributed under the terms of the BSD license.
       6             :  * See README for more details.
       7             :  */
       8             : 
       9             : #include "includes.h"
      10             : 
      11             : #include "common.h"
      12             : #include "common/ieee802_11_defs.h"
      13             : #include "common/wpa_ctrl.h"
      14             : #include "wps/wps_defs.h"
      15             : #include "p2p_i.h"
      16             : #include "p2p.h"
      17             : 
      18             : 
      19             : /*
      20             :  * Number of retries to attempt for provision discovery requests
      21             :  * in case the peer is not listening.
      22             :  */
      23             : #define MAX_PROV_DISC_REQ_RETRIES 120
      24             : 
      25             : 
      26         280 : static void p2p_build_wps_ie_config_methods(struct wpabuf *buf,
      27             :                                             u16 config_methods)
      28             : {
      29             :         u8 *len;
      30         280 :         wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
      31         280 :         len = wpabuf_put(buf, 1);
      32         280 :         wpabuf_put_be32(buf, WPS_DEV_OUI_WFA);
      33             : 
      34             :         /* Config Methods */
      35         280 :         wpabuf_put_be16(buf, ATTR_CONFIG_METHODS);
      36         280 :         wpabuf_put_be16(buf, 2);
      37         280 :         wpabuf_put_be16(buf, config_methods);
      38             : 
      39         280 :         p2p_buf_update_ie_hdr(buf, len);
      40         280 : }
      41             : 
      42             : 
      43          20 : static void p2ps_add_new_group_info(struct p2p_data *p2p, struct wpabuf *buf)
      44             : {
      45             :         int found;
      46             :         u8 intended_addr[ETH_ALEN];
      47             :         u8 ssid[32];
      48             :         size_t ssid_len;
      49             :         int group_iface;
      50             : 
      51          20 :         if (!p2p->cfg->get_go_info)
      52          20 :                 return;
      53             : 
      54          40 :         found = p2p->cfg->get_go_info(
      55          20 :                 p2p->cfg->cb_ctx, intended_addr, ssid,
      56             :                 &ssid_len, &group_iface);
      57          20 :         if (found) {
      58           0 :                 p2p_buf_add_group_id(buf, p2p->cfg->dev_addr,
      59             :                                      ssid, ssid_len);
      60           0 :                 p2p_buf_add_intended_addr(buf, intended_addr);
      61             :         } else {
      62          20 :                 if (!p2p->ssid_set) {
      63          18 :                         p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len);
      64          18 :                         p2p->ssid_set = 1;
      65             :                 }
      66             : 
      67             :                 /* Add pre-composed P2P Group ID */
      68          40 :                 p2p_buf_add_group_id(buf, p2p->cfg->dev_addr,
      69          20 :                                      p2p->ssid, p2p->ssid_len);
      70             : 
      71          20 :                 if (group_iface)
      72           2 :                         p2p_buf_add_intended_addr(
      73           2 :                                 buf, p2p->intended_addr);
      74             :                 else
      75          18 :                         p2p_buf_add_intended_addr(
      76          18 :                                 buf, p2p->cfg->dev_addr);
      77             :         }
      78             : }
      79             : 
      80             : 
      81          18 : static void p2ps_add_pd_req_attrs(struct p2p_data *p2p, struct p2p_device *dev,
      82             :                                   struct wpabuf *buf, u16 config_methods)
      83             : {
      84          18 :         struct p2ps_provision *prov = p2p->p2ps_prov;
      85          18 :         u8 feat_cap_mask[] = { 1, 0 };
      86          18 :         int shared_group = 0;
      87             :         u8 ssid[32];
      88             :         size_t ssid_len;
      89             :         u8 go_dev_addr[ETH_ALEN];
      90             : 
      91             :         /* If we might be explicite group owner, add GO details */
      92          18 :         if (prov->conncap & (P2PS_SETUP_GROUP_OWNER |
      93             :                              P2PS_SETUP_NEW))
      94          18 :                 p2ps_add_new_group_info(p2p, buf);
      95             : 
      96          18 :         if (prov->status >= 0)
      97           3 :                 p2p_buf_add_status(buf, (u8) prov->status);
      98             :         else
      99          15 :                 prov->method = config_methods;
     100             : 
     101          18 :         if (p2p->cfg->get_persistent_group) {
     102          36 :                 shared_group = p2p->cfg->get_persistent_group(
     103          18 :                         p2p->cfg->cb_ctx, dev->info.p2p_device_addr, NULL, 0,
     104             :                         go_dev_addr, ssid, &ssid_len);
     105             :         }
     106             : 
     107             :         /* Add Operating Channel if conncap includes GO */
     108          35 :         if (shared_group ||
     109          17 :             (prov->conncap & (P2PS_SETUP_GROUP_OWNER |
     110             :                               P2PS_SETUP_NEW))) {
     111             :                 u8 tmp;
     112             : 
     113          18 :                 p2p_go_select_channel(p2p, dev, &tmp);
     114             : 
     115          18 :                 if (p2p->op_reg_class && p2p->op_channel)
     116          36 :                         p2p_buf_add_operating_channel(buf, p2p->cfg->country,
     117          18 :                                                       p2p->op_reg_class,
     118          18 :                                                       p2p->op_channel);
     119             :                 else
     120           0 :                         p2p_buf_add_operating_channel(buf, p2p->cfg->country,
     121           0 :                                                       p2p->cfg->op_reg_class,
     122           0 :                                                       p2p->cfg->op_channel);
     123             :         }
     124             : 
     125          18 :         p2p_buf_add_channel_list(buf, p2p->cfg->country, &p2p->cfg->channels);
     126             : 
     127          18 :         if (prov->info[0])
     128           4 :                 p2p_buf_add_session_info(buf, prov->info);
     129             : 
     130          18 :         p2p_buf_add_connection_capability(buf, prov->conncap);
     131             : 
     132          18 :         p2p_buf_add_advertisement_id(buf, prov->adv_id, prov->adv_mac);
     133             : 
     134          18 :         if (shared_group || prov->conncap == P2PS_SETUP_NEW ||
     135           0 :             prov->conncap ==
     136           0 :             (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW) ||
     137           0 :             prov->conncap ==
     138             :             (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_CLIENT)) {
     139             :                 /* Add Config Timeout */
     140          18 :                 p2p_buf_add_config_timeout(buf, p2p->go_timeout,
     141          18 :                                            p2p->client_timeout);
     142             :         }
     143             : 
     144          18 :         p2p_buf_add_listen_channel(buf, p2p->cfg->country, p2p->cfg->reg_class,
     145          18 :                                    p2p->cfg->channel);
     146             : 
     147          18 :         p2p_buf_add_session_id(buf, prov->session_id, prov->session_mac);
     148             : 
     149          18 :         p2p_buf_add_feature_capability(buf, sizeof(feat_cap_mask),
     150             :                                        feat_cap_mask);
     151             : 
     152          18 :         if (shared_group)
     153           1 :                 p2p_buf_add_persistent_group_info(buf, go_dev_addr,
     154             :                                                   ssid, ssid_len);
     155          18 : }
     156             : 
     157             : 
     158         199 : static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p,
     159             :                                                struct p2p_device *dev,
     160             :                                                int join)
     161             : {
     162             :         struct wpabuf *buf;
     163             :         u8 *len;
     164         199 :         size_t extra = 0;
     165         199 :         u8 dialog_token = dev->dialog_token;
     166         199 :         u16 config_methods = dev->req_config_methods;
     167         199 :         struct p2p_device *go = join ? dev : NULL;
     168             :         u8 group_capab;
     169             : 
     170             : #ifdef CONFIG_WIFI_DISPLAY
     171         199 :         if (p2p->wfd_ie_prov_disc_req)
     172           3 :                 extra = wpabuf_len(p2p->wfd_ie_prov_disc_req);
     173             : #endif /* CONFIG_WIFI_DISPLAY */
     174             : 
     175         199 :         if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ])
     176           0 :                 extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ]);
     177             : 
     178         199 :         if (p2p->p2ps_prov)
     179          18 :                 extra += os_strlen(p2p->p2ps_prov->info) + 1 +
     180             :                         sizeof(struct p2ps_provision);
     181             : 
     182         199 :         buf = wpabuf_alloc(1000 + extra);
     183         199 :         if (buf == NULL)
     184           0 :                 return NULL;
     185             : 
     186         199 :         p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_REQ, dialog_token);
     187             : 
     188         199 :         len = p2p_buf_add_ie_hdr(buf);
     189             : 
     190         199 :         group_capab = 0;
     191         199 :         if (p2p->p2ps_prov) {
     192          18 :                 group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP;
     193          18 :                 group_capab |= P2P_GROUP_CAPAB_PERSISTENT_RECONN;
     194          18 :                 if (p2p->cross_connect)
     195           0 :                         group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
     196          18 :                 if (p2p->cfg->p2p_intra_bss)
     197          18 :                         group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST;
     198             :         }
     199         199 :         p2p_buf_add_capability(buf, p2p->dev_capab &
     200             :                                ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY,
     201             :                                group_capab);
     202         199 :         p2p_buf_add_device_info(buf, p2p, NULL);
     203         199 :         if (p2p->p2ps_prov) {
     204          18 :                 p2ps_add_pd_req_attrs(p2p, dev, buf, config_methods);
     205         181 :         } else if (go) {
     206         100 :                 p2p_buf_add_group_id(buf, go->info.p2p_device_addr,
     207          50 :                                      go->oper_ssid, go->oper_ssid_len);
     208             :         }
     209         199 :         p2p_buf_update_ie_hdr(buf, len);
     210             : 
     211             :         /* WPS IE with Config Methods attribute */
     212         199 :         p2p_build_wps_ie_config_methods(buf, config_methods);
     213             : 
     214             : #ifdef CONFIG_WIFI_DISPLAY
     215         199 :         if (p2p->wfd_ie_prov_disc_req)
     216           3 :                 wpabuf_put_buf(buf, p2p->wfd_ie_prov_disc_req);
     217             : #endif /* CONFIG_WIFI_DISPLAY */
     218             : 
     219         199 :         if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ])
     220           0 :                 wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ]);
     221             : 
     222         199 :         return buf;
     223             : }
     224             : 
     225             : 
     226          81 : static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
     227             :                                                 struct p2p_device *dev,
     228             :                                                 u8 dialog_token,
     229             :                                                 enum p2p_status_code status,
     230             :                                                 u16 config_methods,
     231             :                                                 u32 adv_id,
     232             :                                                 const u8 *group_id,
     233             :                                                 size_t group_id_len,
     234             :                                                 const u8 *persist_ssid,
     235             :                                                 size_t persist_ssid_len)
     236             : {
     237             :         struct wpabuf *buf;
     238          81 :         size_t extra = 0;
     239          81 :         int persist = 0;
     240             : 
     241             : #ifdef CONFIG_WIFI_DISPLAY
     242          81 :         struct wpabuf *wfd_ie = p2p->wfd_ie_prov_disc_resp;
     243          81 :         if (wfd_ie && group_id) {
     244             :                 size_t i;
     245           3 :                 for (i = 0; i < p2p->num_groups; i++) {
     246           3 :                         struct p2p_group *g = p2p->groups[i];
     247             :                         struct wpabuf *ie;
     248           3 :                         if (!p2p_group_is_group_id_match(g, group_id,
     249             :                                                          group_id_len))
     250           0 :                                 continue;
     251           3 :                         ie = p2p_group_get_wfd_ie(g);
     252           3 :                         if (ie) {
     253           3 :                                 wfd_ie = ie;
     254           3 :                                 break;
     255             :                         }
     256             :                 }
     257             :         }
     258          81 :         if (wfd_ie)
     259           3 :                 extra = wpabuf_len(wfd_ie);
     260             : #endif /* CONFIG_WIFI_DISPLAY */
     261             : 
     262          81 :         if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP])
     263           0 :                 extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP]);
     264             : 
     265          81 :         buf = wpabuf_alloc(1000 + extra);
     266          81 :         if (buf == NULL)
     267           0 :                 return NULL;
     268             : 
     269          81 :         p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_RESP, dialog_token);
     270             : 
     271             :         /* Add P2P IE for P2PS */
     272          99 :         if (p2p->p2ps_prov && p2p->p2ps_prov->adv_id == adv_id) {
     273          18 :                 u8 feat_cap_mask[] = { 1, 0 };
     274          18 :                 u8 *len = p2p_buf_add_ie_hdr(buf);
     275          18 :                 struct p2ps_provision *prov = p2p->p2ps_prov;
     276             :                 u8 group_capab;
     277             : 
     278          18 :                 if (!status && prov->status != -1)
     279          14 :                         status = prov->status;
     280             : 
     281          18 :                 p2p_buf_add_status(buf, status);
     282          18 :                 group_capab = P2P_GROUP_CAPAB_PERSISTENT_GROUP |
     283             :                         P2P_GROUP_CAPAB_PERSISTENT_RECONN;
     284          18 :                 if (p2p->cross_connect)
     285           0 :                         group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
     286          18 :                 if (p2p->cfg->p2p_intra_bss)
     287          18 :                         group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST;
     288          18 :                 p2p_buf_add_capability(buf, p2p->dev_capab &
     289             :                                        ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY,
     290             :                                        group_capab);
     291          18 :                 p2p_buf_add_device_info(buf, p2p, NULL);
     292             : 
     293          18 :                 if (persist_ssid && p2p->cfg->get_persistent_group &&
     294           0 :                     (status == P2P_SC_SUCCESS ||
     295             :                      status == P2P_SC_SUCCESS_DEFERRED)) {
     296             :                         u8 ssid[32];
     297             :                         size_t ssid_len;
     298             :                         u8 go_dev_addr[ETH_ALEN];
     299             : 
     300           2 :                         persist = p2p->cfg->get_persistent_group(
     301           1 :                                 p2p->cfg->cb_ctx,
     302           1 :                                 dev->info.p2p_device_addr,
     303             :                                 persist_ssid, persist_ssid_len, go_dev_addr,
     304             :                                 ssid, &ssid_len);
     305           1 :                         if (persist)
     306           1 :                                 p2p_buf_add_persistent_group_info(
     307             :                                         buf, go_dev_addr, ssid, ssid_len);
     308             :                 }
     309             : 
     310          18 :                 if (!persist && (prov->conncap & P2PS_SETUP_GROUP_OWNER))
     311           2 :                         p2ps_add_new_group_info(p2p, buf);
     312             : 
     313             :                 /* Add Operating Channel if conncap indicates GO */
     314          18 :                 if (persist || (prov->conncap & P2PS_SETUP_GROUP_OWNER)) {
     315             :                         u8 tmp;
     316             : 
     317           3 :                         if (dev)
     318           3 :                                 p2p_go_select_channel(p2p, dev, &tmp);
     319             : 
     320           3 :                         if (p2p->op_reg_class && p2p->op_channel)
     321           9 :                                 p2p_buf_add_operating_channel(
     322           3 :                                         buf, p2p->cfg->country,
     323           3 :                                         p2p->op_reg_class,
     324           3 :                                         p2p->op_channel);
     325             :                         else
     326           0 :                                 p2p_buf_add_operating_channel(
     327           0 :                                         buf, p2p->cfg->country,
     328           0 :                                         p2p->cfg->op_reg_class,
     329           0 :                                         p2p->cfg->op_channel);
     330             :                 }
     331             : 
     332          18 :                 p2p_buf_add_channel_list(buf, p2p->cfg->country,
     333          18 :                                          &p2p->cfg->channels);
     334             : 
     335          18 :                 if (!persist && (status == P2P_SC_SUCCESS ||
     336             :                                  status == P2P_SC_SUCCESS_DEFERRED))
     337          13 :                         p2p_buf_add_connection_capability(buf, prov->conncap);
     338             : 
     339          18 :                 p2p_buf_add_advertisement_id(buf, adv_id, prov->adv_mac);
     340             : 
     341          18 :                 p2p_buf_add_config_timeout(buf, p2p->go_timeout,
     342          18 :                                            p2p->client_timeout);
     343             : 
     344          18 :                 p2p_buf_add_session_id(buf, prov->session_id,
     345          18 :                                        prov->session_mac);
     346             : 
     347          18 :                 p2p_buf_add_feature_capability(buf, sizeof(feat_cap_mask),
     348             :                                                feat_cap_mask);
     349          18 :                 p2p_buf_update_ie_hdr(buf, len);
     350          63 :         } else if (status != P2P_SC_SUCCESS || adv_id) {
     351           2 :                 u8 *len = p2p_buf_add_ie_hdr(buf);
     352             : 
     353           2 :                 p2p_buf_add_status(buf, status);
     354             : 
     355           2 :                 if (p2p->p2ps_prov)
     356           0 :                         p2p_buf_add_advertisement_id(buf, adv_id,
     357           0 :                                                      p2p->p2ps_prov->adv_mac);
     358             : 
     359           2 :                 p2p_buf_update_ie_hdr(buf, len);
     360             :         }
     361             : 
     362             :         /* WPS IE with Config Methods attribute */
     363          81 :         p2p_build_wps_ie_config_methods(buf, config_methods);
     364             : 
     365             : #ifdef CONFIG_WIFI_DISPLAY
     366          81 :         if (wfd_ie)
     367           3 :                 wpabuf_put_buf(buf, wfd_ie);
     368             : #endif /* CONFIG_WIFI_DISPLAY */
     369             : 
     370          81 :         if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP])
     371           0 :                 wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP]);
     372             : 
     373          81 :         return buf;
     374             : }
     375             : 
     376             : 
     377          15 : static int p2ps_setup_p2ps_prov(struct p2p_data *p2p, u32 adv_id,
     378             :                                 u32 session_id, u16 method,
     379             :                                 const u8 *session_mac, const u8 *adv_mac)
     380             : {
     381             :         struct p2ps_provision *tmp;
     382             : 
     383          15 :         if (!p2p->p2ps_prov) {
     384           7 :                 p2p->p2ps_prov = os_zalloc(sizeof(struct p2ps_provision) + 1);
     385           7 :                 if (!p2p->p2ps_prov)
     386           0 :                         return -1;
     387             :         } else {
     388           8 :                 os_memset(p2p->p2ps_prov, 0, sizeof(struct p2ps_provision) + 1);
     389             :         }
     390             : 
     391          15 :         tmp = p2p->p2ps_prov;
     392          15 :         tmp->adv_id = adv_id;
     393          15 :         tmp->session_id = session_id;
     394          15 :         tmp->method = method;
     395          15 :         os_memcpy(tmp->session_mac, session_mac, ETH_ALEN);
     396          15 :         os_memcpy(tmp->adv_mac, adv_mac, ETH_ALEN);
     397          15 :         tmp->info[0] = '\0';
     398             : 
     399          15 :         return 0;
     400             : }
     401             : 
     402             : 
     403          82 : void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
     404             :                                const u8 *data, size_t len, int rx_freq)
     405             : {
     406             :         struct p2p_message msg;
     407             :         struct p2p_device *dev;
     408             :         int freq;
     409          82 :         enum p2p_status_code reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
     410             :         struct wpabuf *resp;
     411          82 :         u32 adv_id = 0;
     412          82 :         struct p2ps_advertisement *p2ps_adv = NULL;
     413          82 :         u8 conncap = P2PS_SETUP_NEW;
     414          82 :         u8 auto_accept = 0;
     415          82 :         u32 session_id = 0;
     416             :         u8 session_mac[ETH_ALEN];
     417             :         u8 adv_mac[ETH_ALEN];
     418             :         u8 group_mac[ETH_ALEN];
     419          82 :         int passwd_id = DEV_PW_DEFAULT;
     420             :         u16 config_methods;
     421             : 
     422          82 :         if (p2p_parse(data, len, &msg))
     423           2 :                 return;
     424             : 
     425         567 :         p2p_dbg(p2p, "Received Provision Discovery Request from " MACSTR
     426             :                 " with config methods 0x%x (freq=%d)",
     427         567 :                 MAC2STR(sa), msg.wps_config_methods, rx_freq);
     428             : 
     429          81 :         dev = p2p_get_device(p2p, sa);
     430          81 :         if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
     431         402 :                 p2p_dbg(p2p, "Provision Discovery Request from unknown peer "
     432         402 :                         MACSTR, MAC2STR(sa));
     433             : 
     434         134 :                 if (p2p_add_device(p2p, sa, rx_freq, NULL, 0, data + 1, len - 1,
     435             :                                    0)) {
     436           6 :                         p2p_dbg(p2p, "Provision Discovery Request add device failed "
     437           6 :                                 MACSTR, MAC2STR(sa));
     438             :                 }
     439          14 :         } else if (msg.wfd_subelems) {
     440           1 :                 wpabuf_free(dev->info.wfd_subelems);
     441           1 :                 dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
     442             :         }
     443             : 
     444          81 :         if (!(msg.wps_config_methods &
     445             :               (WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD |
     446             :                WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_P2PS))) {
     447           1 :                 p2p_dbg(p2p, "Unsupported Config Methods in Provision Discovery Request");
     448           1 :                 goto out;
     449             :         }
     450             : 
     451             :         /* Legacy (non-P2PS) - Unknown groups allowed for P2PS */
     452          80 :         if (!msg.adv_id && msg.group_id) {
     453             :                 size_t i;
     454          51 :                 for (i = 0; i < p2p->num_groups; i++) {
     455          50 :                         if (p2p_group_is_group_id_match(p2p->groups[i],
     456             :                                                         msg.group_id,
     457             :                                                         msg.group_id_len))
     458          50 :                                 break;
     459             :                 }
     460          51 :                 if (i == p2p->num_groups) {
     461           1 :                         p2p_dbg(p2p, "PD request for unknown P2P Group ID - reject");
     462           1 :                         goto out;
     463             :                 }
     464             :         }
     465             : 
     466          79 :         if (dev) {
     467          77 :                 dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
     468             :                                 P2P_DEV_PD_PEER_KEYPAD |
     469             :                                 P2P_DEV_PD_PEER_P2PS);
     470             : 
     471             :                 /* Remove stale persistent groups */
     472          77 :                 if (p2p->cfg->remove_stale_groups) {
     473         154 :                         p2p->cfg->remove_stale_groups(
     474          77 :                                 p2p->cfg->cb_ctx, dev->info.p2p_device_addr,
     475             :                                 msg.persistent_dev,
     476             :                                 msg.persistent_ssid, msg.persistent_ssid_len);
     477             :                 }
     478             :         }
     479          79 :         if (msg.wps_config_methods & WPS_CONFIG_DISPLAY) {
     480         336 :                 p2p_dbg(p2p, "Peer " MACSTR
     481         336 :                         " requested us to show a PIN on display", MAC2STR(sa));
     482          56 :                 if (dev)
     483          54 :                         dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
     484          56 :                 passwd_id = DEV_PW_USER_SPECIFIED;
     485          23 :         } else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
     486          42 :                 p2p_dbg(p2p, "Peer " MACSTR
     487             :                         " requested us to write its PIN using keypad",
     488          42 :                         MAC2STR(sa));
     489           7 :                 if (dev)
     490           7 :                         dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
     491           7 :                 passwd_id = DEV_PW_REGISTRAR_SPECIFIED;
     492          16 :         } else if (msg.wps_config_methods & WPS_CONFIG_P2PS) {
     493          60 :                 p2p_dbg(p2p, "Peer " MACSTR " requesting P2PS PIN",
     494          60 :                         MAC2STR(sa));
     495          10 :                 if (dev)
     496          10 :                         dev->flags |= P2P_DEV_PD_PEER_P2PS;
     497          10 :                 passwd_id = DEV_PW_P2PS_DEFAULT;
     498             :         }
     499             : 
     500          79 :         reject = P2P_SC_SUCCESS;
     501             : 
     502          79 :         os_memset(session_mac, 0, ETH_ALEN);
     503          79 :         os_memset(adv_mac, 0, ETH_ALEN);
     504          79 :         os_memset(group_mac, 0, ETH_ALEN);
     505             : 
     506          97 :         if (msg.adv_id && msg.session_id && msg.session_mac && msg.adv_mac &&
     507          33 :             (msg.status || msg.conn_cap)) {
     508             :                 u8 remote_conncap;
     509             : 
     510          18 :                 if (msg.intended_addr)
     511          18 :                         os_memcpy(group_mac, msg.intended_addr, ETH_ALEN);
     512             : 
     513          18 :                 os_memcpy(session_mac, msg.session_mac, ETH_ALEN);
     514          18 :                 os_memcpy(adv_mac, msg.adv_mac, ETH_ALEN);
     515             : 
     516          18 :                 session_id = WPA_GET_LE32(msg.session_id);
     517          18 :                 adv_id = WPA_GET_LE32(msg.adv_id);
     518             : 
     519          18 :                 if (!msg.status)
     520          15 :                         p2ps_adv = p2p_service_p2ps_id(p2p, adv_id);
     521             : 
     522          18 :                 p2p_dbg(p2p, "adv_id: %x - p2ps_adv - %p", adv_id, p2ps_adv);
     523             : 
     524          18 :                 if (msg.conn_cap)
     525          18 :                         conncap = *msg.conn_cap;
     526          18 :                 remote_conncap = conncap;
     527             : 
     528          18 :                 if (p2ps_adv) {
     529          15 :                         auto_accept = p2ps_adv->auto_accept;
     530          30 :                         conncap = p2p->cfg->p2ps_group_capability(
     531          15 :                                 p2p->cfg->cb_ctx, conncap, auto_accept);
     532             : 
     533          15 :                         p2p_dbg(p2p, "Conncap: local:%d remote:%d result:%d",
     534             :                                 auto_accept, remote_conncap, conncap);
     535             : 
     536          30 :                         if (p2ps_adv->config_methods &&
     537          30 :                             !(msg.wps_config_methods &
     538          15 :                               p2ps_adv->config_methods)) {
     539           0 :                                 p2p_dbg(p2p,
     540             :                                         "Unsupported config methods in Provision Discovery Request (own=0x%x peer=0x%x)",
     541           0 :                                         p2ps_adv->config_methods,
     542           0 :                                         msg.wps_config_methods);
     543           0 :                                 reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
     544          15 :                         } else if (!p2ps_adv->state) {
     545           0 :                                 p2p_dbg(p2p, "P2PS state unavailable");
     546           0 :                                 reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
     547          15 :                         } else if (!conncap) {
     548           0 :                                 p2p_dbg(p2p, "Conncap resolution failed");
     549           0 :                                 reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
     550             :                         }
     551             : 
     552          15 :                         if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
     553           2 :                                 p2p_dbg(p2p, "Keypad - always defer");
     554           2 :                                 auto_accept = 0;
     555             :                         }
     556             : 
     557          15 :                         if (auto_accept || reject != P2P_SC_SUCCESS) {
     558             :                                 struct p2ps_provision *tmp;
     559             : 
     560          11 :                                 if (reject == P2P_SC_SUCCESS && !conncap) {
     561           0 :                                         reject =
     562             :                                                 P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
     563             :                                 }
     564             : 
     565          11 :                                 if (p2ps_setup_p2ps_prov(
     566             :                                             p2p, adv_id, session_id,
     567          11 :                                             msg.wps_config_methods,
     568             :                                             session_mac, adv_mac) < 0) {
     569           0 :                                         reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
     570           0 :                                         goto out;
     571             :                                 }
     572             : 
     573          11 :                                 tmp = p2p->p2ps_prov;
     574          11 :                                 if (conncap) {
     575          11 :                                         tmp->conncap = conncap;
     576          11 :                                         tmp->status = P2P_SC_SUCCESS;
     577             :                                 } else {
     578           0 :                                         tmp->conncap = auto_accept;
     579           0 :                                         tmp->status = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
     580             :                                 }
     581             : 
     582          11 :                                 if (reject != P2P_SC_SUCCESS)
     583           0 :                                         goto out;
     584             :                         }
     585           3 :                 } else if (!msg.status) {
     586           0 :                         reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
     587           0 :                         goto out;
     588             :                 }
     589             : 
     590          22 :                 if (!msg.status && !auto_accept &&
     591           7 :                     (!p2p->p2ps_prov || p2p->p2ps_prov->adv_id != adv_id)) {
     592             :                         struct p2ps_provision *tmp;
     593             : 
     594           4 :                         if (!conncap) {
     595           0 :                                 reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
     596           0 :                                 goto out;
     597             :                         }
     598             : 
     599           4 :                         if (p2ps_setup_p2ps_prov(p2p, adv_id, session_id,
     600           4 :                                                  msg.wps_config_methods,
     601             :                                                  session_mac, adv_mac) < 0) {
     602           0 :                                 reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
     603           0 :                                 goto out;
     604             :                         }
     605           4 :                         tmp = p2p->p2ps_prov;
     606           4 :                         reject = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
     607           4 :                         tmp->status = reject;
     608             :                 }
     609             : 
     610          18 :                 if (msg.status) {
     611           6 :                         if (*msg.status &&
     612           3 :                             *msg.status != P2P_SC_SUCCESS_DEFERRED) {
     613           0 :                                 reject = *msg.status;
     614           6 :                         } else if (*msg.status == P2P_SC_SUCCESS_DEFERRED &&
     615           3 :                                    p2p->p2ps_prov) {
     616           3 :                                 u16 method = p2p->p2ps_prov->method;
     617             : 
     618           9 :                                 conncap = p2p->cfg->p2ps_group_capability(
     619           3 :                                         p2p->cfg->cb_ctx, remote_conncap,
     620           3 :                                         p2p->p2ps_prov->conncap);
     621             : 
     622           6 :                                 p2p_dbg(p2p,
     623             :                                         "Conncap: local:%d remote:%d result:%d",
     624           3 :                                         p2p->p2ps_prov->conncap,
     625             :                                         remote_conncap, conncap);
     626             : 
     627             :                                 /*
     628             :                                  * Ensure that if we asked for PIN originally,
     629             :                                  * our method is consistent with original
     630             :                                  * request.
     631             :                                  */
     632           3 :                                 if (method & WPS_CONFIG_DISPLAY)
     633           1 :                                         method = WPS_CONFIG_KEYPAD;
     634           2 :                                 else if (method & WPS_CONFIG_KEYPAD)
     635           1 :                                         method = WPS_CONFIG_DISPLAY;
     636             : 
     637             :                                 /* Reject this "Deferred Accept* if incompatible
     638             :                                  * conncap or method */
     639           6 :                                 if (!conncap ||
     640           3 :                                     !(msg.wps_config_methods & method))
     641           0 :                                         reject =
     642             :                                                 P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
     643             :                                 else
     644           3 :                                         reject = P2P_SC_SUCCESS;
     645             : 
     646           3 :                                 p2p->p2ps_prov->status = reject;
     647           3 :                                 p2p->p2ps_prov->conncap = conncap;
     648             :                         }
     649             :                 }
     650             :         }
     651             : 
     652             : out:
     653          81 :         if (reject == P2P_SC_SUCCESS ||
     654             :             reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE)
     655          79 :                 config_methods = msg.wps_config_methods;
     656             :         else
     657           2 :                 config_methods = 0;
     658          81 :         resp = p2p_build_prov_disc_resp(p2p, dev, msg.dialog_token, reject,
     659             :                                         config_methods, adv_id,
     660             :                                         msg.group_id, msg.group_id_len,
     661             :                                         msg.persistent_ssid,
     662             :                                         msg.persistent_ssid_len);
     663          81 :         if (resp == NULL) {
     664           0 :                 p2p_parse_free(&msg);
     665           0 :                 return;
     666             :         }
     667          81 :         p2p_dbg(p2p, "Sending Provision Discovery Response");
     668          81 :         if (rx_freq > 0)
     669          81 :                 freq = rx_freq;
     670             :         else
     671           0 :                 freq = p2p_channel_to_freq(p2p->cfg->reg_class,
     672           0 :                                            p2p->cfg->channel);
     673          81 :         if (freq < 0) {
     674           0 :                 p2p_dbg(p2p, "Unknown regulatory class/channel");
     675           0 :                 wpabuf_free(resp);
     676           0 :                 p2p_parse_free(&msg);
     677           0 :                 return;
     678             :         }
     679          81 :         p2p->pending_action_state = P2P_PENDING_PD_RESPONSE;
     680         162 :         if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr,
     681          81 :                             p2p->cfg->dev_addr,
     682          81 :                             wpabuf_head(resp), wpabuf_len(resp), 200) < 0) {
     683           0 :                 p2p_dbg(p2p, "Failed to send Action frame");
     684             :         } else
     685          81 :                 p2p->send_action_in_progress = 1;
     686             : 
     687          81 :         wpabuf_free(resp);
     688             : 
     689          81 :         if (!p2p->cfg->p2ps_prov_complete) {
     690             :                 /* Don't emit anything */
     691          84 :         } else if (msg.status && *msg.status != P2P_SC_SUCCESS &&
     692           3 :                    *msg.status != P2P_SC_SUCCESS_DEFERRED) {
     693           0 :                 reject = *msg.status;
     694           0 :                 p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, reject,
     695             :                                              sa, adv_mac, session_mac,
     696             :                                              NULL, adv_id, session_id,
     697             :                                              0, 0, msg.persistent_ssid,
     698             :                                              msg.persistent_ssid_len,
     699             :                                              0, 0, NULL);
     700          84 :         } else if (msg.status && *msg.status == P2P_SC_SUCCESS_DEFERRED &&
     701           3 :                    p2p->p2ps_prov) {
     702           3 :                 p2p->p2ps_prov->status = reject;
     703           3 :                 p2p->p2ps_prov->conncap = conncap;
     704             : 
     705           6 :                 if (reject != P2P_SC_SUCCESS)
     706           0 :                         p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, reject,
     707             :                                                      sa, adv_mac, session_mac,
     708             :                                                      NULL, adv_id,
     709             :                                                      session_id, conncap, 0,
     710             :                                                      msg.persistent_ssid,
     711             :                                                      msg.persistent_ssid_len, 0,
     712             :                                                      0, NULL);
     713             :                 else
     714           6 :                         p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx,
     715           3 :                                                      *msg.status,
     716             :                                                      sa, adv_mac, session_mac,
     717             :                                                      group_mac, adv_id,
     718             :                                                      session_id, conncap,
     719             :                                                      passwd_id,
     720             :                                                      msg.persistent_ssid,
     721             :                                                      msg.persistent_ssid_len, 0,
     722             :                                                      0, NULL);
     723          78 :         } else if (msg.status && p2p->p2ps_prov) {
     724           0 :                 p2p->p2ps_prov->status = P2P_SC_SUCCESS;
     725           0 :                 p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, *msg.status, sa,
     726             :                                              adv_mac, session_mac, group_mac,
     727             :                                              adv_id, session_id, conncap,
     728             :                                              passwd_id,
     729             :                                              msg.persistent_ssid,
     730             :                                              msg.persistent_ssid_len,
     731             :                                              0, 0, NULL);
     732          78 :         } else if (msg.status) {
     733          78 :         } else if (auto_accept && reject == P2P_SC_SUCCESS) {
     734          11 :                 p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, P2P_SC_SUCCESS,
     735             :                                              sa, adv_mac, session_mac,
     736             :                                              group_mac, adv_id, session_id,
     737             :                                              conncap, passwd_id,
     738             :                                              msg.persistent_ssid,
     739             :                                              msg.persistent_ssid_len,
     740             :                                              0, 0, NULL);
     741          71 :         } else if (reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE &&
     742           4 :                    (!msg.session_info || !msg.session_info_len)) {
     743           4 :                 p2p->p2ps_prov->method = msg.wps_config_methods;
     744             : 
     745           4 :                 p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, P2P_SC_SUCCESS,
     746             :                                              sa, adv_mac, session_mac,
     747             :                                              group_mac, adv_id, session_id,
     748             :                                              conncap, passwd_id,
     749             :                                              msg.persistent_ssid,
     750             :                                              msg.persistent_ssid_len,
     751             :                                              0, 1, NULL);
     752          63 :         } else if (reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) {
     753           0 :                 size_t buf_len = msg.session_info_len;
     754           0 :                 char *buf = os_malloc(2 * buf_len + 1);
     755             : 
     756           0 :                 if (buf) {
     757           0 :                         p2p->p2ps_prov->method = msg.wps_config_methods;
     758             : 
     759           0 :                         utf8_escape((char *) msg.session_info, buf_len,
     760           0 :                                     buf, 2 * buf_len + 1);
     761             : 
     762           0 :                         p2p->cfg->p2ps_prov_complete(
     763           0 :                                 p2p->cfg->cb_ctx, P2P_SC_SUCCESS, sa,
     764             :                                 adv_mac, session_mac, group_mac, adv_id,
     765             :                                 session_id, conncap, passwd_id,
     766             :                                 msg.persistent_ssid, msg.persistent_ssid_len,
     767             :                                 0, 1, buf);
     768             : 
     769           0 :                         os_free(buf);
     770             :                 }
     771             :         }
     772             : 
     773          81 :         if (reject == P2P_SC_SUCCESS && p2p->cfg->prov_disc_req) {
     774          75 :                 const u8 *dev_addr = sa;
     775          75 :                 if (msg.p2p_device_addr)
     776          75 :                         dev_addr = msg.p2p_device_addr;
     777         525 :                 p2p->cfg->prov_disc_req(p2p->cfg->cb_ctx, sa,
     778          75 :                                         msg.wps_config_methods,
     779             :                                         dev_addr, msg.pri_dev_type,
     780          75 :                                         msg.device_name, msg.config_methods,
     781         150 :                                         msg.capability ? msg.capability[0] : 0,
     782         150 :                                         msg.capability ? msg.capability[1] :
     783             :                                         0,
     784             :                                         msg.group_id, msg.group_id_len);
     785             :         }
     786          81 :         p2p_parse_free(&msg);
     787             : }
     788             : 
     789             : 
     790          80 : void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
     791             :                                 const u8 *data, size_t len)
     792             : {
     793             :         struct p2p_message msg;
     794             :         struct p2p_device *dev;
     795          80 :         u16 report_config_methods = 0, req_config_methods;
     796          80 :         u8 status = P2P_SC_SUCCESS;
     797          80 :         int success = 0;
     798          80 :         u32 adv_id = 0;
     799          80 :         u8 conncap = P2PS_SETUP_NEW;
     800             :         u8 adv_mac[ETH_ALEN];
     801             :         u8 group_mac[ETH_ALEN];
     802          80 :         int passwd_id = DEV_PW_DEFAULT;
     803             : 
     804          80 :         if (p2p_parse(data, len, &msg))
     805           4 :                 return;
     806             : 
     807             :         /* Parse the P2PS members present */
     808          80 :         if (msg.status)
     809          18 :                 status = *msg.status;
     810             : 
     811          80 :         if (msg.intended_addr)
     812           2 :                 os_memcpy(group_mac, msg.intended_addr, ETH_ALEN);
     813             :         else
     814          78 :                 os_memset(group_mac, 0, ETH_ALEN);
     815             : 
     816          80 :         if (msg.adv_mac)
     817          18 :                 os_memcpy(adv_mac, msg.adv_mac, ETH_ALEN);
     818             :         else
     819          62 :                 os_memset(adv_mac, 0, ETH_ALEN);
     820             : 
     821          80 :         if (msg.adv_id)
     822          18 :                 adv_id = WPA_GET_LE32(msg.adv_id);
     823             : 
     824          80 :         if (msg.conn_cap) {
     825          13 :                 conncap = *msg.conn_cap;
     826             : 
     827             :                 /* Switch bits to local relative */
     828          13 :                 switch (conncap) {
     829             :                 case P2PS_SETUP_GROUP_OWNER:
     830           2 :                         conncap = P2PS_SETUP_CLIENT;
     831           2 :                         break;
     832             :                 case P2PS_SETUP_CLIENT:
     833           6 :                         conncap = P2PS_SETUP_GROUP_OWNER;
     834           6 :                         break;
     835             :                 }
     836             :         }
     837             : 
     838         560 :         p2p_dbg(p2p, "Received Provision Discovery Response from " MACSTR
     839             :                 " with config methods 0x%x",
     840         560 :                 MAC2STR(sa), msg.wps_config_methods);
     841             : 
     842          80 :         dev = p2p_get_device(p2p, sa);
     843          80 :         if (dev == NULL || !dev->req_config_methods) {
     844           6 :                 p2p_dbg(p2p, "Ignore Provision Discovery Response from " MACSTR
     845           6 :                         " with no pending request", MAC2STR(sa));
     846           1 :                 p2p_parse_free(&msg);
     847           1 :                 return;
     848             :         }
     849             : 
     850          79 :         if (dev->dialog_token != msg.dialog_token) {
     851           2 :                 p2p_dbg(p2p, "Ignore Provision Discovery Response with unexpected Dialog Token %u (expected %u)",
     852           2 :                         msg.dialog_token, dev->dialog_token);
     853           1 :                 p2p_parse_free(&msg);
     854           1 :                 return;
     855             :         }
     856             : 
     857          78 :         if (p2p->pending_action_state == P2P_PENDING_PD) {
     858          74 :                 os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
     859          74 :                 p2p->pending_action_state = P2P_NO_PENDING_ACTION;
     860             :         }
     861             : 
     862             :         /*
     863             :          * Use a local copy of the requested config methods since
     864             :          * p2p_reset_pending_pd() can clear this in the peer entry.
     865             :          */
     866          78 :         req_config_methods = dev->req_config_methods;
     867             : 
     868             :         /*
     869             :          * If the response is from the peer to whom a user initiated request
     870             :          * was sent earlier, we reset that state info here.
     871             :          */
     872         152 :         if (p2p->user_initiated_pd &&
     873          74 :             os_memcmp(p2p->pending_pd_devaddr, sa, ETH_ALEN) == 0)
     874           0 :                 p2p_reset_pending_pd(p2p);
     875             : 
     876          78 :         if (msg.wps_config_methods != req_config_methods) {
     877           2 :                 p2p_dbg(p2p, "Peer rejected our Provision Discovery Request (received config_methods 0x%x expected 0x%x",
     878           1 :                         msg.wps_config_methods, req_config_methods);
     879           1 :                 if (p2p->cfg->prov_disc_fail)
     880           1 :                         p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa,
     881             :                                                  P2P_PROV_DISC_REJECTED,
     882             :                                                  adv_id, adv_mac, NULL);
     883           1 :                 p2p_parse_free(&msg);
     884           1 :                 os_free(p2p->p2ps_prov);
     885           1 :                 p2p->p2ps_prov = NULL;
     886           1 :                 goto out;
     887             :         }
     888             : 
     889          77 :         report_config_methods = req_config_methods;
     890          77 :         dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
     891             :                         P2P_DEV_PD_PEER_KEYPAD |
     892             :                         P2P_DEV_PD_PEER_P2PS);
     893          77 :         if (req_config_methods & WPS_CONFIG_DISPLAY) {
     894         324 :                 p2p_dbg(p2p, "Peer " MACSTR
     895         324 :                         " accepted to show a PIN on display", MAC2STR(sa));
     896          54 :                 dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
     897          54 :                 passwd_id = DEV_PW_REGISTRAR_SPECIFIED;
     898          23 :         } else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
     899          42 :                 p2p_dbg(p2p, "Peer " MACSTR
     900             :                         " accepted to write our PIN using keypad",
     901          42 :                         MAC2STR(sa));
     902           7 :                 dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
     903           7 :                 passwd_id = DEV_PW_USER_SPECIFIED;
     904          16 :         } else if (msg.wps_config_methods & WPS_CONFIG_P2PS) {
     905          60 :                 p2p_dbg(p2p, "Peer " MACSTR " accepted P2PS PIN",
     906          60 :                         MAC2STR(sa));
     907          10 :                 dev->flags |= P2P_DEV_PD_PEER_P2PS;
     908          10 :                 passwd_id = DEV_PW_P2PS_DEFAULT;
     909             :         }
     910             : 
     911          91 :         if ((msg.conn_cap || msg.persistent_dev) &&
     912          28 :             msg.adv_id &&
     913          14 :             (status == P2P_SC_SUCCESS || status == P2P_SC_SUCCESS_DEFERRED) &&
     914          14 :             p2p->p2ps_prov) {
     915          14 :                 if (p2p->cfg->p2ps_prov_complete) {
     916          56 :                         p2p->cfg->p2ps_prov_complete(
     917          14 :                                 p2p->cfg->cb_ctx, status, sa, adv_mac,
     918          14 :                                 p2p->p2ps_prov->session_mac,
     919          14 :                                 group_mac, adv_id, p2p->p2ps_prov->session_id,
     920             :                                 conncap, passwd_id, msg.persistent_ssid,
     921             :                                 msg.persistent_ssid_len, 1, 0, NULL);
     922             :                 }
     923          14 :                 os_free(p2p->p2ps_prov);
     924          14 :                 p2p->p2ps_prov = NULL;
     925             :         }
     926             : 
     927          77 :         if (status != P2P_SC_SUCCESS &&
     928           0 :             status != P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE &&
     929           0 :             status != P2P_SC_SUCCESS_DEFERRED && p2p->p2ps_prov) {
     930           0 :                 if (p2p->cfg->p2ps_prov_complete)
     931           0 :                         p2p->cfg->p2ps_prov_complete(
     932           0 :                                 p2p->cfg->cb_ctx, status, sa, adv_mac,
     933           0 :                                 p2p->p2ps_prov->session_mac,
     934           0 :                                 group_mac, adv_id, p2p->p2ps_prov->session_id,
     935             :                                 0, 0, NULL, 0, 1, 0, NULL);
     936           0 :                 os_free(p2p->p2ps_prov);
     937           0 :                 p2p->p2ps_prov = NULL;
     938             :         }
     939             : 
     940          77 :         if (status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) {
     941           4 :                 if (p2p->cfg->remove_stale_groups) {
     942           8 :                         p2p->cfg->remove_stale_groups(p2p->cfg->cb_ctx,
     943           4 :                                                       dev->info.p2p_device_addr,
     944             :                                                       NULL, NULL, 0);
     945             :                 }
     946             : 
     947           4 :                 if (msg.session_info && msg.session_info_len) {
     948           0 :                         size_t info_len = msg.session_info_len;
     949           0 :                         char *deferred_sess_resp = os_malloc(2 * info_len + 1);
     950             : 
     951           0 :                         if (!deferred_sess_resp) {
     952           0 :                                 p2p_parse_free(&msg);
     953           0 :                                 os_free(p2p->p2ps_prov);
     954           0 :                                 p2p->p2ps_prov = NULL;
     955           0 :                                 goto out;
     956             :                         }
     957           0 :                         utf8_escape((char *) msg.session_info, info_len,
     958           0 :                                     deferred_sess_resp, 2 * info_len + 1);
     959             : 
     960           0 :                         if (p2p->cfg->prov_disc_fail)
     961           0 :                                 p2p->cfg->prov_disc_fail(
     962           0 :                                         p2p->cfg->cb_ctx, sa,
     963             :                                         P2P_PROV_DISC_INFO_UNAVAILABLE,
     964             :                                         adv_id, adv_mac,
     965             :                                         deferred_sess_resp);
     966           0 :                         os_free(deferred_sess_resp);
     967             :                 } else
     968           4 :                         if (p2p->cfg->prov_disc_fail)
     969           8 :                                 p2p->cfg->prov_disc_fail(
     970           4 :                                         p2p->cfg->cb_ctx, sa,
     971             :                                         P2P_PROV_DISC_INFO_UNAVAILABLE,
     972             :                                         adv_id, adv_mac, NULL);
     973          73 :         } else if (msg.wps_config_methods != dev->req_config_methods ||
     974             :                    status != P2P_SC_SUCCESS) {
     975           0 :                 p2p_dbg(p2p, "Peer rejected our Provision Discovery Request");
     976           0 :                 if (p2p->cfg->prov_disc_fail)
     977           0 :                         p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa,
     978             :                                                  P2P_PROV_DISC_REJECTED, 0,
     979             :                                                  NULL, NULL);
     980           0 :                 p2p_parse_free(&msg);
     981           0 :                 os_free(p2p->p2ps_prov);
     982           0 :                 p2p->p2ps_prov = NULL;
     983           0 :                 goto out;
     984             :         }
     985             : 
     986             :         /* Store the provisioning info */
     987          77 :         dev->wps_prov_info = msg.wps_config_methods;
     988             : 
     989          77 :         p2p_parse_free(&msg);
     990          77 :         success = 1;
     991             : 
     992             : out:
     993          78 :         dev->req_config_methods = 0;
     994          78 :         p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
     995          78 :         if (dev->flags & P2P_DEV_PD_BEFORE_GO_NEG) {
     996          12 :                 p2p_dbg(p2p, "Start GO Neg after the PD-before-GO-Neg workaround with "
     997          12 :                         MACSTR, MAC2STR(dev->info.p2p_device_addr));
     998           2 :                 dev->flags &= ~P2P_DEV_PD_BEFORE_GO_NEG;
     999           2 :                 p2p_connect_send(p2p, dev);
    1000           2 :                 return;
    1001             :         }
    1002          76 :         if (success && p2p->cfg->prov_disc_resp)
    1003          75 :                 p2p->cfg->prov_disc_resp(p2p->cfg->cb_ctx, sa,
    1004             :                                          report_config_methods);
    1005             : 
    1006          76 :         if (p2p->state == P2P_PD_DURING_FIND) {
    1007          13 :                 p2p_clear_timeout(p2p);
    1008          13 :                 p2p_continue_find(p2p);
    1009             :         }
    1010             : }
    1011             : 
    1012             : 
    1013         200 : int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
    1014             :                            int join, int force_freq)
    1015             : {
    1016             :         struct wpabuf *req;
    1017             :         int freq;
    1018             : 
    1019         200 :         if (force_freq > 0)
    1020          48 :                 freq = force_freq;
    1021             :         else
    1022         152 :                 freq = dev->listen_freq > 0 ? dev->listen_freq :
    1023             :                         dev->oper_freq;
    1024         200 :         if (freq <= 0) {
    1025           6 :                 p2p_dbg(p2p, "No Listen/Operating frequency known for the peer "
    1026             :                         MACSTR " to send Provision Discovery Request",
    1027           6 :                         MAC2STR(dev->info.p2p_device_addr));
    1028           1 :                 return -1;
    1029             :         }
    1030             : 
    1031         199 :         if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) {
    1032           0 :                 if (!(dev->info.dev_capab &
    1033             :                       P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) {
    1034           0 :                         p2p_dbg(p2p, "Cannot use PD with P2P Device " MACSTR
    1035             :                                 " that is in a group and is not discoverable",
    1036           0 :                                 MAC2STR(dev->info.p2p_device_addr));
    1037           0 :                         return -1;
    1038             :                 }
    1039             :                 /* TODO: use device discoverability request through GO */
    1040             :         }
    1041             : 
    1042         199 :         if (p2p->p2ps_prov) {
    1043          18 :                 if (p2p->p2ps_prov->status == P2P_SC_SUCCESS_DEFERRED) {
    1044           3 :                         if (p2p->p2ps_prov->method == WPS_CONFIG_DISPLAY)
    1045           1 :                                 dev->req_config_methods = WPS_CONFIG_KEYPAD;
    1046           2 :                         else if (p2p->p2ps_prov->method == WPS_CONFIG_KEYPAD)
    1047           1 :                                 dev->req_config_methods = WPS_CONFIG_DISPLAY;
    1048             :                         else
    1049           1 :                                 dev->req_config_methods = WPS_CONFIG_P2PS;
    1050             :                 } else {
    1051             :                         /* Order of preference, based on peer's capabilities */
    1052          15 :                         if (p2p->p2ps_prov->method)
    1053          15 :                                 dev->req_config_methods =
    1054          15 :                                         p2p->p2ps_prov->method;
    1055           0 :                         else if (dev->info.config_methods & WPS_CONFIG_P2PS)
    1056           0 :                                 dev->req_config_methods = WPS_CONFIG_P2PS;
    1057           0 :                         else if (dev->info.config_methods & WPS_CONFIG_DISPLAY)
    1058           0 :                                 dev->req_config_methods = WPS_CONFIG_DISPLAY;
    1059             :                         else
    1060           0 :                                 dev->req_config_methods = WPS_CONFIG_KEYPAD;
    1061             :                 }
    1062          54 :                 p2p_dbg(p2p,
    1063             :                         "Building PD Request based on P2PS config method 0x%x status %d --> req_config_methods 0x%x",
    1064          36 :                         p2p->p2ps_prov->method, p2p->p2ps_prov->status,
    1065          18 :                         dev->req_config_methods);
    1066             :         }
    1067             : 
    1068         199 :         req = p2p_build_prov_disc_req(p2p, dev, join);
    1069         199 :         if (req == NULL)
    1070           0 :                 return -1;
    1071             : 
    1072         199 :         if (p2p->state != P2P_IDLE)
    1073          24 :                 p2p_stop_listen_for_freq(p2p, freq);
    1074         199 :         p2p->pending_action_state = P2P_PENDING_PD;
    1075         398 :         if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
    1076         199 :                             p2p->cfg->dev_addr, dev->info.p2p_device_addr,
    1077         199 :                             wpabuf_head(req), wpabuf_len(req), 200) < 0) {
    1078           0 :                 p2p_dbg(p2p, "Failed to send Action frame");
    1079           0 :                 wpabuf_free(req);
    1080           0 :                 return -1;
    1081             :         }
    1082             : 
    1083         199 :         os_memcpy(p2p->pending_pd_devaddr, dev->info.p2p_device_addr, ETH_ALEN);
    1084             : 
    1085         199 :         wpabuf_free(req);
    1086         199 :         return 0;
    1087             : }
    1088             : 
    1089             : 
    1090          88 : int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
    1091             :                       struct p2ps_provision *p2ps_prov,
    1092             :                       u16 config_methods, int join, int force_freq,
    1093             :                       int user_initiated_pd)
    1094             : {
    1095             :         struct p2p_device *dev;
    1096             : 
    1097          88 :         dev = p2p_get_device(p2p, peer_addr);
    1098          88 :         if (dev == NULL)
    1099           7 :                 dev = p2p_get_device_interface(p2p, peer_addr);
    1100          88 :         if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
    1101          42 :                 p2p_dbg(p2p, "Provision Discovery Request destination " MACSTR
    1102          42 :                         " not yet known", MAC2STR(peer_addr));
    1103           7 :                 os_free(p2ps_prov);
    1104           7 :                 return -1;
    1105             :         }
    1106             : 
    1107         567 :         p2p_dbg(p2p, "Provision Discovery Request with " MACSTR
    1108             :                 " (config methods 0x%x)",
    1109         486 :                 MAC2STR(peer_addr), config_methods);
    1110          81 :         if (config_methods == 0 && !p2ps_prov) {
    1111           1 :                 os_free(p2ps_prov);
    1112           1 :                 return -1;
    1113             :         }
    1114             : 
    1115          83 :         if (p2ps_prov && p2ps_prov->status == P2P_SC_SUCCESS_DEFERRED &&
    1116           3 :             p2p->p2ps_prov) {
    1117             :                 /* Use cached method from deferred provisioning */
    1118           3 :                 p2ps_prov->method = p2p->p2ps_prov->method;
    1119             :         }
    1120             : 
    1121             :         /* Reset provisioning info */
    1122          80 :         dev->wps_prov_info = 0;
    1123          80 :         os_free(p2p->p2ps_prov);
    1124          80 :         p2p->p2ps_prov = p2ps_prov;
    1125             : 
    1126          80 :         dev->req_config_methods = config_methods;
    1127          80 :         if (join)
    1128          50 :                 dev->flags |= P2P_DEV_PD_FOR_JOIN;
    1129             :         else
    1130          30 :                 dev->flags &= ~P2P_DEV_PD_FOR_JOIN;
    1131             : 
    1132          86 :         if (p2p->state != P2P_IDLE && p2p->state != P2P_SEARCH &&
    1133           6 :             p2p->state != P2P_LISTEN_ONLY) {
    1134           0 :                 p2p_dbg(p2p, "Busy with other operations; postpone Provision Discovery Request with "
    1135             :                         MACSTR " (config methods 0x%x)",
    1136           0 :                         MAC2STR(peer_addr), config_methods);
    1137           0 :                 return 0;
    1138             :         }
    1139             : 
    1140          80 :         p2p->user_initiated_pd = user_initiated_pd;
    1141          80 :         p2p->pd_force_freq = force_freq;
    1142             : 
    1143          80 :         if (p2p->user_initiated_pd)
    1144          76 :                 p2p->pd_retries = MAX_PROV_DISC_REQ_RETRIES;
    1145             : 
    1146             :         /*
    1147             :          * Assign dialog token here to use the same value in each retry within
    1148             :          * the same PD exchange.
    1149             :          */
    1150          80 :         dev->dialog_token++;
    1151          80 :         if (dev->dialog_token == 0)
    1152           0 :                 dev->dialog_token = 1;
    1153             : 
    1154          80 :         return p2p_send_prov_disc_req(p2p, dev, join, force_freq);
    1155             : }
    1156             : 
    1157             : 
    1158           1 : void p2p_reset_pending_pd(struct p2p_data *p2p)
    1159             : {
    1160             :         struct p2p_device *dev;
    1161             : 
    1162           2 :         dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
    1163           1 :                 if (os_memcmp(p2p->pending_pd_devaddr,
    1164             :                               dev->info.p2p_device_addr, ETH_ALEN))
    1165           0 :                         continue;
    1166           1 :                 if (!dev->req_config_methods)
    1167           0 :                         continue;
    1168           1 :                 if (dev->flags & P2P_DEV_PD_FOR_JOIN)
    1169           0 :                         continue;
    1170             :                 /* Reset the config methods of the device */
    1171           1 :                 dev->req_config_methods = 0;
    1172             :         }
    1173             : 
    1174           1 :         p2p->user_initiated_pd = 0;
    1175           1 :         os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
    1176           1 :         p2p->pd_retries = 0;
    1177           1 :         p2p->pd_force_freq = 0;
    1178           1 : }

Generated by: LCOV version 1.10