P2P: Use another interface operating channel as listen channel
Performing a P2P Device flow such as p2p_listen or p2p_find, can degrade the performance of an active interface connection, if the listen frequency is different than the frequency used by that interface. To reduce the effect of P2P Device flows on other interfaces, try changing the listen channel of the P2P Device to match the operating channel of one of the other active interfaces. This change will be possible only in case that the listen channel is not forced externally, and will be delayed to a point where the P2P Device state machine is idle. The optimization can be configured in the configuration file and is disabled by default. Signed-off-by: Ilan Peer <ilan.peer@intel.com>
This commit is contained in:
parent
28812a8983
commit
e3bd6e9dc0
10 changed files with 132 additions and 6 deletions
|
@ -183,6 +183,14 @@ void p2p_set_state(struct p2p_data *p2p, int new_state)
|
||||||
p2p_dbg(p2p, "State %s -> %s",
|
p2p_dbg(p2p, "State %s -> %s",
|
||||||
p2p_state_txt(p2p->state), p2p_state_txt(new_state));
|
p2p_state_txt(p2p->state), p2p_state_txt(new_state));
|
||||||
p2p->state = new_state;
|
p2p->state = new_state;
|
||||||
|
|
||||||
|
if (new_state == P2P_IDLE && p2p->pending_channel) {
|
||||||
|
p2p_dbg(p2p, "Apply change in listen channel");
|
||||||
|
p2p->cfg->reg_class = p2p->pending_reg_class;
|
||||||
|
p2p->cfg->channel = p2p->pending_channel;
|
||||||
|
p2p->pending_reg_class = 0;
|
||||||
|
p2p->pending_channel = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3991,20 +3999,43 @@ void p2p_set_managed_oper(struct p2p_data *p2p, int enabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel)
|
int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel,
|
||||||
|
u8 forced)
|
||||||
{
|
{
|
||||||
if (p2p_channel_to_freq(reg_class, channel) < 0)
|
if (p2p_channel_to_freq(reg_class, channel) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
p2p_dbg(p2p, "Set Listen channel: reg_class %u channel %u",
|
p2p_dbg(p2p, "Set Listen channel: reg_class %u channel %u",
|
||||||
reg_class, channel);
|
reg_class, channel);
|
||||||
p2p->cfg->reg_class = reg_class;
|
|
||||||
p2p->cfg->channel = channel;
|
/*
|
||||||
|
* Listen channel was set in configuration or set by control interface;
|
||||||
|
* cannot override it.
|
||||||
|
*/
|
||||||
|
if (p2p->cfg->channel_forced && forced == 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (p2p->state == P2P_IDLE) {
|
||||||
|
p2p->cfg->reg_class = reg_class;
|
||||||
|
p2p->cfg->channel = channel;
|
||||||
|
p2p->cfg->channel_forced = forced;
|
||||||
|
} else {
|
||||||
|
p2p_dbg(p2p, "Defer setting listen channel");
|
||||||
|
p2p->pending_reg_class = reg_class;
|
||||||
|
p2p->pending_channel = channel;
|
||||||
|
p2p->pending_channel_forced = forced;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
u8 p2p_get_listen_channel(struct p2p_data *p2p)
|
||||||
|
{
|
||||||
|
return p2p->cfg->channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int p2p_set_ssid_postfix(struct p2p_data *p2p, const u8 *postfix, size_t len)
|
int p2p_set_ssid_postfix(struct p2p_data *p2p, const u8 *postfix, size_t len)
|
||||||
{
|
{
|
||||||
p2p_dbg(p2p, "New SSID postfix: %s", wpa_ssid_txt(postfix, len));
|
p2p_dbg(p2p, "New SSID postfix: %s", wpa_ssid_txt(postfix, len));
|
||||||
|
|
|
@ -266,6 +266,12 @@ struct p2p_config {
|
||||||
*/
|
*/
|
||||||
u8 channel;
|
u8 channel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* channel_forced - the listen channel was forced by configuration
|
||||||
|
* or by control interface and cannot be overridden
|
||||||
|
*/
|
||||||
|
u8 channel_forced;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Regulatory class for own operational channel
|
* Regulatory class for own operational channel
|
||||||
*/
|
*/
|
||||||
|
@ -1669,7 +1675,10 @@ void p2p_set_client_discoverability(struct p2p_data *p2p, int enabled);
|
||||||
*/
|
*/
|
||||||
void p2p_set_managed_oper(struct p2p_data *p2p, int enabled);
|
void p2p_set_managed_oper(struct p2p_data *p2p, int enabled);
|
||||||
|
|
||||||
int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel);
|
int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel,
|
||||||
|
u8 forced);
|
||||||
|
|
||||||
|
u8 p2p_get_listen_channel(struct p2p_data *p2p);
|
||||||
|
|
||||||
int p2p_set_ssid_postfix(struct p2p_data *p2p, const u8 *postfix, size_t len);
|
int p2p_set_ssid_postfix(struct p2p_data *p2p, const u8 *postfix, size_t len);
|
||||||
|
|
||||||
|
|
|
@ -480,6 +480,10 @@ struct p2p_data {
|
||||||
unsigned int search_delay;
|
unsigned int search_delay;
|
||||||
int in_search_delay;
|
int in_search_delay;
|
||||||
|
|
||||||
|
u8 pending_reg_class;
|
||||||
|
u8 pending_channel;
|
||||||
|
u8 pending_channel_forced;
|
||||||
|
|
||||||
#ifdef CONFIG_WIFI_DISPLAY
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
struct wpabuf *wfd_ie_beacon;
|
struct wpabuf *wfd_ie_beacon;
|
||||||
struct wpabuf *wfd_ie_probe_req;
|
struct wpabuf *wfd_ie_probe_req;
|
||||||
|
|
|
@ -3256,6 +3256,7 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
|
||||||
config->p2p_go_intent = DEFAULT_P2P_GO_INTENT;
|
config->p2p_go_intent = DEFAULT_P2P_GO_INTENT;
|
||||||
config->p2p_intra_bss = DEFAULT_P2P_INTRA_BSS;
|
config->p2p_intra_bss = DEFAULT_P2P_INTRA_BSS;
|
||||||
config->p2p_go_max_inactivity = DEFAULT_P2P_GO_MAX_INACTIVITY;
|
config->p2p_go_max_inactivity = DEFAULT_P2P_GO_MAX_INACTIVITY;
|
||||||
|
config->p2p_optimize_listen_chan = DEFAULT_P2P_OPTIMIZE_LISTEN_CHAN;
|
||||||
config->bss_max_count = DEFAULT_BSS_MAX_COUNT;
|
config->bss_max_count = DEFAULT_BSS_MAX_COUNT;
|
||||||
config->bss_expiration_age = DEFAULT_BSS_EXPIRATION_AGE;
|
config->bss_expiration_age = DEFAULT_BSS_EXPIRATION_AGE;
|
||||||
config->bss_expiration_scan_count = DEFAULT_BSS_EXPIRATION_SCAN_COUNT;
|
config->bss_expiration_scan_count = DEFAULT_BSS_EXPIRATION_SCAN_COUNT;
|
||||||
|
@ -3838,6 +3839,7 @@ static const struct global_parse_data global_fields[] = {
|
||||||
{ FUNC(p2p_pref_chan), CFG_CHANGED_P2P_PREF_CHAN },
|
{ FUNC(p2p_pref_chan), CFG_CHANGED_P2P_PREF_CHAN },
|
||||||
{ FUNC(p2p_no_go_freq), CFG_CHANGED_P2P_PREF_CHAN },
|
{ FUNC(p2p_no_go_freq), CFG_CHANGED_P2P_PREF_CHAN },
|
||||||
{ INT_RANGE(p2p_add_cli_chan, 0, 1), 0 },
|
{ INT_RANGE(p2p_add_cli_chan, 0, 1), 0 },
|
||||||
|
{ INT_RANGE(p2p_optimize_listen_chan, 0, 1), 0 },
|
||||||
{ INT(p2p_go_ht40), 0 },
|
{ INT(p2p_go_ht40), 0 },
|
||||||
{ INT(p2p_go_vht), 0 },
|
{ INT(p2p_go_vht), 0 },
|
||||||
{ INT(p2p_disabled), 0 },
|
{ INT(p2p_disabled), 0 },
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#define DEFAULT_P2P_GO_INTENT 7
|
#define DEFAULT_P2P_GO_INTENT 7
|
||||||
#define DEFAULT_P2P_INTRA_BSS 1
|
#define DEFAULT_P2P_INTRA_BSS 1
|
||||||
#define DEFAULT_P2P_GO_MAX_INACTIVITY (5 * 60)
|
#define DEFAULT_P2P_GO_MAX_INACTIVITY (5 * 60)
|
||||||
|
#define DEFAULT_P2P_OPTIMIZE_LISTEN_CHAN 0
|
||||||
#define DEFAULT_BSS_MAX_COUNT 200
|
#define DEFAULT_BSS_MAX_COUNT 200
|
||||||
#define DEFAULT_BSS_EXPIRATION_AGE 180
|
#define DEFAULT_BSS_EXPIRATION_AGE 180
|
||||||
#define DEFAULT_BSS_EXPIRATION_SCAN_COUNT 2
|
#define DEFAULT_BSS_EXPIRATION_SCAN_COUNT 2
|
||||||
|
@ -686,6 +687,7 @@ struct wpa_config {
|
||||||
struct wpa_freq_range_list p2p_no_go_freq;
|
struct wpa_freq_range_list p2p_no_go_freq;
|
||||||
int p2p_add_cli_chan;
|
int p2p_add_cli_chan;
|
||||||
int p2p_ignore_shared_freq;
|
int p2p_ignore_shared_freq;
|
||||||
|
int p2p_optimize_listen_chan;
|
||||||
|
|
||||||
struct wpabuf *wps_vendor_ext_m1;
|
struct wpabuf *wps_vendor_ext_m1;
|
||||||
|
|
||||||
|
|
|
@ -1035,6 +1035,10 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
|
||||||
}
|
}
|
||||||
if (config->p2p_add_cli_chan)
|
if (config->p2p_add_cli_chan)
|
||||||
fprintf(f, "p2p_add_cli_chan=%d\n", config->p2p_add_cli_chan);
|
fprintf(f, "p2p_add_cli_chan=%d\n", config->p2p_add_cli_chan);
|
||||||
|
if (config->p2p_optimize_listen_chan !=
|
||||||
|
DEFAULT_P2P_OPTIMIZE_LISTEN_CHAN)
|
||||||
|
fprintf(f, "p2p_optimize_listen_chan=%d\n",
|
||||||
|
config->p2p_optimize_listen_chan);
|
||||||
if (config->p2p_go_ht40)
|
if (config->p2p_go_ht40)
|
||||||
fprintf(f, "p2p_go_ht40=%u\n", config->p2p_go_ht40);
|
fprintf(f, "p2p_go_ht40=%u\n", config->p2p_go_ht40);
|
||||||
if (config->p2p_go_vht)
|
if (config->p2p_go_vht)
|
||||||
|
|
|
@ -4760,7 +4760,7 @@ static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
|
||||||
|
|
||||||
if (os_strcmp(cmd, "listen_channel") == 0) {
|
if (os_strcmp(cmd, "listen_channel") == 0) {
|
||||||
return p2p_set_listen_channel(wpa_s->global->p2p, 81,
|
return p2p_set_listen_channel(wpa_s->global->p2p, 81,
|
||||||
atoi(param));
|
atoi(param), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (os_strcmp(cmd, "ssid_postfix") == 0) {
|
if (os_strcmp(cmd, "ssid_postfix") == 0) {
|
||||||
|
|
|
@ -3872,6 +3872,7 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
|
||||||
wpa_s->conf->p2p_listen_channel) {
|
wpa_s->conf->p2p_listen_channel) {
|
||||||
p2p.reg_class = wpa_s->conf->p2p_listen_reg_class;
|
p2p.reg_class = wpa_s->conf->p2p_listen_reg_class;
|
||||||
p2p.channel = wpa_s->conf->p2p_listen_channel;
|
p2p.channel = wpa_s->conf->p2p_listen_channel;
|
||||||
|
p2p.channel_forced = 1;
|
||||||
} else {
|
} else {
|
||||||
p2p.reg_class = 81;
|
p2p.reg_class = 81;
|
||||||
/*
|
/*
|
||||||
|
@ -3880,6 +3881,7 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
|
||||||
*/
|
*/
|
||||||
os_get_random((u8 *) &r, sizeof(r));
|
os_get_random((u8 *) &r, sizeof(r));
|
||||||
p2p.channel = 1 + (r % 3) * 5;
|
p2p.channel = 1 + (r % 3) * 5;
|
||||||
|
p2p.channel_forced = 0;
|
||||||
}
|
}
|
||||||
wpa_printf(MSG_DEBUG, "P2P: Own listen channel: %d", p2p.channel);
|
wpa_printf(MSG_DEBUG, "P2P: Own listen channel: %d", p2p.channel);
|
||||||
|
|
||||||
|
@ -6270,10 +6272,13 @@ void wpas_p2p_update_config(struct wpa_supplicant *wpa_s)
|
||||||
u8 reg_class, channel;
|
u8 reg_class, channel;
|
||||||
int ret;
|
int ret;
|
||||||
unsigned int r;
|
unsigned int r;
|
||||||
|
u8 channel_forced;
|
||||||
|
|
||||||
if (wpa_s->conf->p2p_listen_reg_class &&
|
if (wpa_s->conf->p2p_listen_reg_class &&
|
||||||
wpa_s->conf->p2p_listen_channel) {
|
wpa_s->conf->p2p_listen_channel) {
|
||||||
reg_class = wpa_s->conf->p2p_listen_reg_class;
|
reg_class = wpa_s->conf->p2p_listen_reg_class;
|
||||||
channel = wpa_s->conf->p2p_listen_channel;
|
channel = wpa_s->conf->p2p_listen_channel;
|
||||||
|
channel_forced = 1;
|
||||||
} else {
|
} else {
|
||||||
reg_class = 81;
|
reg_class = 81;
|
||||||
/*
|
/*
|
||||||
|
@ -6282,8 +6287,10 @@ void wpas_p2p_update_config(struct wpa_supplicant *wpa_s)
|
||||||
*/
|
*/
|
||||||
os_get_random((u8 *) &r, sizeof(r));
|
os_get_random((u8 *) &r, sizeof(r));
|
||||||
channel = 1 + (r % 3) * 5;
|
channel = 1 + (r % 3) * 5;
|
||||||
|
channel_forced = 0;
|
||||||
}
|
}
|
||||||
ret = p2p_set_listen_channel(p2p, reg_class, channel);
|
ret = p2p_set_listen_channel(p2p, reg_class, channel,
|
||||||
|
channel_forced);
|
||||||
if (ret)
|
if (ret)
|
||||||
wpa_printf(MSG_ERROR, "P2P: Own listen channel update "
|
wpa_printf(MSG_ERROR, "P2P: Own listen channel update "
|
||||||
"failed: %d", ret);
|
"failed: %d", ret);
|
||||||
|
@ -7766,3 +7773,60 @@ int wpas_p2p_nfc_tag_enabled(struct wpa_supplicant *wpa_s, int enabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_WPS_NFC */
|
#endif /* CONFIG_WPS_NFC */
|
||||||
|
|
||||||
|
|
||||||
|
static void wpas_p2p_optimize_listen_channel(struct wpa_supplicant *wpa_s,
|
||||||
|
struct wpa_used_freq_data *freqs,
|
||||||
|
unsigned int num)
|
||||||
|
{
|
||||||
|
u8 curr_chan, cand, chan;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
curr_chan = p2p_get_listen_channel(wpa_s->global->p2p);
|
||||||
|
for (i = 0, cand = 0; i < num; i++) {
|
||||||
|
ieee80211_freq_to_chan(freqs[i].freq, &chan);
|
||||||
|
if (curr_chan == chan) {
|
||||||
|
cand = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chan == 1 || chan == 6 || chan == 11)
|
||||||
|
cand = chan;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cand) {
|
||||||
|
wpa_dbg(wpa_s, MSG_DEBUG,
|
||||||
|
"P2P: Update Listen channel to %u baased on operating channel",
|
||||||
|
cand);
|
||||||
|
p2p_set_listen_channel(wpa_s->global->p2p, 81, cand, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void wpas_p2p_indicate_state_change(struct wpa_supplicant *wpa_s)
|
||||||
|
{
|
||||||
|
struct wpa_used_freq_data *freqs;
|
||||||
|
unsigned int num = wpa_s->num_multichan_concurrent;
|
||||||
|
|
||||||
|
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If possible, optimize the Listen channel to be a channel that is
|
||||||
|
* already used by one of the other interfaces.
|
||||||
|
*/
|
||||||
|
if (!wpa_s->conf->p2p_optimize_listen_chan)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!wpa_s->current_ssid || wpa_s->wpa_state != WPA_COMPLETED)
|
||||||
|
return;
|
||||||
|
|
||||||
|
freqs = os_calloc(num, sizeof(struct wpa_used_freq_data));
|
||||||
|
if (!freqs)
|
||||||
|
return;
|
||||||
|
|
||||||
|
num = get_shared_radio_freqs_data(wpa_s, freqs, num);
|
||||||
|
|
||||||
|
wpas_p2p_optimize_listen_channel(wpa_s, freqs, num);
|
||||||
|
os_free(freqs);
|
||||||
|
}
|
||||||
|
|
|
@ -160,6 +160,8 @@ int wpas_p2p_nfc_report_handover(struct wpa_supplicant *wpa_s, int init,
|
||||||
int wpas_p2p_nfc_tag_enabled(struct wpa_supplicant *wpa_s, int enabled);
|
int wpas_p2p_nfc_tag_enabled(struct wpa_supplicant *wpa_s, int enabled);
|
||||||
void wpas_p2p_pbc_overlap_cb(void *eloop_ctx, void *timeout_ctx);
|
void wpas_p2p_pbc_overlap_cb(void *eloop_ctx, void *timeout_ctx);
|
||||||
|
|
||||||
|
void wpas_p2p_indicate_state_change(struct wpa_supplicant *wpa_s);
|
||||||
|
|
||||||
#ifdef CONFIG_P2P
|
#ifdef CONFIG_P2P
|
||||||
int wpas_p2p_4way_hs_failed(struct wpa_supplicant *wpa_s);
|
int wpas_p2p_4way_hs_failed(struct wpa_supplicant *wpa_s);
|
||||||
void wpas_p2p_ap_setup_failed(struct wpa_supplicant *wpa_s);
|
void wpas_p2p_ap_setup_failed(struct wpa_supplicant *wpa_s);
|
||||||
|
|
|
@ -737,6 +737,14 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
|
||||||
if (wpa_s->wpa_state != old_state) {
|
if (wpa_s->wpa_state != old_state) {
|
||||||
wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
|
wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
|
||||||
|
|
||||||
|
#ifdef CONFIG_P2P
|
||||||
|
/*
|
||||||
|
* Notify the P2P Device interface about a state change in one
|
||||||
|
* of the interfaces.
|
||||||
|
*/
|
||||||
|
wpas_p2p_indicate_state_change(wpa_s);
|
||||||
|
#endif /* CONFIG_P2P */
|
||||||
|
|
||||||
if (wpa_s->wpa_state == WPA_COMPLETED ||
|
if (wpa_s->wpa_state == WPA_COMPLETED ||
|
||||||
old_state == WPA_COMPLETED)
|
old_state == WPA_COMPLETED)
|
||||||
wpas_notify_auth_changed(wpa_s);
|
wpas_notify_auth_changed(wpa_s);
|
||||||
|
|
Loading…
Reference in a new issue