diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index 7d449c689..af2d24afd 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -214,7 +214,7 @@ void p2p_go_neg_failed(struct p2p_data *p2p, struct p2p_device *peer, } -static void p2p_listen_in_find(struct p2p_data *p2p) +static void p2p_listen_in_find(struct p2p_data *p2p, int dev_disc) { unsigned int r, tu; int freq; @@ -235,6 +235,19 @@ static void p2p_listen_in_find(struct p2p_data *p2p) os_get_random((u8 *) &r, sizeof(r)); tu = (r % ((p2p->max_disc_int - p2p->min_disc_int) + 1) + p2p->min_disc_int) * 100; + if (p2p->max_disc_tu >= 0 && tu > (unsigned int) p2p->max_disc_tu) + tu = p2p->max_disc_tu; + if (!dev_disc && tu < 100) + tu = 100; /* Need to wait in non-device discovery use cases */ + if (p2p->cfg->max_listen && 1024 * tu / 1000 > p2p->cfg->max_listen) + tu = p2p->cfg->max_listen * 1000 / 1024; + + if (tu == 0) { + wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Skip listen state " + "since duration was 0 TU"); + p2p_set_timeout(p2p, 0, 0); + return; + } p2p->pending_listen_freq = freq; p2p->pending_listen_sec = 0; @@ -2327,6 +2340,7 @@ struct p2p_data * p2p_init(const struct p2p_config *cfg) p2p->min_disc_int = 1; p2p->max_disc_int = 3; + p2p->max_disc_tu = -1; os_get_random(&p2p->next_tie_breaker, 1); p2p->next_tie_breaker &= 0x01; @@ -2590,7 +2604,7 @@ void p2p_continue_find(struct p2p_data *p2p) } } - p2p_listen_in_find(p2p); + p2p_listen_in_find(p2p, 1); } @@ -3060,7 +3074,7 @@ static void p2p_timeout_connect(struct p2p_data *p2p) return; } p2p_set_state(p2p, P2P_CONNECT_LISTEN); - p2p_listen_in_find(p2p); + p2p_listen_in_find(p2p, 0); } @@ -3124,7 +3138,7 @@ static void p2p_timeout_wait_peer_idle(struct p2p_data *p2p) "P2P: Go to Listen state while waiting for the peer to become " "ready for GO Negotiation"); p2p_set_state(p2p, P2P_WAIT_PEER_CONNECT); - p2p_listen_in_find(p2p); + p2p_listen_in_find(p2p, 0); } @@ -3192,7 +3206,7 @@ static void p2p_timeout_invite(struct p2p_data *p2p) p2p_set_timeout(p2p, 0, 100000); return; } - p2p_listen_in_find(p2p); + p2p_listen_in_find(p2p, 0); } @@ -4237,3 +4251,20 @@ int p2p_set_wfd_coupled_sink_info(struct p2p_data *p2p, } #endif /* CONFIG_WIFI_DISPLAY */ + + +int p2p_set_disc_int(struct p2p_data *p2p, int min_disc_int, int max_disc_int, + int max_disc_tu) +{ + if (min_disc_int > max_disc_int || min_disc_int < 0 || max_disc_int < 0) + return -1; + + p2p->min_disc_int = min_disc_int; + p2p->max_disc_int = max_disc_int; + p2p->max_disc_tu = max_disc_tu; + wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Set discoverable interval: " + "min=%d max=%d max_tu=%d", min_disc_int, max_disc_int, + max_disc_tu); + + return 0; +} diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index e5833f009..4d40a9f79 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -354,6 +354,11 @@ struct p2p_config { */ size_t ssid_postfix_len; + /** + * max_listen - Maximum listen duration in ms + */ + unsigned int max_listen; + /** * msg_ctx - Context to use with wpa_msg() calls */ @@ -1739,4 +1744,25 @@ int p2p_set_wfd_coupled_sink_info(struct p2p_data *p2p, const struct wpabuf *elem); struct wpabuf * wifi_display_encaps(struct wpabuf *subelems); +/** + * p2p_set_disc_int - Set min/max discoverable interval for p2p_find + * @p2p: P2P module context from p2p_init() + * @min_disc_int: minDiscoverableInterval (in units of 100 TU); default 1 + * @max_disc_int: maxDiscoverableInterval (in units of 100 TU); default 3 + * @max_disc_tu: Maximum number of TUs (1.024 ms) for discoverable interval; or + * -1 not to limit + * Returns: 0 on success, or -1 on failure + * + * This function can be used to configure minDiscoverableInterval and + * maxDiscoverableInterval parameters for the Listen state during device + * discovery (p2p_find). A random number of 100 TU units is picked for each + * Listen state iteration from [min_disc_int,max_disc_int] range. + * + * max_disc_tu can be used to futher limit the discoverable duration. However, + * it should be noted that use of this parameter is not recommended since it + * would not be compliant with the P2P specification. + */ +int p2p_set_disc_int(struct p2p_data *p2p, int min_disc_int, int max_disc_int, + int max_disc_tu); + #endif /* P2P_H */ diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h index 0f00c5402..c38eb3bde 100644 --- a/src/p2p/p2p_i.h +++ b/src/p2p/p2p_i.h @@ -225,6 +225,11 @@ struct p2p_data { */ int max_disc_int; + /** + * max_disc_tu - Maximum number of TUs for discoverable interval + */ + int max_disc_tu; + /** * devices - List of known P2P Device peers */ diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 2f0b38c78..a037cca4c 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -4223,6 +4223,30 @@ static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd) if (os_strcmp(cmd, "disallow_freq") == 0) return p2p_ctrl_disallow_freq(wpa_s, param); + if (os_strcmp(cmd, "disc_int") == 0) { + int min_disc_int, max_disc_int, max_disc_tu; + char *pos; + + pos = param; + + min_disc_int = atoi(pos); + pos = os_strchr(pos, ' '); + if (pos == NULL) + return -1; + *pos++ = '\0'; + + max_disc_int = atoi(pos); + pos = os_strchr(pos, ' '); + if (pos == NULL) + return -1; + *pos++ = '\0'; + + max_disc_tu = atoi(pos); + + return p2p_set_disc_int(wpa_s->global->p2p, min_disc_int, + max_disc_int, max_disc_tu); + } + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'", cmd); diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 800499d14..7dae6ef5c 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -2760,6 +2760,8 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s) p2p.p2p_intra_bss = wpa_s->conf->p2p_intra_bss; + p2p.max_listen = wpa_s->max_remain_on_chan; + global->p2p = p2p_init(&p2p); if (global->p2p == NULL) return -1;