Add suspend/resume notifications

wpa_supplicant can now be notified of suspend/resume events, e.g.,
from pm-action scripts. This allows wpa_supplicant to clear information
that may become invalid during a suspend operation.
This commit is contained in:
Jouni Malinen 2010-02-27 18:46:02 +02:00
parent be8be6717d
commit 207ef3fb12
11 changed files with 126 additions and 5 deletions

View file

@ -1731,6 +1731,18 @@ struct wpa_driver_ops {
* normal station operations like scanning to be completed. * normal station operations like scanning to be completed.
*/ */
int (*deinit_ap)(void *priv); int (*deinit_ap)(void *priv);
/**
* suspend - Notification on system suspend/hibernate event
* @priv: Private driver interface data
*/
void (*suspend)(void *priv);
/**
* resume - Notification on system resume/thaw event
* @priv: Private driver interface data
*/
void (*resume)(void *priv);
}; };

View file

@ -3272,5 +3272,7 @@ const struct wpa_driver_ops wpa_driver_ndis_ops = {
NULL /* cancel_remain_on_channel */, NULL /* cancel_remain_on_channel */,
NULL /* probe_req_report */, NULL /* probe_req_report */,
NULL /* disable_11b_rates */, NULL /* disable_11b_rates */,
NULL /* deinit_ap */ NULL /* deinit_ap */,
NULL /* suspend */,
NULL /* resume */
}; };

View file

@ -4996,6 +4996,16 @@ static int wpa_driver_nl80211_deinit_ap(void *priv)
} }
static void wpa_driver_nl80211_resume(void *priv)
{
struct wpa_driver_nl80211_data *drv = priv;
if (linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1)) {
wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface up on "
"resume event");
}
}
const struct wpa_driver_ops wpa_driver_nl80211_ops = { const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.name = "nl80211", .name = "nl80211",
.desc = "Linux nl80211/cfg80211", .desc = "Linux nl80211/cfg80211",
@ -5053,4 +5063,5 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.release_interface_addr = wpa_driver_nl80211_release_interface_addr, .release_interface_addr = wpa_driver_nl80211_release_interface_addr,
.disable_11b_rates = wpa_driver_nl80211_disable_11b_rates, .disable_11b_rates = wpa_driver_nl80211_disable_11b_rates,
.deinit_ap = wpa_driver_nl80211_deinit_ap, .deinit_ap = wpa_driver_nl80211_deinit_ap,
.resume = wpa_driver_nl80211_resume,
}; };

View file

@ -1,6 +1,6 @@
/* /*
* WPA Supplicant / Control interface (shared code for all backends) * WPA Supplicant / Control interface (shared code for all backends)
* Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi> * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@ -1812,6 +1812,10 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
reply_len = ap_ctrl_iface_sta_next(wpa_s, buf + 9, reply, reply_len = ap_ctrl_iface_sta_next(wpa_s, buf + 9, reply,
reply_size); reply_size);
#endif /* CONFIG_AP */ #endif /* CONFIG_AP */
} else if (os_strcmp(buf, "SUSPEND") == 0) {
wpas_notify_suspend(wpa_s->global);
} else if (os_strcmp(buf, "RESUME") == 0) {
wpas_notify_resume(wpa_s->global);
} else { } else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16); os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16; reply_len = 16;
@ -2038,6 +2042,10 @@ char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
global, reply, reply_size); global, reply, reply_size);
} else if (os_strcmp(buf, "TERMINATE") == 0) { } else if (os_strcmp(buf, "TERMINATE") == 0) {
wpa_supplicant_terminate_proc(global); wpa_supplicant_terminate_proc(global);
} else if (os_strcmp(buf, "SUSPEND") == 0) {
wpas_notify_suspend(global);
} else if (os_strcmp(buf, "RESUME") == 0) {
wpas_notify_resume(global);
} else { } else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16); os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16; reply_len = 16;

View file

@ -456,4 +456,16 @@ static inline int wpa_drv_deinit_ap(struct wpa_supplicant *wpa_s)
return 0; return 0;
} }
static inline void wpa_drv_suspend(struct wpa_supplicant *wpa_s)
{
if (wpa_s->driver->suspend)
wpa_s->driver->suspend(wpa_s->drv_priv);
}
static inline void wpa_drv_resume(struct wpa_supplicant *wpa_s)
{
if (wpa_s->driver->resume)
wpa_s->driver->resume(wpa_s->drv_priv);
}
#endif /* DRIVER_I_H */ #endif /* DRIVER_I_H */

View file

@ -0,0 +1,17 @@
#!/bin/sh
# /etc/pm/sleep.d/60_wpa_supplicant
# Action script to notify wpa_supplicant of pm-action events.
PATH=/sbin:/usr/sbin:/bin:/usr/bin
WPACLI=wpa_cli
case "$1" in
suspend|hibernate)
$WPACLI suspend
;;
resume|thaw)
$WPACLI resume
;;
esac

View file

@ -1,6 +1,6 @@
/* /*
* wpa_supplicant - Event notifications * wpa_supplicant - Event notifications
* Copyright (c) 2009, Jouni Malinen <j@w1.fi> * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@ -22,6 +22,8 @@
#include "dbus/dbus_common.h" #include "dbus/dbus_common.h"
#include "dbus/dbus_old.h" #include "dbus/dbus_old.h"
#include "dbus/dbus_new.h" #include "dbus/dbus_new.h"
#include "driver_i.h"
#include "scan.h"
#include "notify.h" #include "notify.h"
int wpas_notify_supplicant_initialized(struct wpa_global *global) int wpas_notify_supplicant_initialized(struct wpa_global *global)
@ -301,3 +303,37 @@ void wpas_notify_debug_show_keys_changed(struct wpa_global *global)
{ {
wpas_dbus_signal_debug_show_keys_changed(global); wpas_dbus_signal_debug_show_keys_changed(global);
} }
void wpas_notify_suspend(struct wpa_global *global)
{
struct wpa_supplicant *wpa_s;
os_get_time(&global->suspend_time);
wpa_printf(MSG_DEBUG, "System suspend notification");
for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
wpa_drv_suspend(wpa_s);
}
void wpas_notify_resume(struct wpa_global *global)
{
struct os_time now;
int slept;
struct wpa_supplicant *wpa_s;
if (global->suspend_time.sec == 0)
slept = -1;
else {
os_get_time(&now);
slept = now.sec - global->suspend_time.sec;
}
wpa_printf(MSG_DEBUG, "System resume notification (slept %d seconds)",
slept);
for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
wpa_drv_resume(wpa_s);
if (wpa_s->wpa_state == WPA_DISCONNECTED)
wpa_supplicant_req_scan(wpa_s, 0, 100000);
}
}

View file

@ -1,6 +1,6 @@
/* /*
* wpa_supplicant - Event notifications * wpa_supplicant - Event notifications
* Copyright (c) 2009, Jouni Malinen <j@w1.fi> * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@ -75,5 +75,7 @@ void wpas_notify_blob_removed(struct wpa_supplicant *wpa_s, const char *name);
void wpas_notify_debug_level_changed(struct wpa_global *global); void wpas_notify_debug_level_changed(struct wpa_global *global);
void wpas_notify_debug_timestamp_changed(struct wpa_global *global); void wpas_notify_debug_timestamp_changed(struct wpa_global *global);
void wpas_notify_debug_show_keys_changed(struct wpa_global *global); void wpas_notify_debug_show_keys_changed(struct wpa_global *global);
void wpas_notify_suspend(struct wpa_global *global);
void wpas_notify_resume(struct wpa_global *global);
#endif /* NOTIFY_H */ #endif /* NOTIFY_H */

View file

@ -216,6 +216,7 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
#endif /* CONFIG_WPS */ #endif /* CONFIG_WPS */
struct wpa_driver_scan_params params; struct wpa_driver_scan_params params;
size_t max_ssids; size_t max_ssids;
enum wpa_states prev_state;
if (wpa_s->disconnected && !wpa_s->scan_req) { if (wpa_s->disconnected && !wpa_s->scan_req) {
wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
@ -271,6 +272,7 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
os_memset(&params, 0, sizeof(params)); os_memset(&params, 0, sizeof(params));
prev_state = wpa_s->wpa_state;
if (wpa_s->wpa_state == WPA_DISCONNECTED || if (wpa_s->wpa_state == WPA_DISCONNECTED ||
wpa_s->wpa_state == WPA_INACTIVE) wpa_s->wpa_state == WPA_INACTIVE)
wpa_supplicant_set_state(wpa_s, WPA_SCANNING); wpa_supplicant_set_state(wpa_s, WPA_SCANNING);
@ -368,6 +370,8 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
if (ret) { if (ret) {
wpa_printf(MSG_WARNING, "Failed to initiate AP scan."); wpa_printf(MSG_WARNING, "Failed to initiate AP scan.");
if (prev_state != wpa_s->wpa_state)
wpa_supplicant_set_state(wpa_s, prev_state);
wpa_supplicant_req_scan(wpa_s, 10, 0); wpa_supplicant_req_scan(wpa_s, 10, 0);
} else } else
wpa_s->scan_runs++; wpa_s->scan_runs++;

View file

@ -1403,6 +1403,18 @@ static int wpa_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
#endif /* CONFIG_AP */ #endif /* CONFIG_AP */
static int wpa_cli_cmd_suspend(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
return wpa_ctrl_command(ctrl, "SUSPEND");
}
static int wpa_cli_cmd_resume(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
return wpa_ctrl_command(ctrl, "RESUME");
}
enum wpa_cli_cmd_flags { enum wpa_cli_cmd_flags {
cli_cmd_flag_none = 0x00, cli_cmd_flag_none = 0x00,
cli_cmd_flag_sensitive = 0x01 cli_cmd_flag_sensitive = 0x01
@ -1597,6 +1609,10 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
cli_cmd_flag_none, cli_cmd_flag_none,
"= get information about all associated stations (AP)" }, "= get information about all associated stations (AP)" },
#endif /* CONFIG_AP */ #endif /* CONFIG_AP */
{ "suspend", wpa_cli_cmd_suspend, cli_cmd_flag_none,
"= notification of suspend/hibernate" },
{ "resume", wpa_cli_cmd_resume, cli_cmd_flag_none,
"= notification of resume/thaw" },
{ NULL, NULL, cli_cmd_flag_none, NULL } { NULL, NULL, cli_cmd_flag_none, NULL }
}; };

View file

@ -1,6 +1,6 @@
/* /*
* wpa_supplicant - Internal definitions * wpa_supplicant - Internal definitions
* Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi> * Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@ -194,6 +194,7 @@ struct wpa_global {
struct wpas_dbus_priv *dbus; struct wpas_dbus_priv *dbus;
void **drv_priv; void **drv_priv;
size_t drv_count; size_t drv_count;
struct os_time suspend_time;
}; };