From 207ef3fb12b713e9432d0eca81d0632c124ee271 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sat, 27 Feb 2010 18:46:02 +0200 Subject: [PATCH] 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. --- src/drivers/driver.h | 12 +++++++ src/drivers/driver_ndis.c | 4 ++- src/drivers/driver_nl80211.c | 11 +++++++ wpa_supplicant/ctrl_iface.c | 10 +++++- wpa_supplicant/driver_i.h | 12 +++++++ wpa_supplicant/examples/60_wpa_supplicant | 17 ++++++++++ wpa_supplicant/notify.c | 38 ++++++++++++++++++++++- wpa_supplicant/notify.h | 4 ++- wpa_supplicant/scan.c | 4 +++ wpa_supplicant/wpa_cli.c | 16 ++++++++++ wpa_supplicant/wpa_supplicant_i.h | 3 +- 11 files changed, 126 insertions(+), 5 deletions(-) create mode 100755 wpa_supplicant/examples/60_wpa_supplicant diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 51e189852..04125869e 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -1731,6 +1731,18 @@ struct wpa_driver_ops { * normal station operations like scanning to be completed. */ 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); }; diff --git a/src/drivers/driver_ndis.c b/src/drivers/driver_ndis.c index 29597a682..6f284523b 100644 --- a/src/drivers/driver_ndis.c +++ b/src/drivers/driver_ndis.c @@ -3272,5 +3272,7 @@ const struct wpa_driver_ops wpa_driver_ndis_ops = { NULL /* cancel_remain_on_channel */, NULL /* probe_req_report */, NULL /* disable_11b_rates */, - NULL /* deinit_ap */ + NULL /* deinit_ap */, + NULL /* suspend */, + NULL /* resume */ }; diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index aff6b81d5..6c2949d3a 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -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 = { .name = "nl80211", .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, .disable_11b_rates = wpa_driver_nl80211_disable_11b_rates, .deinit_ap = wpa_driver_nl80211_deinit_ap, + .resume = wpa_driver_nl80211_resume, }; diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 7242e5ca4..33a1d946e 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -1,6 +1,6 @@ /* * WPA Supplicant / Control interface (shared code for all backends) - * Copyright (c) 2004-2009, Jouni Malinen + * Copyright (c) 2004-2010, Jouni Malinen * * 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 @@ -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_size); #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 { os_memcpy(reply, "UNKNOWN COMMAND\n", 16); reply_len = 16; @@ -2038,6 +2042,10 @@ char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global, global, reply, reply_size); } else if (os_strcmp(buf, "TERMINATE") == 0) { 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 { os_memcpy(reply, "UNKNOWN COMMAND\n", 16); reply_len = 16; diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h index bd312538f..7f64c4c66 100644 --- a/wpa_supplicant/driver_i.h +++ b/wpa_supplicant/driver_i.h @@ -456,4 +456,16 @@ static inline int wpa_drv_deinit_ap(struct wpa_supplicant *wpa_s) 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 */ diff --git a/wpa_supplicant/examples/60_wpa_supplicant b/wpa_supplicant/examples/60_wpa_supplicant new file mode 100755 index 000000000..f570ad305 --- /dev/null +++ b/wpa_supplicant/examples/60_wpa_supplicant @@ -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 diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c index 6a55cdc65..ac65b4f0d 100644 --- a/wpa_supplicant/notify.c +++ b/wpa_supplicant/notify.c @@ -1,6 +1,6 @@ /* * wpa_supplicant - Event notifications - * Copyright (c) 2009, Jouni Malinen + * Copyright (c) 2009-2010, Jouni Malinen * * 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 @@ -22,6 +22,8 @@ #include "dbus/dbus_common.h" #include "dbus/dbus_old.h" #include "dbus/dbus_new.h" +#include "driver_i.h" +#include "scan.h" #include "notify.h" 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); } + + +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); + } +} diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h index 7b1febeea..2e70bdba2 100644 --- a/wpa_supplicant/notify.h +++ b/wpa_supplicant/notify.h @@ -1,6 +1,6 @@ /* * wpa_supplicant - Event notifications - * Copyright (c) 2009, Jouni Malinen + * Copyright (c) 2009-2010, Jouni Malinen * * 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 @@ -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_timestamp_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 */ diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c index 56f062f56..9c61690fd 100644 --- a/wpa_supplicant/scan.c +++ b/wpa_supplicant/scan.c @@ -216,6 +216,7 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) #endif /* CONFIG_WPS */ struct wpa_driver_scan_params params; size_t max_ssids; + enum wpa_states prev_state; if (wpa_s->disconnected && !wpa_s->scan_req) { 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(¶ms, 0, sizeof(params)); + prev_state = wpa_s->wpa_state; if (wpa_s->wpa_state == WPA_DISCONNECTED || wpa_s->wpa_state == WPA_INACTIVE) 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) { 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); } else wpa_s->scan_runs++; diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c index d3b9e1f9c..518afa089 100644 --- a/wpa_supplicant/wpa_cli.c +++ b/wpa_supplicant/wpa_cli.c @@ -1403,6 +1403,18 @@ static int wpa_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc, char *argv[]) #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 { cli_cmd_flag_none = 0x00, cli_cmd_flag_sensitive = 0x01 @@ -1597,6 +1609,10 @@ static struct wpa_cli_cmd wpa_cli_commands[] = { cli_cmd_flag_none, "= get information about all associated stations (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 } }; diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index c96fd3b70..bc565175f 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -1,6 +1,6 @@ /* * wpa_supplicant - Internal definitions - * Copyright (c) 2003-2009, Jouni Malinen + * Copyright (c) 2003-2010, Jouni Malinen * * 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 @@ -194,6 +194,7 @@ struct wpa_global { struct wpas_dbus_priv *dbus; void **drv_priv; size_t drv_count; + struct os_time suspend_time; };