P2PS: Add channel policy to PD Request

Add operating channel selection and channel list processing similar to
that done when building GO Negotiation Request, i.e., consider the
currently used channels, configured channels, etc.

P2PS introduces a flow where a responder needs to provide channel data
without being previously aware of the current constraints, i.e., the
channels currently in use by other interfaces. To handle this, extend
the get_group_capability() callback to also handle channel selection
aspects of group capabilities.

In case there is an active P2P GO that is going to be used for the P2PS
PD, force its current operating frequency in the PD attributes.

Signed-off-by: Ilan Peer <ilan.peer@intel.com>
This commit is contained in:
Ilan Peer 2015-10-08 12:35:58 +03:00 committed by Jouni Malinen
parent 4acd5ac67b
commit ebd32943cb
4 changed files with 111 additions and 60 deletions

View file

@ -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() * @p2p: P2P module context from p2p_init()
* @dev: Selected peer device * @dev: Selected peer device
* @force_freq: Forced frequency in MHz or 0 if not forced * @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) * Returns: 0 on success, -1 on failure (channel not supported for P2P)
* *
* This function is used to do initial operating channel selection for GO * This function is used to do initial operating channel selection for GO
* Negotiation prior to having received peer information. The selected channel * Negotiation prior to having received peer information or for P2PS PD
* may be further optimized in p2p_reselect_channel() once the peer information * signalling. The selected channel may be further optimized in
* is available. * p2p_reselect_channel() once the peer information is available.
*/ */
int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev, int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev,
unsigned int force_freq, unsigned int pref_freq, int go) unsigned int force_freq, unsigned int pref_freq, int go)

View file

@ -223,6 +223,16 @@ struct p2ps_provision {
*/ */
u8 cpt_priority[P2PS_FEATURE_CAPAB_CPT_MAX + 1]; 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 * info - Vendor defined extra Provisioning information
*/ */
@ -1024,6 +1034,8 @@ struct p2p_config {
* @ssid_len: Buffer for returning length of @ssid * @ssid_len: Buffer for returning length of @ssid
* @group_iface: Buffer for returning whether a separate group interface * @group_iface: Buffer for returning whether a separate group interface
* would be used * 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 * Returns: 1 if GO info found, 0 otherwise
* *
* This is used to compose New Group settings (SSID, and intended * 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. * result in our being an autonomous GO.
*/ */
int (*get_go_info)(void *ctx, u8 *intended_addr, 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 * remove_stale_groups - Remove stale P2PS groups
@ -1070,14 +1083,20 @@ struct p2p_config {
/** /**
* p2ps_group_capability - Determine group capability * 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 * This function can be used to determine group capability and
* information from P2PS PD exchange and the current state of ongoing * frequencies based on information from P2PS PD exchange and the
* groups and driver capabilities. * current state of ongoing groups and driver capabilities.
*
* P2PS_SETUP_* bitmap is used as the parameters and return value.
*/ */
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 * get_pref_freq_list - Get preferred frequency list for an interface

View file

@ -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; int found;
u8 intended_addr[ETH_ALEN]; u8 intended_addr[ETH_ALEN];
u8 ssid[SSID_MAX_LEN]; u8 ssid[SSID_MAX_LEN];
size_t ssid_len; size_t ssid_len;
int group_iface; int group_iface;
unsigned int force_freq;
if (!p2p->cfg->get_go_info) if (!p2p->cfg->get_go_info)
return; return;
found = p2p->cfg->get_go_info( found = p2p->cfg->get_go_info(
p2p->cfg->cb_ctx, intended_addr, ssid, p2p->cfg->cb_ctx, intended_addr, ssid,
&ssid_len, &group_iface); &ssid_len, &group_iface, &force_freq);
if (found) { 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, p2p_buf_add_group_id(buf, p2p->cfg->dev_addr,
ssid, ssid_len); 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 we might be explicite group owner, add GO details */
if (prov->conncap & (P2PS_SETUP_GROUP_OWNER | if (prov->conncap & (P2PS_SETUP_GROUP_OWNER |
P2PS_SETUP_NEW)) P2PS_SETUP_NEW))
p2ps_add_new_group_info(p2p, buf); p2ps_add_new_group_info(p2p, dev, buf);
if (prov->status >= 0) if (prov->status >= 0)
p2p_buf_add_status(buf, (u8) prov->status); 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); go_dev_addr, ssid, &ssid_len, intended_addr);
} }
/* Add Operating Channel if conncap includes GO */
if (shared_group || if (shared_group ||
(prov->conncap & (P2PS_SETUP_GROUP_OWNER | (prov->conncap & (P2PS_SETUP_CLIENT | P2PS_SETUP_NEW)))
P2PS_SETUP_NEW))) { p2p_buf_add_channel_list(buf, p2p->cfg->country,
u8 tmp; &p2p->channels);
p2p_go_select_channel(p2p, dev, &tmp); if ((shared_group && !is_zero_ether_addr(intended_addr)) ||
(prov->conncap & (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW)))
if (p2p->op_reg_class && p2p->op_channel) p2p_buf_add_operating_channel(buf, p2p->cfg->country,
p2p_buf_add_operating_channel(buf, p2p->cfg->country, p2p->op_reg_class,
p2p->op_reg_class, p2p->op_channel);
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 (prov->info[0]) if (prov->info[0])
p2p_buf_add_session_info(buf, prov->info); 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)) 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 */ /* Add Operating Channel if conncap indicates GO */
if (persist || (prov->conncap & P2PS_SETUP_GROUP_OWNER)) { 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_buf_add_channel_list(buf, p2p->cfg->country,
&p2p->cfg->channels); &p2p->channels);
if (!persist && (status == P2P_SC_SUCCESS || if (!persist && (status == P2P_SC_SUCCESS ||
status == P2P_SC_SUCCESS_DEFERRED)) 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) { if (p2ps_adv) {
unsigned int forced_freq, pref_freq;
auto_accept = p2ps_adv->auto_accept; auto_accept = p2ps_adv->auto_accept;
conncap = p2p->cfg->p2ps_group_capability(p2p->cfg->cb_ctx, 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", p2p_dbg(p2p, "Conncap: local:%d remote:%d result:%d",
auto_accept, remote_conncap, conncap); 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 = p2p->p2ps_prov;
tmp->force_freq = forced_freq;
tmp->pref_freq = pref_freq;
if (conncap) { if (conncap) {
tmp->conncap = conncap; tmp->conncap = conncap;
tmp->status = P2P_SC_SUCCESS; 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, conncap = p2p->cfg->p2ps_group_capability(p2p->cfg->cb_ctx,
remote_conncap, remote_conncap,
p2p->p2ps_prov->conncap); p2p->p2ps_prov->conncap,
&p2p->p2ps_prov->force_freq,
p2p_dbg(p2p, "Conncap: local:%d remote:%d result:%d", &p2p->p2ps_prov->pref_freq);
p2p->p2ps_prov->conncap, remote_conncap, conncap);
resp_fcap.cpt = p2ps_own_preferred_cpt(p2p->p2ps_prov->cpt_priority, resp_fcap.cpt = p2ps_own_preferred_cpt(p2p->p2ps_prov->cpt_priority,
req_fcap->cpt); 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_dbg(p2p, "cpt: local:0x%x remote:0x%x result:0x%x",
p2p->p2ps_prov->cpt_mask, req_fcap->cpt, resp_fcap.cpt); 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 * Ensure that if we asked for PIN originally, our method is consistent
* with original request. * 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", "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, p2p->p2ps_prov->method, p2p->p2ps_prov->status,
dev->req_config_methods); 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); req = p2p_build_prov_disc_req(p2p, dev, join);

View file

@ -124,6 +124,10 @@ wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
int go); int go);
static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s, int freq, static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s, int freq,
const u8 *ssid, size_t ssid_len); 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, static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq,
const u8 *ssid, size_t ssid_len); const u8 *ssid, size_t ssid_len);
static void wpas_p2p_join_scan(void *eloop_ctx, void *timeout_ctx); 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 */ /* Find a persistent group where we are the GO */
static struct wpa_ssid * static struct wpa_ssid *
wpas_p2p_get_persistent_go(struct wpa_supplicant *wpa_s) 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_supplicant *wpa_s = ctx;
struct wpa_ssid *s; 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_supplicant *go_wpa_s, *cli_wpa_s;
struct wpa_ssid *persistent_go; struct wpa_ssid *persistent_go;
int p2p_no_group_iface; 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); 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: * For non-concurrent capable devices:
* If persistent_go, then no new. * 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, 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 *wpa_s = ctx;
struct wpa_supplicant *go;
struct wpa_ssid *s; struct wpa_ssid *s;
u8 bssid[ETH_ALEN];
/* /*
* group_iface will be set to 1 only if a dedicated interface for P2P * 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. * that the pending interface should be used.
*/ */
*group_iface = 0; *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); s = wpas_p2p_get_persistent_go(wpa_s);
*group_iface = wpas_p2p_create_iface(wpa_s); *group_iface = wpas_p2p_create_iface(wpa_s);
if (s) if (s)
os_memcpy(bssid, s->bssid, ETH_ALEN); os_memcpy(intended_addr, s->bssid, ETH_ALEN);
else else
return 0; 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); os_memcpy(ssid, s->ssid, s->ssid_len);
*ssid_len = 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; wpa_s->pending_pd_use = NORMAL_PD;
if (p2ps_prov && use == WPAS_P2P_PD_FOR_ASP) { if (p2ps_prov && use == WPAS_P2P_PD_FOR_ASP) {
p2ps_prov->conncap = p2ps_group_capability( 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, wpa_printf(MSG_DEBUG,
"P2P: %s conncap: %d - ASP parsed: %x %x %d %s", "P2P: %s conncap: %d - ASP parsed: %x %x %d %s",
__func__, p2ps_prov->conncap, __func__, p2ps_prov->conncap,