From 6cb27aa85f6f71720404154233587b83cec7c5fe Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Thu, 14 Mar 2013 16:22:31 +0200 Subject: [PATCH] P2P: Fix shared frequency preference for concurrent operations Commit 50285f5ca8086cca45afa42cd23c3a3c1cd58f40 changed number of rules in channel selection and among other things, it broke the design where the currently used operating channel on a virtual interface that is shared by the same radio is preferred to avoid costs related to multi-channel concurrency. Fix this regression by making the P2P module aware of the shared channel and using that preference as the highest priority when re-selecting the channel during negotiation. Signed-hostap: Jouni Malinen --- src/p2p/p2p.c | 8 ++++++++ src/p2p/p2p.h | 11 +++++++++++ src/p2p/p2p_go_neg.c | 12 ++++++++++++ src/p2p/p2p_i.h | 1 + wpa_supplicant/p2p_supplicant.c | 15 +++++++++++++++ 5 files changed, 47 insertions(+) diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index 1dbdf6d1c..d38e9c59d 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -4202,6 +4202,14 @@ void p2p_set_best_channels(struct p2p_data *p2p, int freq_24, int freq_5, } +void p2p_set_own_freq_preference(struct p2p_data *p2p, int freq) +{ + wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Own frequency preference: " + "%d MHz", freq); + p2p->own_freq_preference = freq; +} + + const u8 * p2p_get_go_neg_peer(struct p2p_data *p2p) { if (p2p == NULL || p2p->go_neg_peer == NULL) diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index ae96b6e51..eb57a3a51 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -1641,6 +1641,17 @@ void p2p_update_channel_list(struct p2p_data *p2p, struct p2p_channels *chan); void p2p_set_best_channels(struct p2p_data *p2p, int freq_24, int freq_5, int freq_overall); +/** + * p2p_set_own_freq_preference - Set own preference for channel + * @p2p: P2P module context from p2p_init() + * @freq: Frequency (MHz) of the preferred channel or 0 if no preference + * + * This function can be used to set a preference on the operating channel based + * on frequencies used on the other virtual interfaces that share the same + * radio. If non-zero, this is used to try to avoid multi-channel concurrency. + */ +void p2p_set_own_freq_preference(struct p2p_data *p2p, int freq); + const u8 * p2p_get_go_neg_peer(struct p2p_data *p2p); /** diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c index 8a86c5442..805bf6934 100644 --- a/src/p2p/p2p_go_neg.c +++ b/src/p2p/p2p_go_neg.c @@ -350,6 +350,18 @@ void p2p_reselect_channel(struct p2p_data *p2p, u8 op_reg_class, op_channel; unsigned int i; + if (p2p->own_freq_preference > 0 && + p2p_freq_to_channel(p2p->cfg->country, p2p->own_freq_preference, + &op_reg_class, &op_channel) == 0 && + p2p_channels_includes(intersection, op_reg_class, op_channel)) { + wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Pick own channel " + "preference (reg_class %u channel %u) from " + "intersection", op_reg_class, op_channel); + p2p->op_reg_class = op_reg_class; + p2p->op_channel = op_channel; + return; + } + if (p2p->best_freq_overall > 0 && p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_overall, &op_reg_class, &op_channel) == 0 && diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h index c753d4939..dff226ada 100644 --- a/src/p2p/p2p_i.h +++ b/src/p2p/p2p_i.h @@ -417,6 +417,7 @@ struct p2p_data { int best_freq_24; int best_freq_5; int best_freq_overall; + int own_freq_preference; /** * wps_vendor_ext - WPS Vendor Extensions to add diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index e016f8202..3a06406e9 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -93,6 +93,15 @@ static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s, static int wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s); +static void wpas_p2p_set_own_freq_preference(struct wpa_supplicant *wpa_s, + int freq) +{ + if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) + return; + p2p_set_own_freq_preference(wpa_s->global->p2p, freq); +} + + static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res) { @@ -2410,11 +2419,14 @@ static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid, } accept_inv: + wpas_p2p_set_own_freq_preference(wpa_s, 0); + if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, cur_bssid) == 0 && wpa_s->assoc_freq) { wpa_printf(MSG_DEBUG, "P2P: Trying to force channel to match " "the channel we are already using"); *force_freq = wpa_s->assoc_freq; + wpas_p2p_set_own_freq_preference(wpa_s, wpa_s->assoc_freq); } res = wpa_drv_shared_freq(wpa_s); @@ -2423,6 +2435,7 @@ accept_inv: "with the channel we are already using on a " "shared interface"); *force_freq = res; + wpas_p2p_set_own_freq_preference(wpa_s, res); } return P2P_SC_SUCCESS; @@ -3736,6 +3749,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, &oper_freq); if (res) return res; + wpas_p2p_set_own_freq_preference(wpa_s, oper_freq); wpa_s->create_p2p_iface = wpas_p2p_create_iface(wpa_s); @@ -4807,6 +4821,7 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname, &oper_freq); if (res) return res; + wpas_p2p_set_own_freq_preference(wpa_s, oper_freq); return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid, ssid->ssid, ssid->ssid_len, force_freq,