From 7cfc4ac31960948afdf8f3ca959b9d8744b4524d Mon Sep 17 00:00:00 2001 From: Anil Gathala Sudha Date: Wed, 10 Nov 2010 13:33:47 +0200 Subject: [PATCH] P2P: Add support for automatic channel selection at GO The driver wrapper may now indicate the preferred channel (e.g., based on scan results) on both 2.4 GHz and 5 GHz bands (and an overall best frequency). When setting up a GO, this preference information is used to select the operating channel if configuration does not include hardcoded channel. Similarly, this information can be used during GO Negotiation to indicate preference for a specific channel based on current channel conditions. p2p_group_add command can now use special values (freq=2 and freq=5) to indicate that the GO is to be started on the specified band. --- src/drivers/driver.h | 25 ++++++- src/p2p/p2p.c | 55 ++++++++++++++- src/p2p/p2p.h | 15 ++++ src/p2p/p2p_i.h | 4 ++ wpa_supplicant/events.c | 13 ++++ wpa_supplicant/p2p_supplicant.c | 113 ++++++++++++++++++++++++++---- wpa_supplicant/p2p_supplicant.h | 2 + wpa_supplicant/wpa_supplicant_i.h | 5 ++ 8 files changed, 215 insertions(+), 17 deletions(-) diff --git a/src/drivers/driver.h b/src/drivers/driver.h index da2daaf73..5bf0f5282 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -2229,7 +2229,16 @@ enum wpa_event_type { * resource conflicts could also trigger this for station mode * interfaces. */ - EVENT_INTERFACE_UNAVAILABLE + EVENT_INTERFACE_UNAVAILABLE, + + /** + * EVENT_BEST_CHANNEL + * + * Driver generates this event whenever it detects a better channel + * (e.g., based on RSSI or channel use). This information can be used + * to improve channel selection for a new AP/P2P group. + */ + EVENT_BEST_CHANNEL }; @@ -2649,6 +2658,20 @@ union wpa_event_data { int current_noise; int current_txrate; } signal_change; + + /** + * struct best_channel - Data for EVENT_BEST_CHANNEL events + * @freq_24: Best 2.4 GHz band channel frequency in MHz + * @freq_5: Best 5 GHz band channel frequency in MHz + * @freq_overall: Best channel frequency in MHz + * + * 0 can be used to indicate no preference in either band. + */ + struct best_channel { + int freq_24; + int freq_5; + int freq_overall; + } best_chan; }; /** diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index 1f0d7c199..02fa35ffb 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -853,14 +853,52 @@ static int p2p_prepare_channel(struct p2p_data *p2p, unsigned int force_freq) p2p->channels.reg_class[0].reg_class = p2p->op_reg_class; p2p->channels.reg_class[0].channel[0] = p2p->op_channel; } else { - p2p->op_reg_class = p2p->cfg->op_reg_class; - p2p->op_channel = p2p->cfg->op_channel; + u8 op_reg_class, op_channel; + + if (!p2p->cfg->cfg_op_channel && p2p->best_freq_overall > 0 && + p2p_supported_freq(p2p, p2p->best_freq_overall) && + p2p_freq_to_channel(p2p->cfg->country, + p2p->best_freq_overall, + &op_reg_class, &op_channel) == 0) { + wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, + "P2P: Select best overall channel as " + "operating channel preference"); + p2p->op_reg_class = op_reg_class; + p2p->op_channel = op_channel; + } else if (!p2p->cfg->cfg_op_channel && p2p->best_freq_5 > 0 && + p2p_supported_freq(p2p, p2p->best_freq_5) && + p2p_freq_to_channel(p2p->cfg->country, + p2p->best_freq_5, + &op_reg_class, &op_channel) == + 0) { + wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, + "P2P: Select best 5 GHz channel as " + "operating channel preference"); + p2p->op_reg_class = op_reg_class; + p2p->op_channel = op_channel; + } else if (!p2p->cfg->cfg_op_channel && + p2p->best_freq_24 > 0 && + p2p_supported_freq(p2p, p2p->best_freq_24) && + p2p_freq_to_channel(p2p->cfg->country, + p2p->best_freq_24, + &op_reg_class, &op_channel) == + 0) { + wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, + "P2P: Select best 2.4 GHz channel as " + "operating channel preference"); + p2p->op_reg_class = op_reg_class; + p2p->op_channel = op_channel; + } else { + p2p->op_reg_class = p2p->cfg->op_reg_class; + p2p->op_channel = p2p->cfg->op_channel; + } + os_memcpy(&p2p->channels, &p2p->cfg->channels, sizeof(struct p2p_channels)); } wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Own preference for operation channel: " - "Regulatory Class %u Channel %u%s", + "Operating Class %u Channel %u%s", p2p->op_reg_class, p2p->op_channel, force_freq ? " (forced)" : ""); @@ -3133,3 +3171,14 @@ int p2p_send_action(struct p2p_data *p2p, unsigned int freq, const u8 *dst, return p2p->cfg->send_action(p2p->cfg->cb_ctx, freq, dst, src, bssid, buf, len, wait_time); } + + +void p2p_set_best_channels(struct p2p_data *p2p, int freq_24, int freq_5, + int freq_overall) +{ + wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Best channel: 2.4 GHz: %d," + " 5 GHz: %d, overall: %d", freq_24, freq_5, freq_overall); + p2p->best_freq_24 = freq_24; + p2p->best_freq_5 = freq_5; + p2p->best_freq_overall = freq_overall; +} diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index a4e5d62b9..7c7f6c754 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -170,6 +170,11 @@ struct p2p_config { */ u8 op_channel; + /** + * cfg_op_channel - Whether op_channel is hardcoded in configuration + */ + u8 cfg_op_channel; + /** * channels - Own supported regulatory classes and channels * @@ -1294,4 +1299,14 @@ int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq); void p2p_update_channel_list(struct p2p_data *p2p, struct p2p_channels *chan); +/** + * p2p_set_best_channels - Update best channel information + * @p2p: P2P module context from p2p_init() + * @freq_24: Frequency (MHz) of best channel in 2.4 GHz band + * @freq_5: Frequency (MHz) of best channel in 5 GHz band + * @freq_overall: Frequency (MHz) of best channel overall + */ +void p2p_set_best_channels(struct p2p_data *p2p, int freq_24, int freq_5, + int freq_overall); + #endif /* P2P_H */ diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h index be05a8428..c31f23af9 100644 --- a/src/p2p/p2p_i.h +++ b/src/p2p/p2p_i.h @@ -383,6 +383,10 @@ struct p2p_data { u8 peer_filter[ETH_ALEN]; int cross_connect; + + int best_freq_24; + int best_freq_5; + int best_freq_overall; }; /** diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index b4e8a0d7e..39ac33b02 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -1874,6 +1874,19 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, case EVENT_INTERFACE_UNAVAILABLE: #ifdef CONFIG_P2P wpas_p2p_interface_unavailable(wpa_s); +#endif /* CONFIG_P2P */ + break; + case EVENT_BEST_CHANNEL: + wpa_printf(MSG_DEBUG, "Best channel event received (%d %d %d)", + data->best_chan.freq_24, data->best_chan.freq_5, + data->best_chan.freq_overall); + wpa_s->best_24_freq = data->best_chan.freq_24; + wpa_s->best_5_freq = data->best_chan.freq_5; + wpa_s->best_overall_freq = data->best_chan.freq_overall; +#ifdef CONFIG_P2P + wpas_p2p_update_best_channels(wpa_s, data->best_chan.freq_24, + data->best_chan.freq_5, + data->best_chan.freq_overall); #endif /* CONFIG_P2P */ break; default: diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index eb4b238ec..2f6ae8990 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -2203,23 +2203,28 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s) os_get_random((u8 *) &r, sizeof(r)); p2p.channel = 1 + (r % 3) * 5; } + wpa_printf(MSG_DEBUG, "P2P: Own listen channel: %d", p2p.channel); if (wpa_s->conf->p2p_oper_reg_class && wpa_s->conf->p2p_oper_channel) { p2p.op_reg_class = wpa_s->conf->p2p_oper_reg_class; p2p.op_channel = wpa_s->conf->p2p_oper_channel; + p2p.cfg_op_channel = 1; + wpa_printf(MSG_DEBUG, "P2P: Configured operating channel: " + "%d:%d", p2p.op_reg_class, p2p.op_channel); + } else { p2p.op_reg_class = 81; /* - * For initial tests, pick the operation channel randomly. - * TODO: Use scan results (etc.) to select the best channel. + * Use random operation channel from (1, 6, 11) if no other + * preference is indicated. */ os_get_random((u8 *) &r, sizeof(r)); - p2p.op_channel = 1 + r % 11; + p2p.op_channel = 1 + (r % 3) * 5; + p2p.cfg_op_channel = 0; + wpa_printf(MSG_DEBUG, "P2P: Random operating channel: " + "%d:%d", p2p.op_reg_class, p2p.op_channel); } - wpa_printf(MSG_DEBUG, "P2P: Own listen channel: %d " - "Own preferred operation channel: %d", - p2p.channel, p2p.op_channel); if (wpa_s->conf->country[0] && wpa_s->conf->country[1]) { os_memcpy(p2p.country, wpa_s->conf->country, 2); p2p.country[2] = 0x04; @@ -2865,16 +2870,48 @@ static void wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s, os_memset(params, 0, sizeof(*params)); params->role_go = 1; - params->freq = 2412; - if (freq) + if (freq) { + wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on forced " + "frequency %d MHz", freq); params->freq = freq; - else if (wpa_s->conf->p2p_oper_reg_class == 81 && - wpa_s->conf->p2p_oper_channel >= 1 && - wpa_s->conf->p2p_oper_channel <= 11) + } else if (wpa_s->conf->p2p_oper_reg_class == 81 && + wpa_s->conf->p2p_oper_channel >= 1 && + wpa_s->conf->p2p_oper_channel <= 11) { params->freq = 2407 + 5 * wpa_s->conf->p2p_oper_channel; - else if (wpa_s->conf->p2p_oper_reg_class == 115 || - wpa_s->conf->p2p_oper_reg_class == 118) + wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on configured " + "frequency %d MHz", params->freq); + } else if (wpa_s->conf->p2p_oper_reg_class == 115 || + wpa_s->conf->p2p_oper_reg_class == 118) { params->freq = 5000 + 5 * wpa_s->conf->p2p_oper_channel; + wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on configured " + "frequency %d MHz", params->freq); + } else if (wpa_s->conf->p2p_oper_channel == 0 && + wpa_s->best_overall_freq > 0 && + p2p_supported_freq(wpa_s->global->p2p, + wpa_s->best_overall_freq)) { + params->freq = wpa_s->best_overall_freq; + wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best overall " + "channel %d MHz", params->freq); + } else if (wpa_s->conf->p2p_oper_channel == 0 && + wpa_s->best_24_freq > 0 && + p2p_supported_freq(wpa_s->global->p2p, + wpa_s->best_24_freq)) { + params->freq = wpa_s->best_24_freq; + wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best 2.4 GHz " + "channel %d MHz", params->freq); + } else if (wpa_s->conf->p2p_oper_channel == 0 && + wpa_s->best_5_freq > 0 && + p2p_supported_freq(wpa_s->global->p2p, + wpa_s->best_5_freq)) { + params->freq = wpa_s->best_5_freq; + wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best 5 GHz " + "channel %d MHz", params->freq); + } else { + params->freq = 2412; + wpa_printf(MSG_DEBUG, "P2P: Set GO freq %d MHz (no preference " + "known)", params->freq); + } + if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid) == 0 && wpa_s->assoc_freq && !freq) { wpa_printf(MSG_DEBUG, "P2P: Force GO on the channel we are " @@ -2927,6 +2964,46 @@ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group, int freq) { struct p2p_go_neg_results params; + unsigned int r; + + if (freq == 2) { + wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 2.4 GHz " + "band"); + if (wpa_s->best_24_freq > 0 && + p2p_supported_freq(wpa_s->global->p2p, + wpa_s->best_24_freq)) { + freq = wpa_s->best_24_freq; + wpa_printf(MSG_DEBUG, "P2P: Use best 2.4 GHz band " + "channel: %d MHz", freq); + } else { + os_get_random((u8 *) &r, sizeof(r)); + freq = 2412 + (r % 3) * 25; + wpa_printf(MSG_DEBUG, "P2P: Use random 2.4 GHz band " + "channel: %d MHz", freq); + } + } + + if (freq == 5) { + wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 5 GHz " + "band"); + if (wpa_s->best_5_freq > 0 && + p2p_supported_freq(wpa_s->global->p2p, + wpa_s->best_5_freq)) { + freq = wpa_s->best_5_freq; + wpa_printf(MSG_DEBUG, "P2P: Use best 5 GHz band " + "channel: %d MHz", freq); + } else { + os_get_random((u8 *) &r, sizeof(r)); + freq = 5180 + (r % 4) * 20; + if (!p2p_supported_freq(wpa_s->global->p2p, freq)) { + wpa_printf(MSG_DEBUG, "P2P: Could not select " + "5 GHz channel for P2P group"); + return -1; + } + wpa_printf(MSG_DEBUG, "P2P: Use random 5 GHz band " + "channel: %d MHz", freq); + } + } if (freq > 0 && !p2p_supported_freq(wpa_s->global->p2p, freq)) { wpa_printf(MSG_DEBUG, "P2P: The forced channel for GO " @@ -3790,3 +3867,13 @@ void wpas_p2p_interface_unavailable(struct wpa_supplicant *wpa_s) wpa_s->removal_reason = P2P_GROUP_REMOVAL_UNAVAILABLE; wpas_p2p_group_delete(wpa_s); } + + +void wpas_p2p_update_best_channels(struct wpa_supplicant *wpa_s, + int freq_24, int freq_5, int freq_overall) +{ + struct p2p_data *p2p = wpa_s->global->p2p; + if (p2p == NULL || (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)) + return; + p2p_set_best_channels(p2p, freq_24, freq_5, freq_overall); +} diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h index a411c9a4f..d0221f221 100644 --- a/wpa_supplicant/p2p_supplicant.h +++ b/wpa_supplicant/p2p_supplicant.h @@ -118,5 +118,7 @@ int wpas_p2p_notif_pbc_overlap(struct wpa_supplicant *wpa_s); void wpas_p2p_update_channel_list(struct wpa_supplicant *wpa_s); int wpas_p2p_cancel(struct wpa_supplicant *wpa_s); void wpas_p2p_interface_unavailable(struct wpa_supplicant *wpa_s); +void wpas_p2p_update_best_channels(struct wpa_supplicant *wpa_s, + int freq_24, int freq_5, int freq_overall); #endif /* P2P_SUPPLICANT_H */ diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 5d8e4d62e..13abea631 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -534,6 +534,11 @@ struct wpa_supplicant { unsigned int wps_freq; int wps_fragment_size; int auto_reconnect_disabled; + + /* Channel preferences for AP/P2P GO use */ + int best_24_freq; + int best_5_freq; + int best_overall_freq; };