P2P: Allow peer to propose channel in invitation process

Make Invitation process for re-invoking a persistent group behave
similarly to GO Negotiation as far as channel negotiation is concerned.
The Operating Channel value (if present) is used as a starting point if
the local device does not have a forced operating channel (e.g., due to
concurrent use). Channel lists from devices are then compared to check
that the selected channel is in the intersection. If not, channel is
selected based on GO Negotiation channel rules (best channel preferences
etc.). Invitation Request is rejected if no common channel can be
selected.

Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
Jouni Malinen 2012-09-24 22:15:58 +03:00 committed by Jouni Malinen
parent 7759fba1c2
commit 2cd0758441
4 changed files with 80 additions and 10 deletions

View file

@ -336,8 +336,8 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
} }
static void p2p_reselect_channel(struct p2p_data *p2p, void p2p_reselect_channel(struct p2p_data *p2p,
struct p2p_channels *intersection) struct p2p_channels *intersection)
{ {
struct p2p_reg_class *cl; struct p2p_reg_class *cl;
int freq; int freq;

View file

@ -642,6 +642,8 @@ void p2p_process_go_neg_conf(struct p2p_data *p2p, const u8 *sa,
const u8 *data, size_t len); const u8 *data, size_t len);
int p2p_connect_send(struct p2p_data *p2p, struct p2p_device *dev); int p2p_connect_send(struct p2p_data *p2p, struct p2p_device *dev);
u16 p2p_wps_method_pw_id(enum p2p_wps_method wps_method); u16 p2p_wps_method_pw_id(enum p2p_wps_method wps_method);
void p2p_reselect_channel(struct p2p_data *p2p,
struct p2p_channels *intersection);
/* p2p_pd.c */ /* p2p_pd.c */
void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,

View file

@ -233,6 +233,8 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
} }
if (op_freq) { if (op_freq) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Invitation "
"processing forced frequency %d MHz", op_freq);
if (p2p_freq_to_channel(p2p->cfg->country, op_freq, if (p2p_freq_to_channel(p2p->cfg->country, op_freq,
&reg_class, &channel) < 0) { &reg_class, &channel) < 0) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
@ -256,24 +258,89 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
if (status == P2P_SC_SUCCESS) if (status == P2P_SC_SUCCESS)
channels = &intersection; channels = &intersection;
} else { } else {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: No forced channel from invitation processing - "
"figure out best one to use");
p2p_channels_intersect(&p2p->cfg->channels, &dev->channels,
&intersection);
/* Default to own configuration as a starting point */
p2p->op_reg_class = p2p->cfg->op_reg_class;
p2p->op_channel = p2p->cfg->op_channel;
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Own default "
"op_class %d channel %d",
p2p->op_reg_class, p2p->op_channel);
/* Use peer preference if specified and compatible */
if (msg.operating_channel) {
int req_freq;
req_freq = p2p_channel_to_freq(
(const char *) msg.operating_channel,
msg.operating_channel[3],
msg.operating_channel[4]);
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer "
"operating channel preference: %d MHz",
req_freq);
if (req_freq > 0 &&
p2p_channels_includes(&intersection,
msg.operating_channel[3],
msg.operating_channel[4])) {
p2p->op_reg_class = msg.operating_channel[3];
p2p->op_channel = msg.operating_channel[4];
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Use peer preference op_class %d "
"channel %d",
p2p->op_reg_class, p2p->op_channel);
} else {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Cannot use peer channel "
"preference");
}
}
if (!p2p_channels_includes(&intersection, p2p->op_reg_class,
p2p->op_channel)) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Initially selected channel (op_class %d "
"channel %d) not in channel intersection - try "
"to reselect",
p2p->op_reg_class, p2p->op_channel);
p2p_reselect_channel(p2p, &intersection);
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Re-selection result: op_class %d "
"channel %d",
p2p->op_reg_class, p2p->op_channel);
if (!p2p_channels_includes(&intersection,
p2p->op_reg_class,
p2p->op_channel)) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Peer does not support selected "
"operating channel (reg_class=%u "
"channel=%u)",
p2p->op_reg_class, p2p->op_channel);
status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
goto fail;
}
}
op_freq = p2p_channel_to_freq(p2p->cfg->country, op_freq = p2p_channel_to_freq(p2p->cfg->country,
p2p->cfg->op_reg_class, p2p->op_reg_class,
p2p->cfg->op_channel); p2p->op_channel);
if (op_freq < 0) { if (op_freq < 0) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Unknown operational channel " "P2P: Unknown operational channel "
"(country=%c%c reg_class=%u channel=%u)", "(country=%c%c reg_class=%u channel=%u)",
p2p->cfg->country[0], p2p->cfg->country[1], p2p->cfg->country[0], p2p->cfg->country[1],
p2p->cfg->op_reg_class, p2p->cfg->op_channel); p2p->op_reg_class, p2p->op_channel);
status = P2P_SC_FAIL_NO_COMMON_CHANNELS; status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
goto fail; goto fail;
} }
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Selected operating "
"channel - %d MHz", op_freq);
p2p_channels_intersect(&p2p->cfg->channels, &dev->channels,
&intersection);
if (status == P2P_SC_SUCCESS) { if (status == P2P_SC_SUCCESS) {
reg_class = p2p->cfg->op_reg_class; reg_class = p2p->op_reg_class;
channel = p2p->cfg->op_channel; channel = p2p->op_channel;
channels = &intersection; channels = &intersection;
} }
} }

View file

@ -2249,8 +2249,9 @@ static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid,
" was accepted; op_freq=%d MHz", " was accepted; op_freq=%d MHz",
MAC2STR(sa), op_freq); MAC2STR(sa), op_freq);
if (s) { if (s) {
int go = s->mode == WPAS_MODE_P2P_GO;
wpas_p2p_group_add_persistent( wpas_p2p_group_add_persistent(
wpa_s, s, s->mode == WPAS_MODE_P2P_GO, 0, 0); wpa_s, s, go, go ? op_freq : 0, 0);
} else if (bssid) { } else if (bssid) {
wpas_p2p_join(wpa_s, bssid, go_dev_addr, wpas_p2p_join(wpa_s, bssid, go_dev_addr,
wpa_s->p2p_wps_method, 0); wpa_s->p2p_wps_method, 0);