From 2cd075844185f21c41068d25442903bfdb6fb169 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 24 Sep 2012 22:15:58 +0300 Subject: [PATCH] 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 --- src/p2p/p2p_go_neg.c | 4 +- src/p2p/p2p_i.h | 2 + src/p2p/p2p_invitation.c | 81 ++++++++++++++++++++++++++++++--- wpa_supplicant/p2p_supplicant.c | 3 +- 4 files changed, 80 insertions(+), 10 deletions(-) diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c index 031b3a1f5..9137aebe9 100644 --- a/src/p2p/p2p_go_neg.c +++ b/src/p2p/p2p_go_neg.c @@ -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, - struct p2p_channels *intersection) +void p2p_reselect_channel(struct p2p_data *p2p, + struct p2p_channels *intersection) { struct p2p_reg_class *cl; int freq; diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h index 860233323..0f00c5402 100644 --- a/src/p2p/p2p_i.h +++ b/src/p2p/p2p_i.h @@ -642,6 +642,8 @@ void p2p_process_go_neg_conf(struct p2p_data *p2p, const u8 *sa, const u8 *data, size_t len); int p2p_connect_send(struct p2p_data *p2p, struct p2p_device *dev); 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 */ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c index d26654b66..e06ba12ca 100644 --- a/src/p2p/p2p_invitation.c +++ b/src/p2p/p2p_invitation.c @@ -233,6 +233,8 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa, } 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, ®_class, &channel) < 0) { 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) channels = &intersection; } 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, - p2p->cfg->op_reg_class, - p2p->cfg->op_channel); + p2p->op_reg_class, + p2p->op_channel); if (op_freq < 0) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Unknown operational channel " "(country=%c%c reg_class=%u channel=%u)", 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; 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) { - reg_class = p2p->cfg->op_reg_class; - channel = p2p->cfg->op_channel; + reg_class = p2p->op_reg_class; + channel = p2p->op_channel; channels = &intersection; } } diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 883761a50..6abdd684b 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -2249,8 +2249,9 @@ static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid, " was accepted; op_freq=%d MHz", MAC2STR(sa), op_freq); if (s) { + int go = s->mode == WPAS_MODE_P2P_GO; 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) { wpas_p2p_join(wpa_s, bssid, go_dev_addr, wpa_s->p2p_wps_method, 0);