P2P: Add mechanism for timing out idle groups
A new configuration parameter, p2p_group_idle, can now be used to set idle timeout value for P2P groups in seconds (0 = no timeout). If set, this values is used to remove P2P group (both GO and P2P client) interfaces after the group has been idle (no clients/GO seen) for the configuration duration. The P2P-GROUP-REMOVED event is now indicating the reason for group removal when known. For example: P2P-GROUP-REMOVED wlan0 GO reason=REQUESTED P2P-GROUP-REMOVED wlan1 client reason=IDLE
This commit is contained in:
parent
1f4c7b6b2a
commit
3071e18109
8 changed files with 114 additions and 3 deletions
|
@ -1049,6 +1049,13 @@ struct p2p_group_config {
|
||||||
*/
|
*/
|
||||||
void (*ie_update)(void *ctx, struct wpabuf *beacon_ies,
|
void (*ie_update)(void *ctx, struct wpabuf *beacon_ies,
|
||||||
struct wpabuf *proberesp_ies);
|
struct wpabuf *proberesp_ies);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* idle_update - Notification of changes in group idle state
|
||||||
|
* @ctx: Callback context from cb_ctx
|
||||||
|
* @idle: Whether the group is idle (no associated stations)
|
||||||
|
*/
|
||||||
|
void (*idle_update)(void *ctx, int idle);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -72,6 +72,7 @@ struct p2p_group * p2p_group_init(struct p2p_data *p2p,
|
||||||
group->group_formation = 1;
|
group->group_formation = 1;
|
||||||
group->beacon_update = 1;
|
group->beacon_update = 1;
|
||||||
p2p_group_update_ies(group);
|
p2p_group_update_ies(group);
|
||||||
|
group->cfg->idle_update(group->cfg->cb_ctx, 1);
|
||||||
|
|
||||||
return group;
|
return group;
|
||||||
}
|
}
|
||||||
|
@ -338,6 +339,8 @@ int p2p_group_notif_assoc(struct p2p_group *group, const u8 *addr,
|
||||||
if (group->num_members == group->cfg->max_clients)
|
if (group->num_members == group->cfg->max_clients)
|
||||||
group->beacon_update = 1;
|
group->beacon_update = 1;
|
||||||
p2p_group_update_ies(group);
|
p2p_group_update_ies(group);
|
||||||
|
if (group->num_members == 1)
|
||||||
|
group->cfg->idle_update(group->cfg->cb_ctx, 0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -396,6 +399,8 @@ void p2p_group_notif_disassoc(struct p2p_group *group, const u8 *addr)
|
||||||
if (group->num_members == group->cfg->max_clients - 1)
|
if (group->num_members == group->cfg->max_clients - 1)
|
||||||
group->beacon_update = 1;
|
group->beacon_update = 1;
|
||||||
p2p_group_update_ies(group);
|
p2p_group_update_ies(group);
|
||||||
|
if (group->num_members == 0)
|
||||||
|
group->cfg->idle_update(group->cfg->cb_ctx, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2403,6 +2403,7 @@ static const struct global_parse_data global_fields[] = {
|
||||||
{ STR(p2p_ssid_postfix), CFG_CHANGED_P2P_SSID_POSTFIX },
|
{ STR(p2p_ssid_postfix), CFG_CHANGED_P2P_SSID_POSTFIX },
|
||||||
{ INT_RANGE(persistent_reconnect, 0, 1), 0 },
|
{ INT_RANGE(persistent_reconnect, 0, 1), 0 },
|
||||||
{ INT_RANGE(p2p_intra_bss, 0, 1), CFG_CHANGED_P2P_INTRA_BSS },
|
{ INT_RANGE(p2p_intra_bss, 0, 1), CFG_CHANGED_P2P_INTRA_BSS },
|
||||||
|
{ INT(p2p_group_idle), 0 },
|
||||||
#endif /* CONFIG_P2P */
|
#endif /* CONFIG_P2P */
|
||||||
{ FUNC(country), CFG_CHANGED_COUNTRY },
|
{ FUNC(country), CFG_CHANGED_COUNTRY },
|
||||||
{ INT(bss_max_count), 0 },
|
{ INT(bss_max_count), 0 },
|
||||||
|
|
|
@ -366,6 +366,18 @@ struct wpa_config {
|
||||||
int persistent_reconnect;
|
int persistent_reconnect;
|
||||||
int p2p_intra_bss;
|
int p2p_intra_bss;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* p2p_group_idle - Maximum idle time in seconds for P2P group
|
||||||
|
*
|
||||||
|
* This value controls how long a P2P group is maintained after there
|
||||||
|
* is no other members in the group. As a GO, this means no associated
|
||||||
|
* stations in the group. As a P2P client, this means no GO seen in
|
||||||
|
* scan results. The maximum idle time is specified in seconds with 0
|
||||||
|
* indicating no time limit, i.e., the P2P group remains in active
|
||||||
|
* state indefinitely until explicitly removed.
|
||||||
|
*/
|
||||||
|
unsigned int p2p_group_idle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* bss_max_count - Maximum number of BSS entries to keep in memory
|
* bss_max_count - Maximum number of BSS entries to keep in memory
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -675,7 +675,8 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
|
||||||
config->persistent_reconnect);
|
config->persistent_reconnect);
|
||||||
if (config->p2p_intra_bss != DEFAULT_P2P_INTRA_BSS)
|
if (config->p2p_intra_bss != DEFAULT_P2P_INTRA_BSS)
|
||||||
fprintf(f, "p2p_intra_bss=%u\n", config->p2p_intra_bss);
|
fprintf(f, "p2p_intra_bss=%u\n", config->p2p_intra_bss);
|
||||||
|
if (config->p2p_group_idle)
|
||||||
|
fprintf(f, "p2p_group_idle=%u\n", config->p2p_group_idle);
|
||||||
#endif /* CONFIG_P2P */
|
#endif /* CONFIG_P2P */
|
||||||
if (config->country[0] && config->country[1]) {
|
if (config->country[0] && config->country[1]) {
|
||||||
fprintf(f, "country=%c%c\n",
|
fprintf(f, "country=%c%c\n",
|
||||||
|
|
|
@ -259,6 +259,8 @@ static int wpa_config_read_global(struct wpa_config *config, HKEY hk)
|
||||||
#ifdef CONFIG_P2P
|
#ifdef CONFIG_P2P
|
||||||
config->p2p_ssid_postfix = wpa_config_read_reg_string(
|
config->p2p_ssid_postfix = wpa_config_read_reg_string(
|
||||||
hk, TEXT("p2p_ssid_postfix"));
|
hk, TEXT("p2p_ssid_postfix"));
|
||||||
|
wpa_config_read_reg_dword(hk, TEXT("p2p_group_idle"),
|
||||||
|
(int *) &config->p2p_group_idle);
|
||||||
#endif /* CONFIG_P2P */
|
#endif /* CONFIG_P2P */
|
||||||
|
|
||||||
wpa_config_read_reg_dword(hk, TEXT("bss_max_count"),
|
wpa_config_read_reg_dword(hk, TEXT("bss_max_count"),
|
||||||
|
@ -596,6 +598,8 @@ static int wpa_config_write_global(struct wpa_config *config, HKEY hk)
|
||||||
#ifdef CONFIG_P2P
|
#ifdef CONFIG_P2P
|
||||||
wpa_config_write_reg_string(hk, "p2p_ssid_postfix",
|
wpa_config_write_reg_string(hk, "p2p_ssid_postfix",
|
||||||
config->p2p_ssid_postfix);
|
config->p2p_ssid_postfix);
|
||||||
|
wpa_config_write_reg_dword(hk, TEXT("p2p_group_idle"),
|
||||||
|
config->p2p_group_idle, 0);
|
||||||
#endif /* CONFIG_P2P */
|
#endif /* CONFIG_P2P */
|
||||||
|
|
||||||
wpa_config_write_reg_dword(hk, TEXT("bss_max_count"),
|
wpa_config_write_reg_dword(hk, TEXT("bss_max_count"),
|
||||||
|
|
|
@ -46,6 +46,8 @@ static int wpas_p2p_join(struct wpa_supplicant *wpa_s, const u8 *iface_addr,
|
||||||
const u8 *dev_addr, enum p2p_wps_method wps_method);
|
const u8 *dev_addr, enum p2p_wps_method wps_method);
|
||||||
static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s);
|
static int wpas_p2p_create_iface(struct wpa_supplicant *wpa_s);
|
||||||
static void wpas_p2p_cross_connect_setup(struct wpa_supplicant *wpa_s);
|
static void wpas_p2p_cross_connect_setup(struct wpa_supplicant *wpa_s);
|
||||||
|
static void wpas_p2p_group_idle_timeout(void *eloop_ctx, void *timeout_ctx);
|
||||||
|
static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s);
|
||||||
|
|
||||||
|
|
||||||
static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s,
|
static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s,
|
||||||
|
@ -175,6 +177,9 @@ static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s)
|
||||||
{
|
{
|
||||||
struct wpa_ssid *ssid;
|
struct wpa_ssid *ssid;
|
||||||
char *gtype;
|
char *gtype;
|
||||||
|
const char *reason;
|
||||||
|
|
||||||
|
eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
|
||||||
|
|
||||||
ssid = wpa_s->current_ssid;
|
ssid = wpa_s->current_ssid;
|
||||||
if (ssid == NULL) {
|
if (ssid == NULL) {
|
||||||
|
@ -208,8 +213,19 @@ static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s)
|
||||||
P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
|
P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
|
||||||
wpa_s->ifname, wpa_s->cross_connect_uplink);
|
wpa_s->ifname, wpa_s->cross_connect_uplink);
|
||||||
}
|
}
|
||||||
wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_REMOVED "%s %s",
|
switch (wpa_s->removal_reason) {
|
||||||
wpa_s->ifname, gtype);
|
case P2P_GROUP_REMOVAL_REQUESTED:
|
||||||
|
reason = " reason=REQUESTED";
|
||||||
|
break;
|
||||||
|
case P2P_GROUP_REMOVAL_IDLE_TIMEOUT:
|
||||||
|
reason = " reason=IDLE";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
reason = "";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_REMOVED "%s %s%s",
|
||||||
|
wpa_s->ifname, gtype, reason);
|
||||||
if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
|
if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
|
||||||
struct wpa_global *global;
|
struct wpa_global *global;
|
||||||
char *ifname;
|
char *ifname;
|
||||||
|
@ -451,6 +467,7 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
|
||||||
MAC2STR(go_dev_addr),
|
MAC2STR(go_dev_addr),
|
||||||
persistent ? " [PERSISTENT]" : "");
|
persistent ? " [PERSISTENT]" : "");
|
||||||
wpas_p2p_cross_connect_setup(wpa_s);
|
wpas_p2p_cross_connect_setup(wpa_s);
|
||||||
|
wpas_p2p_set_group_idle_timeout(wpa_s);
|
||||||
} else {
|
} else {
|
||||||
wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
|
wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
|
||||||
"%s GO ssid=\"%s\" freq=%d passphrase=\"%s\" "
|
"%s GO ssid=\"%s\" freq=%d passphrase=\"%s\" "
|
||||||
|
@ -460,6 +477,7 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
|
||||||
MAC2STR(go_dev_addr),
|
MAC2STR(go_dev_addr),
|
||||||
persistent ? " [PERSISTENT]" : "");
|
persistent ? " [PERSISTENT]" : "");
|
||||||
wpas_p2p_cross_connect_setup(wpa_s);
|
wpas_p2p_cross_connect_setup(wpa_s);
|
||||||
|
wpas_p2p_set_group_idle_timeout(wpa_s);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (persistent)
|
if (persistent)
|
||||||
|
@ -743,6 +761,7 @@ static void p2p_go_configured(void *ctx, void *data)
|
||||||
wpa_s->parent, ssid,
|
wpa_s->parent, ssid,
|
||||||
wpa_s->parent->own_addr);
|
wpa_s->parent->own_addr);
|
||||||
wpas_p2p_cross_connect_setup(wpa_s);
|
wpas_p2p_cross_connect_setup(wpa_s);
|
||||||
|
wpas_p2p_set_group_idle_timeout(wpa_s);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -822,6 +841,8 @@ static void wpas_p2p_clone_config(struct wpa_supplicant *dst,
|
||||||
C(device_type);
|
C(device_type);
|
||||||
C(config_methods);
|
C(config_methods);
|
||||||
#undef C
|
#undef C
|
||||||
|
|
||||||
|
d->p2p_group_idle = s->p2p_group_idle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2244,6 +2265,7 @@ void wpas_p2p_deinit(struct wpa_supplicant *wpa_s)
|
||||||
eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
|
eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
|
||||||
wpa_s->p2p_long_listen = 0;
|
wpa_s->p2p_long_listen = 0;
|
||||||
eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
|
eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
|
||||||
|
eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
|
||||||
wpas_p2p_remove_pending_group_interface(wpa_s);
|
wpas_p2p_remove_pending_group_interface(wpa_s);
|
||||||
|
|
||||||
/* TODO: remove group interface from the driver if this wpa_s instance
|
/* TODO: remove group interface from the driver if this wpa_s instance
|
||||||
|
@ -2782,6 +2804,7 @@ int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname)
|
||||||
while (wpa_s) {
|
while (wpa_s) {
|
||||||
prev = wpa_s;
|
prev = wpa_s;
|
||||||
wpa_s = wpa_s->next;
|
wpa_s = wpa_s->next;
|
||||||
|
wpa_s->removal_reason = P2P_GROUP_REMOVAL_REQUESTED;
|
||||||
wpas_p2p_group_delete(prev);
|
wpas_p2p_group_delete(prev);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2795,6 +2818,7 @@ int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname)
|
||||||
if (wpa_s == NULL)
|
if (wpa_s == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
wpa_s->removal_reason = P2P_GROUP_REMOVAL_REQUESTED;
|
||||||
wpas_p2p_group_delete(wpa_s);
|
wpas_p2p_group_delete(wpa_s);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -3001,6 +3025,19 @@ static void wpas_p2p_ie_update(void *ctx, struct wpabuf *beacon_ies,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void wpas_p2p_idle_update(void *ctx, int idle)
|
||||||
|
{
|
||||||
|
struct wpa_supplicant *wpa_s = ctx;
|
||||||
|
if (!wpa_s->ap_iface)
|
||||||
|
return;
|
||||||
|
wpa_printf(MSG_DEBUG, "P2P: GO - group %sidle", idle ? "" : "not ");
|
||||||
|
if (idle)
|
||||||
|
wpas_p2p_set_group_idle_timeout(wpa_s);
|
||||||
|
else
|
||||||
|
eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
|
struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
|
||||||
int persistent_group,
|
int persistent_group,
|
||||||
int group_formation)
|
int group_formation)
|
||||||
|
@ -3021,6 +3058,7 @@ struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
|
||||||
cfg->max_clients = wpa_s->conf->max_num_sta;
|
cfg->max_clients = wpa_s->conf->max_num_sta;
|
||||||
cfg->cb_ctx = wpa_s;
|
cfg->cb_ctx = wpa_s;
|
||||||
cfg->ie_update = wpas_p2p_ie_update;
|
cfg->ie_update = wpas_p2p_ie_update;
|
||||||
|
cfg->idle_update = wpas_p2p_idle_update;
|
||||||
|
|
||||||
group = p2p_group_init(wpa_s->global->p2p, cfg);
|
group = p2p_group_init(wpa_s->global->p2p, cfg);
|
||||||
if (group == NULL)
|
if (group == NULL)
|
||||||
|
@ -3375,6 +3413,39 @@ int wpas_p2p_ext_listen(struct wpa_supplicant *wpa_s, unsigned int period,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void wpas_p2p_group_idle_timeout(void *eloop_ctx, void *timeout_ctx)
|
||||||
|
{
|
||||||
|
struct wpa_supplicant *wpa_s = eloop_ctx;
|
||||||
|
|
||||||
|
if (wpa_s->conf->p2p_group_idle == 0) {
|
||||||
|
wpa_printf(MSG_DEBUG, "P2P: Ignore group idle timeout - "
|
||||||
|
"disabled");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "P2P: Group idle timeout reached - terminate "
|
||||||
|
"group");
|
||||||
|
wpa_s->removal_reason = P2P_GROUP_REMOVAL_IDLE_TIMEOUT;
|
||||||
|
wpas_p2p_group_delete(wpa_s);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s)
|
||||||
|
{
|
||||||
|
eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
|
||||||
|
if (wpa_s->conf->p2p_group_idle == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (wpa_s->current_ssid == NULL || !wpa_s->current_ssid->p2p_group)
|
||||||
|
return;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "P2P: Set P2P group idle timeout to %u seconds",
|
||||||
|
wpa_s->conf->p2p_group_idle);
|
||||||
|
eloop_register_timeout(wpa_s->conf->p2p_group_idle, 0,
|
||||||
|
wpas_p2p_group_idle_timeout, wpa_s, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void wpas_p2p_deauth_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
|
void wpas_p2p_deauth_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
|
||||||
u16 reason_code, const u8 *ie, size_t ie_len)
|
u16 reason_code, const u8 *ie, size_t ie_len)
|
||||||
{
|
{
|
||||||
|
@ -3557,12 +3628,16 @@ void wpas_p2p_notif_connected(struct wpa_supplicant *wpa_s)
|
||||||
wpas_p2p_disable_cross_connect(wpa_s);
|
wpas_p2p_disable_cross_connect(wpa_s);
|
||||||
else
|
else
|
||||||
wpas_p2p_enable_cross_connect(wpa_s);
|
wpas_p2p_enable_cross_connect(wpa_s);
|
||||||
|
if (!wpa_s->ap_iface)
|
||||||
|
eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void wpas_p2p_notif_disconnected(struct wpa_supplicant *wpa_s)
|
void wpas_p2p_notif_disconnected(struct wpa_supplicant *wpa_s)
|
||||||
{
|
{
|
||||||
wpas_p2p_disable_cross_connect(wpa_s);
|
wpas_p2p_disable_cross_connect(wpa_s);
|
||||||
|
if (!wpa_s->ap_iface)
|
||||||
|
wpas_p2p_set_group_idle_timeout(wpa_s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -514,6 +514,12 @@ struct wpa_supplicant {
|
||||||
* Uplink interface name for cross connection
|
* Uplink interface name for cross connection
|
||||||
*/
|
*/
|
||||||
char cross_connect_uplink[100];
|
char cross_connect_uplink[100];
|
||||||
|
|
||||||
|
enum {
|
||||||
|
P2P_GROUP_REMOVAL_UNKNOWN,
|
||||||
|
P2P_GROUP_REMOVAL_REQUESTED,
|
||||||
|
P2P_GROUP_REMOVAL_IDLE_TIMEOUT
|
||||||
|
} removal_reason;
|
||||||
#endif /* CONFIG_P2P */
|
#endif /* CONFIG_P2P */
|
||||||
|
|
||||||
struct wpa_ssid *bgscan_ssid;
|
struct wpa_ssid *bgscan_ssid;
|
||||||
|
|
Loading…
Reference in a new issue