p2p_dbg(p2p, "State %s -> %s",
p2p_state_txt(p2p->state), p2p_state_txt(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;
+ }
}
}
-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)
return -1;
p2p_dbg(p2p, "Set Listen channel: reg_class %u channel %u",
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;
}
+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)
{
p2p_dbg(p2p, "New SSID postfix: %s", wpa_ssid_txt(postfix, len));
*/
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
*/
*/
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);
unsigned int search_delay;
int in_search_delay;
+ u8 pending_reg_class;
+ u8 pending_channel;
+ u8 pending_channel_forced;
+
#ifdef CONFIG_WIFI_DISPLAY
struct wpabuf *wfd_ie_beacon;
struct wpabuf *wfd_ie_probe_req;
config->p2p_go_intent = DEFAULT_P2P_GO_INTENT;
config->p2p_intra_bss = DEFAULT_P2P_INTRA_BSS;
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_expiration_age = DEFAULT_BSS_EXPIRATION_AGE;
config->bss_expiration_scan_count = DEFAULT_BSS_EXPIRATION_SCAN_COUNT;
{ FUNC(p2p_pref_chan), 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_optimize_listen_chan, 0, 1), 0 },
{ INT(p2p_go_ht40), 0 },
{ INT(p2p_go_vht), 0 },
{ INT(p2p_disabled), 0 },
#define DEFAULT_P2P_GO_INTENT 7
#define DEFAULT_P2P_INTRA_BSS 1
#define DEFAULT_P2P_GO_MAX_INACTIVITY (5 * 60)
+#define DEFAULT_P2P_OPTIMIZE_LISTEN_CHAN 0
#define DEFAULT_BSS_MAX_COUNT 200
#define DEFAULT_BSS_EXPIRATION_AGE 180
#define DEFAULT_BSS_EXPIRATION_SCAN_COUNT 2
struct wpa_freq_range_list p2p_no_go_freq;
int p2p_add_cli_chan;
int p2p_ignore_shared_freq;
+ int p2p_optimize_listen_chan;
struct wpabuf *wps_vendor_ext_m1;
}
if (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)
fprintf(f, "p2p_go_ht40=%u\n", config->p2p_go_ht40);
if (config->p2p_go_vht)
if (os_strcmp(cmd, "listen_channel") == 0) {
return p2p_set_listen_channel(wpa_s->global->p2p, 81,
- atoi(param));
+ atoi(param), 1);
}
if (os_strcmp(cmd, "ssid_postfix") == 0) {
wpa_s->conf->p2p_listen_channel) {
p2p.reg_class = wpa_s->conf->p2p_listen_reg_class;
p2p.channel = wpa_s->conf->p2p_listen_channel;
+ p2p.channel_forced = 1;
} else {
p2p.reg_class = 81;
/*
*/
os_get_random((u8 *) &r, sizeof(r));
p2p.channel = 1 + (r % 3) * 5;
+ p2p.channel_forced = 0;
}
wpa_printf(MSG_DEBUG, "P2P: Own listen channel: %d", p2p.channel);
u8 reg_class, channel;
int ret;
unsigned int r;
+ u8 channel_forced;
+
if (wpa_s->conf->p2p_listen_reg_class &&
wpa_s->conf->p2p_listen_channel) {
reg_class = wpa_s->conf->p2p_listen_reg_class;
channel = wpa_s->conf->p2p_listen_channel;
+ channel_forced = 1;
} else {
reg_class = 81;
/*
*/
os_get_random((u8 *) &r, sizeof(r));
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)
wpa_printf(MSG_ERROR, "P2P: Own listen channel update "
"failed: %d", ret);
}
#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);
+}
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_indicate_state_change(struct wpa_supplicant *wpa_s);
+
#ifdef CONFIG_P2P
int wpas_p2p_4way_hs_failed(struct wpa_supplicant *wpa_s);
void wpas_p2p_ap_setup_failed(struct wpa_supplicant *wpa_s);
if (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 ||
old_state == WPA_COMPLETED)
wpas_notify_auth_changed(wpa_s);