diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index 6984cb428..d8615199e 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -1459,7 +1459,7 @@ static void p2p_prepare_channel_best(struct p2p_data *p2p) /** - * p2p_prepare_channel - Select operating channel for GO Negotiation + * p2p_prepare_channel - Select operating channel for GO Negotiation or P2PS PD * @p2p: P2P module context from p2p_init() * @dev: Selected peer device * @force_freq: Forced frequency in MHz or 0 if not forced @@ -1468,9 +1468,9 @@ static void p2p_prepare_channel_best(struct p2p_data *p2p) * Returns: 0 on success, -1 on failure (channel not supported for P2P) * * This function is used to do initial operating channel selection for GO - * Negotiation prior to having received peer information. The selected channel - * may be further optimized in p2p_reselect_channel() once the peer information - * is available. + * Negotiation prior to having received peer information or for P2PS PD + * signalling. The selected channel may be further optimized in + * p2p_reselect_channel() once the peer information is available. */ int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev, unsigned int force_freq, unsigned int pref_freq, int go) diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index b4060be47..481ccd067 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -223,6 +223,16 @@ struct p2ps_provision { */ u8 cpt_priority[P2PS_FEATURE_CAPAB_CPT_MAX + 1]; + /** + * force_freq - The only allowed channel frequency in MHz or 0. + */ + unsigned int force_freq; + + /** + * pref_freq - Preferred operating frequency in MHz or 0. + */ + unsigned int pref_freq; + /** * info - Vendor defined extra Provisioning information */ @@ -1024,6 +1034,8 @@ struct p2p_config { * @ssid_len: Buffer for returning length of @ssid * @group_iface: Buffer for returning whether a separate group interface * would be used + * @freq: Variable for returning the current operating frequency of a + * currently running P2P GO. * Returns: 1 if GO info found, 0 otherwise * * This is used to compose New Group settings (SSID, and intended @@ -1031,7 +1043,8 @@ struct p2p_config { * result in our being an autonomous GO. */ int (*get_go_info)(void *ctx, u8 *intended_addr, - u8 *ssid, size_t *ssid_len, int *group_iface); + u8 *ssid, size_t *ssid_len, int *group_iface, + unsigned int *freq); /** * remove_stale_groups - Remove stale P2PS groups @@ -1070,14 +1083,20 @@ struct p2p_config { /** * p2ps_group_capability - Determine group capability + * @ctx: Callback context from cb_ctx + * @incoming: Peer requested roles, expressed with P2PS_SETUP_* bitmap. + * @role: Local roles, expressed with P2PS_SETUP_* bitmap. + * @force_freq: Variable for returning forced frequency for the group. + * @pref_freq: Variable for returning preferred frequency for the group. + * Returns: P2PS_SETUP_* bitmap of group capability result. * - * This function can be used to determine group capability based on - * information from P2PS PD exchange and the current state of ongoing - * groups and driver capabilities. - * - * P2PS_SETUP_* bitmap is used as the parameters and return value. + * This function can be used to determine group capability and + * frequencies based on information from P2PS PD exchange and the + * current state of ongoing groups and driver capabilities. */ - u8 (*p2ps_group_capability)(void *ctx, u8 incoming, u8 role); + u8 (*p2ps_group_capability)(void *ctx, u8 incoming, u8 role, + unsigned int *force_freq, + unsigned int *pref_freq); /** * get_pref_freq_list - Get preferred frequency list for an interface diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c index de70e3dac..f54752713 100644 --- a/src/p2p/p2p_pd.c +++ b/src/p2p/p2p_pd.c @@ -40,21 +40,31 @@ static void p2p_build_wps_ie_config_methods(struct wpabuf *buf, } -static void p2ps_add_new_group_info(struct p2p_data *p2p, struct wpabuf *buf) +static void p2ps_add_new_group_info(struct p2p_data *p2p, + struct p2p_device *dev, + struct wpabuf *buf) { int found; u8 intended_addr[ETH_ALEN]; u8 ssid[SSID_MAX_LEN]; size_t ssid_len; int group_iface; + unsigned int force_freq; if (!p2p->cfg->get_go_info) return; found = p2p->cfg->get_go_info( p2p->cfg->cb_ctx, intended_addr, ssid, - &ssid_len, &group_iface); + &ssid_len, &group_iface, &force_freq); if (found) { + if (force_freq > 0) { + p2p->p2ps_prov->force_freq = force_freq; + p2p->p2ps_prov->pref_freq = 0; + + if (dev) + p2p_prepare_channel(p2p, dev, force_freq, 0, 0); + } p2p_buf_add_group_id(buf, p2p->cfg->dev_addr, ssid, ssid_len); @@ -96,7 +106,7 @@ static void p2ps_add_pd_req_attrs(struct p2p_data *p2p, struct p2p_device *dev, /* If we might be explicite group owner, add GO details */ if (prov->conncap & (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW)) - p2ps_add_new_group_info(p2p, buf); + p2ps_add_new_group_info(p2p, dev, buf); if (prov->status >= 0) p2p_buf_add_status(buf, (u8) prov->status); @@ -109,25 +119,16 @@ static void p2ps_add_pd_req_attrs(struct p2p_data *p2p, struct p2p_device *dev, go_dev_addr, ssid, &ssid_len, intended_addr); } - /* Add Operating Channel if conncap includes GO */ if (shared_group || - (prov->conncap & (P2PS_SETUP_GROUP_OWNER | - P2PS_SETUP_NEW))) { - u8 tmp; + (prov->conncap & (P2PS_SETUP_CLIENT | P2PS_SETUP_NEW))) + p2p_buf_add_channel_list(buf, p2p->cfg->country, + &p2p->channels); - p2p_go_select_channel(p2p, dev, &tmp); - - if (p2p->op_reg_class && p2p->op_channel) - p2p_buf_add_operating_channel(buf, p2p->cfg->country, - p2p->op_reg_class, - p2p->op_channel); - else - p2p_buf_add_operating_channel(buf, p2p->cfg->country, - p2p->cfg->op_reg_class, - p2p->cfg->op_channel); - } - - p2p_buf_add_channel_list(buf, p2p->cfg->country, &p2p->cfg->channels); + if ((shared_group && !is_zero_ether_addr(intended_addr)) || + (prov->conncap & (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW))) + p2p_buf_add_operating_channel(buf, p2p->cfg->country, + p2p->op_reg_class, + p2p->op_channel); if (prov->info[0]) p2p_buf_add_session_info(buf, prov->info); @@ -324,7 +325,7 @@ static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p, } if (!persist && (prov->conncap & P2PS_SETUP_GROUP_OWNER)) - p2ps_add_new_group_info(p2p, buf); + p2ps_add_new_group_info(p2p, dev, buf); /* Add Operating Channel if conncap indicates GO */ if (persist || (prov->conncap & P2PS_SETUP_GROUP_OWNER)) { @@ -346,7 +347,7 @@ static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p, } p2p_buf_add_channel_list(buf, p2p->cfg->country, - &p2p->cfg->channels); + &p2p->channels); if (!persist && (status == P2P_SC_SUCCESS || status == P2P_SC_SUCCESS_DEFERRED)) @@ -703,9 +704,15 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, } if (p2ps_adv) { + unsigned int forced_freq, pref_freq; + auto_accept = p2ps_adv->auto_accept; conncap = p2p->cfg->p2ps_group_capability(p2p->cfg->cb_ctx, - conncap, auto_accept); + conncap, auto_accept, + &forced_freq, + &pref_freq); + + p2p_prepare_channel(p2p, dev, forced_freq, pref_freq, 0); p2p_dbg(p2p, "Conncap: local:%d remote:%d result:%d", auto_accept, remote_conncap, conncap); @@ -752,6 +759,8 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, } tmp = p2p->p2ps_prov; + tmp->force_freq = forced_freq; + tmp->pref_freq = pref_freq; if (conncap) { tmp->conncap = conncap; tmp->status = P2P_SC_SUCCESS; @@ -814,10 +823,9 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, conncap = p2p->cfg->p2ps_group_capability(p2p->cfg->cb_ctx, remote_conncap, - p2p->p2ps_prov->conncap); - - p2p_dbg(p2p, "Conncap: local:%d remote:%d result:%d", - p2p->p2ps_prov->conncap, remote_conncap, conncap); + p2p->p2ps_prov->conncap, + &p2p->p2ps_prov->force_freq, + &p2p->p2ps_prov->pref_freq); resp_fcap.cpt = p2ps_own_preferred_cpt(p2p->p2ps_prov->cpt_priority, req_fcap->cpt); @@ -825,6 +833,9 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, p2p_dbg(p2p, "cpt: local:0x%x remote:0x%x result:0x%x", p2p->p2ps_prov->cpt_mask, req_fcap->cpt, resp_fcap.cpt); + p2p_prepare_channel(p2p, dev, p2p->p2ps_prov->force_freq, + p2p->p2ps_prov->pref_freq, 0); + /* * Ensure that if we asked for PIN originally, our method is consistent * with original request. @@ -1460,6 +1471,10 @@ int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev, "Building PD Request based on P2PS config method 0x%x status %d --> req_config_methods 0x%x", p2p->p2ps_prov->method, p2p->p2ps_prov->status, dev->req_config_methods); + + if (p2p_prepare_channel(p2p, dev, p2p->p2ps_prov->force_freq, + p2p->p2ps_prov->pref_freq, 1) < 0) + return -1; } req = p2p_build_prov_disc_req(p2p, dev, join); diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 809c45518..fada64a57 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -124,6 +124,10 @@ wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated, int go); static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s, int freq, const u8 *ssid, size_t ssid_len); +static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq, + int *force_freq, int *pref_freq, int go, + unsigned int *pref_freq_list, + unsigned int *num_pref_freq); static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq, const u8 *ssid, size_t ssid_len); static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx); @@ -605,20 +609,6 @@ wpas_p2p_get_cli_group(struct wpa_supplicant *wpa_s) } -/* Find an active P2P group where we are the GO */ -static struct wpa_ssid * wpas_p2p_group_go_ssid(struct wpa_supplicant *wpa_s, - u8 *bssid) -{ - struct wpa_supplicant *go = wpas_p2p_get_go_group(wpa_s); - - if (!go) - return NULL; - - os_memcpy(bssid, go->own_addr, ETH_ALEN); - return go->current_ssid; -} - - /* Find a persistent group where we are the GO */ static struct wpa_ssid * wpas_p2p_get_persistent_go(struct wpa_supplicant *wpa_s) @@ -634,7 +624,9 @@ wpas_p2p_get_persistent_go(struct wpa_supplicant *wpa_s) } -static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role) +static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role, + unsigned int *force_freq, + unsigned int *pref_freq) { struct wpa_supplicant *wpa_s = ctx; struct wpa_ssid *s; @@ -643,9 +635,23 @@ static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role) struct wpa_supplicant *go_wpa_s, *cli_wpa_s; struct wpa_ssid *persistent_go; int p2p_no_group_iface; + unsigned int pref_freq_list[P2P_MAX_PREF_CHANNELS], size; wpa_printf(MSG_DEBUG, "P2P: Conncap - in:%d role:%d", incoming, role); + if (force_freq) + *force_freq = 0; + if (pref_freq) + *pref_freq = 0; + + size = P2P_MAX_PREF_CHANNELS; + if (force_freq && pref_freq && + !wpas_p2p_setup_freqs(wpa_s, 0, (int *) force_freq, + (int *) pref_freq, 0, pref_freq_list, &size)) + wpas_p2p_set_own_freq_preference(wpa_s, + *force_freq ? *force_freq : + *pref_freq); + /* * For non-concurrent capable devices: * If persistent_go, then no new. @@ -3685,11 +3691,12 @@ static int wpas_get_persistent_group(void *ctx, const u8 *addr, const u8 *ssid, static int wpas_get_go_info(void *ctx, u8 *intended_addr, - u8 *ssid, size_t *ssid_len, int *group_iface) + u8 *ssid, size_t *ssid_len, int *group_iface, + unsigned int *freq) { struct wpa_supplicant *wpa_s = ctx; + struct wpa_supplicant *go; struct wpa_ssid *s; - u8 bssid[ETH_ALEN]; /* * group_iface will be set to 1 only if a dedicated interface for P2P @@ -3699,17 +3706,25 @@ static int wpas_get_go_info(void *ctx, u8 *intended_addr, * that the pending interface should be used. */ *group_iface = 0; - s = wpas_p2p_group_go_ssid(wpa_s, bssid); - if (!s) { + + if (freq) + *freq = 0; + + go = wpas_p2p_get_go_group(wpa_s); + if (!go) { s = wpas_p2p_get_persistent_go(wpa_s); *group_iface = wpas_p2p_create_iface(wpa_s); if (s) - os_memcpy(bssid, s->bssid, ETH_ALEN); + os_memcpy(intended_addr, s->bssid, ETH_ALEN); else return 0; + } else { + s = go->current_ssid; + os_memcpy(intended_addr, go->own_addr, ETH_ALEN); + if (freq) + *freq = go->assoc_freq; } - os_memcpy(intended_addr, bssid, ETH_ALEN); os_memcpy(ssid, s->ssid, s->ssid_len); *ssid_len = s->ssid_len; @@ -6235,7 +6250,9 @@ int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr, wpa_s->pending_pd_use = NORMAL_PD; if (p2ps_prov && use == WPAS_P2P_PD_FOR_ASP) { p2ps_prov->conncap = p2ps_group_capability( - wpa_s, P2PS_SETUP_NONE, p2ps_prov->role); + wpa_s, P2PS_SETUP_NONE, p2ps_prov->role, + &p2ps_prov->force_freq, &p2ps_prov->pref_freq); + wpa_printf(MSG_DEBUG, "P2P: %s conncap: %d - ASP parsed: %x %x %d %s", __func__, p2ps_prov->conncap,