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,
|
||||
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->beacon_update = 1;
|
||||
p2p_group_update_ies(group);
|
||||
group->cfg->idle_update(group->cfg->cb_ctx, 1);
|
||||
|
||||
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)
|
||||
group->beacon_update = 1;
|
||||
p2p_group_update_ies(group);
|
||||
if (group->num_members == 1)
|
||||
group->cfg->idle_update(group->cfg->cb_ctx, 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)
|
||||
group->beacon_update = 1;
|
||||
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 },
|
||||
{ INT_RANGE(persistent_reconnect, 0, 1), 0 },
|
||||
{ INT_RANGE(p2p_intra_bss, 0, 1), CFG_CHANGED_P2P_INTRA_BSS },
|
||||
{ INT(p2p_group_idle), 0 },
|
||||
#endif /* CONFIG_P2P */
|
||||
{ FUNC(country), CFG_CHANGED_COUNTRY },
|
||||
{ INT(bss_max_count), 0 },
|
||||
|
|
|
@ -366,6 +366,18 @@ struct wpa_config {
|
|||
int persistent_reconnect;
|
||||
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
|
||||
*/
|
||||
|
|
|
@ -675,7 +675,8 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
|
|||
config->persistent_reconnect);
|
||||
if (config->p2p_intra_bss != DEFAULT_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 */
|
||||
if (config->country[0] && config->country[1]) {
|
||||
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
|
||||
config->p2p_ssid_postfix = wpa_config_read_reg_string(
|
||||
hk, TEXT("p2p_ssid_postfix"));
|
||||
wpa_config_read_reg_dword(hk, TEXT("p2p_group_idle"),
|
||||
(int *) &config->p2p_group_idle);
|
||||
#endif /* CONFIG_P2P */
|
||||
|
||||
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
|
||||
wpa_config_write_reg_string(hk, "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 */
|
||||
|
||||
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);
|
||||
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_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,
|
||||
|
@ -175,6 +177,9 @@ static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s)
|
|||
{
|
||||
struct wpa_ssid *ssid;
|
||||
char *gtype;
|
||||
const char *reason;
|
||||
|
||||
eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
|
||||
|
||||
ssid = wpa_s->current_ssid;
|
||||
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",
|
||||
wpa_s->ifname, wpa_s->cross_connect_uplink);
|
||||
}
|
||||
wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_REMOVED "%s %s",
|
||||
wpa_s->ifname, gtype);
|
||||
switch (wpa_s->removal_reason) {
|
||||
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) {
|
||||
struct wpa_global *global;
|
||||
char *ifname;
|
||||
|
@ -451,6 +467,7 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
|
|||
MAC2STR(go_dev_addr),
|
||||
persistent ? " [PERSISTENT]" : "");
|
||||
wpas_p2p_cross_connect_setup(wpa_s);
|
||||
wpas_p2p_set_group_idle_timeout(wpa_s);
|
||||
} else {
|
||||
wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
|
||||
"%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),
|
||||
persistent ? " [PERSISTENT]" : "");
|
||||
wpas_p2p_cross_connect_setup(wpa_s);
|
||||
wpas_p2p_set_group_idle_timeout(wpa_s);
|
||||
}
|
||||
|
||||
if (persistent)
|
||||
|
@ -743,6 +761,7 @@ static void p2p_go_configured(void *ctx, void *data)
|
|||
wpa_s->parent, ssid,
|
||||
wpa_s->parent->own_addr);
|
||||
wpas_p2p_cross_connect_setup(wpa_s);
|
||||
wpas_p2p_set_group_idle_timeout(wpa_s);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -822,6 +841,8 @@ static void wpas_p2p_clone_config(struct wpa_supplicant *dst,
|
|||
C(device_type);
|
||||
C(config_methods);
|
||||
#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);
|
||||
wpa_s->p2p_long_listen = 0;
|
||||
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);
|
||||
|
||||
/* 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) {
|
||||
prev = wpa_s;
|
||||
wpa_s = wpa_s->next;
|
||||
wpa_s->removal_reason = P2P_GROUP_REMOVAL_REQUESTED;
|
||||
wpas_p2p_group_delete(prev);
|
||||
}
|
||||
return 0;
|
||||
|
@ -2795,6 +2818,7 @@ int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname)
|
|||
if (wpa_s == NULL)
|
||||
return -1;
|
||||
|
||||
wpa_s->removal_reason = P2P_GROUP_REMOVAL_REQUESTED;
|
||||
wpas_p2p_group_delete(wpa_s);
|
||||
|
||||
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,
|
||||
int persistent_group,
|
||||
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->cb_ctx = wpa_s;
|
||||
cfg->ie_update = wpas_p2p_ie_update;
|
||||
cfg->idle_update = wpas_p2p_idle_update;
|
||||
|
||||
group = p2p_group_init(wpa_s->global->p2p, cfg);
|
||||
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,
|
||||
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);
|
||||
else
|
||||
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)
|
||||
{
|
||||
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
|
||||
*/
|
||||
char cross_connect_uplink[100];
|
||||
|
||||
enum {
|
||||
P2P_GROUP_REMOVAL_UNKNOWN,
|
||||
P2P_GROUP_REMOVAL_REQUESTED,
|
||||
P2P_GROUP_REMOVAL_IDLE_TIMEOUT
|
||||
} removal_reason;
|
||||
#endif /* CONFIG_P2P */
|
||||
|
||||
struct wpa_ssid *bgscan_ssid;
|
||||
|
|
Loading…
Reference in a new issue