diff --git a/cfg80211-mac80211-disconnect-on-suspend.patch b/cfg80211-mac80211-disconnect-on-suspend.patch new file mode 100644 index 000000000..92ab492ce --- /dev/null +++ b/cfg80211-mac80211-disconnect-on-suspend.patch @@ -0,0 +1,219 @@ +From 8125696991194aacb1173b6e8196d19098b44e17 Mon Sep 17 00:00:00 2001 +From: Stanislaw Gruszka +Date: Thu, 28 Feb 2013 09:55:25 +0000 +Subject: cfg80211/mac80211: disconnect on suspend + +If possible that after suspend, cfg80211 will receive request to +disconnect what require action on interface that was removed during +suspend. + +Problem can manifest itself by various warnings similar to below one: + +WARNING: at net/mac80211/driver-ops.h:12 ieee80211_bss_info_change_notify+0x2f9/0x300 [mac80211]() +wlan0: Failed check-sdata-in-driver check, flags: 0x4 +Call Trace: + [] warn_slowpath_fmt+0x33/0x40 + [] ieee80211_bss_info_change_notify+0x2f9/0x300 [mac80211] + [] ieee80211_recalc_ps_vif+0x2a/0x30 [mac80211] + [] ieee80211_set_disassoc+0xf6/0x500 [mac80211] + [] ieee80211_mgd_deauth+0x1f1/0x280 [mac80211] + [] ieee80211_deauth+0x16/0x20 [mac80211] + [] cfg80211_mlme_down+0x70/0xc0 [cfg80211] + [] __cfg80211_disconnect+0x1b1/0x1d0 [cfg80211] + +To fix the problem disconnect from any associated network before +suspend. User space is responsible to establish connection again +after resume. This basically need to be done by user space anyway, +because associated stations can go away during suspend (for example +NetworkManager disconnects on suspend and connect on resume by default). + +Patch also handle situation when driver refuse to suspend with wowlan +configured and try to suspend again without it. + +Signed-off-by: Stanislaw Gruszka +Signed-off-by: Johannes Berg +--- +diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c +index d0275f3..4d105c7 100644 +--- a/net/mac80211/pm.c ++++ b/net/mac80211/pm.c +@@ -93,7 +93,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) + return err; + } else if (err > 0) { + WARN_ON(err != 1); +- local->wowlan = false; ++ return err; + } else { + list_for_each_entry(sdata, &local->interfaces, list) + if (ieee80211_sdata_running(sdata)) +diff --git a/net/wireless/core.c b/net/wireless/core.c +index ea4155f..f382cae 100644 +--- a/net/wireless/core.c ++++ b/net/wireless/core.c +@@ -814,6 +814,46 @@ void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, + rdev->num_running_monitor_ifaces += num; + } + ++void cfg80211_leave(struct cfg80211_registered_device *rdev, ++ struct wireless_dev *wdev) ++{ ++ struct net_device *dev = wdev->netdev; ++ ++ switch (wdev->iftype) { ++ case NL80211_IFTYPE_ADHOC: ++ cfg80211_leave_ibss(rdev, dev, true); ++ break; ++ case NL80211_IFTYPE_P2P_CLIENT: ++ case NL80211_IFTYPE_STATION: ++ mutex_lock(&rdev->sched_scan_mtx); ++ __cfg80211_stop_sched_scan(rdev, false); ++ mutex_unlock(&rdev->sched_scan_mtx); ++ ++ wdev_lock(wdev); ++#ifdef CONFIG_CFG80211_WEXT ++ kfree(wdev->wext.ie); ++ wdev->wext.ie = NULL; ++ wdev->wext.ie_len = 0; ++ wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; ++#endif ++ __cfg80211_disconnect(rdev, dev, ++ WLAN_REASON_DEAUTH_LEAVING, true); ++ cfg80211_mlme_down(rdev, dev); ++ wdev_unlock(wdev); ++ break; ++ case NL80211_IFTYPE_MESH_POINT: ++ cfg80211_leave_mesh(rdev, dev); ++ break; ++ case NL80211_IFTYPE_AP: ++ cfg80211_stop_ap(rdev, dev); ++ break; ++ default: ++ break; ++ } ++ ++ wdev->beacon_interval = 0; ++} ++ + static int cfg80211_netdev_notifier_call(struct notifier_block *nb, + unsigned long state, + void *ndev) +@@ -882,38 +922,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, + dev->priv_flags |= IFF_DONT_BRIDGE; + break; + case NETDEV_GOING_DOWN: +- switch (wdev->iftype) { +- case NL80211_IFTYPE_ADHOC: +- cfg80211_leave_ibss(rdev, dev, true); +- break; +- case NL80211_IFTYPE_P2P_CLIENT: +- case NL80211_IFTYPE_STATION: +- mutex_lock(&rdev->sched_scan_mtx); +- __cfg80211_stop_sched_scan(rdev, false); +- mutex_unlock(&rdev->sched_scan_mtx); +- +- wdev_lock(wdev); +-#ifdef CONFIG_CFG80211_WEXT +- kfree(wdev->wext.ie); +- wdev->wext.ie = NULL; +- wdev->wext.ie_len = 0; +- wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; +-#endif +- __cfg80211_disconnect(rdev, dev, +- WLAN_REASON_DEAUTH_LEAVING, true); +- cfg80211_mlme_down(rdev, dev); +- wdev_unlock(wdev); +- break; +- case NL80211_IFTYPE_MESH_POINT: +- cfg80211_leave_mesh(rdev, dev); +- break; +- case NL80211_IFTYPE_AP: +- cfg80211_stop_ap(rdev, dev); +- break; +- default: +- break; +- } +- wdev->beacon_interval = 0; ++ cfg80211_leave(rdev, wdev); + break; + case NETDEV_DOWN: + cfg80211_update_iface_num(rdev, wdev->iftype, -1); +diff --git a/net/wireless/core.h b/net/wireless/core.h +index 9a2be8d..d5d06fd 100644 +--- a/net/wireless/core.h ++++ b/net/wireless/core.h +@@ -500,6 +500,9 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, + void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, + enum nl80211_iftype iftype, int num); + ++void cfg80211_leave(struct cfg80211_registered_device *rdev, ++ struct wireless_dev *wdev); ++ + #define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10 + + #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS +diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h +index 8c8b26f..d77e1c1 100644 +--- a/net/wireless/rdev-ops.h ++++ b/net/wireless/rdev-ops.h +@@ -6,11 +6,12 @@ + #include "core.h" + #include "trace.h" + +-static inline int rdev_suspend(struct cfg80211_registered_device *rdev) ++static inline int rdev_suspend(struct cfg80211_registered_device *rdev, ++ struct cfg80211_wowlan *wowlan) + { + int ret; +- trace_rdev_suspend(&rdev->wiphy, rdev->wowlan); +- ret = rdev->ops->suspend(&rdev->wiphy, rdev->wowlan); ++ trace_rdev_suspend(&rdev->wiphy, wowlan); ++ ret = rdev->ops->suspend(&rdev->wiphy, wowlan); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; + } +diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c +index 238ee49..8f28b9f 100644 +--- a/net/wireless/sysfs.c ++++ b/net/wireless/sysfs.c +@@ -83,6 +83,14 @@ static int wiphy_uevent(struct device *dev, struct kobj_uevent_env *env) + return 0; + } + ++static void cfg80211_leave_all(struct cfg80211_registered_device *rdev) ++{ ++ struct wireless_dev *wdev; ++ ++ list_for_each_entry(wdev, &rdev->wdev_list, list) ++ cfg80211_leave(rdev, wdev); ++} ++ + static int wiphy_suspend(struct device *dev, pm_message_t state) + { + struct cfg80211_registered_device *rdev = dev_to_rdev(dev); +@@ -90,12 +98,19 @@ static int wiphy_suspend(struct device *dev, pm_message_t state) + + rdev->suspend_at = get_seconds(); + +- if (rdev->ops->suspend) { +- rtnl_lock(); +- if (rdev->wiphy.registered) +- ret = rdev_suspend(rdev); +- rtnl_unlock(); ++ rtnl_lock(); ++ if (rdev->wiphy.registered) { ++ if (!rdev->wowlan) ++ cfg80211_leave_all(rdev); ++ if (rdev->ops->suspend) ++ ret = rdev_suspend(rdev, rdev->wowlan); ++ if (ret == 1) { ++ /* Driver refuse to configure wowlan */ ++ cfg80211_leave_all(rdev); ++ ret = rdev_suspend(rdev, NULL); ++ } + } ++ rtnl_unlock(); + + return ret; + } +-- +cgit v0.9.1 diff --git a/kernel.spec b/kernel.spec index 4b72d1fd1..6bd9e9768 100644 --- a/kernel.spec +++ b/kernel.spec @@ -748,6 +748,9 @@ Patch21270: signal-always-clear-sa_restorer-on-execve.patch #CVE-2013-0913 rhbz 920471 920529 Patch21271: drm-i915-bounds-check-execbuffer-relocation-count.patch +#rhbz 856863 +Patch21273: cfg80211-mac80211-disconnect-on-suspend.patch + Patch22000: weird-root-dentry-name-debug.patch #selinux ptrace child permissions @@ -1454,6 +1457,9 @@ ApplyPatch signal-always-clear-sa_restorer-on-execve.patch #CVE-2013-0913 rhbz 920471 920529 ApplyPatch drm-i915-bounds-check-execbuffer-relocation-count.patch +#rhbz 856863 +ApplyPatch cfg80211-mac80211-disconnect-on-suspend.patch + # END OF PATCH APPLICATIONS %endif @@ -2296,6 +2302,7 @@ fi # || || %changelog * Tue Mar 12 2013 Josh Boyer +- Add patches to fix cfg80211 issues with suspend (rhbz 856863) - CVE-2013-0913 drm/i915: head writing overflow (rhbz 920471 920529) - CVE-2013-0914 sa_restorer information leak (rhbz 920499 920510)