diff --git a/cfg80211-mac80211-disconnect-on-suspend.patch b/cfg80211-mac80211-disconnect-on-suspend.patch new file mode 100644 index 000000000..940ac2cc4 --- /dev/null +++ b/cfg80211-mac80211-disconnect-on-suspend.patch @@ -0,0 +1,227 @@ +From ad3a7b84092599eef931bce4de54e18e47612f9f Mon Sep 17 00:00:00 2001 +From: Stanislaw Gruszka +Date: Thu, 28 Feb 2013 09:55:25 +0000 +Subject: [PATCH] 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 +--- + net/mac80211/pm.c | 2 +- + net/wireless/core.c | 73 +++++++++++++++++++++++++++---------------------- + net/wireless/core.h | 3 ++ + net/wireless/rdev-ops.h | 7 +++-- + net/wireless/sysfs.c | 25 +++++++++++++---- + 5 files changed, 69 insertions(+), 41 deletions(-) + +diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c +index 79a48f3..ce4f973 100644 +--- a/net/mac80211/pm.c ++++ b/net/mac80211/pm.c +@@ -92,7 +92,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) { + cancel_work_sync(&sdata->work); +diff --git a/net/wireless/core.c b/net/wireless/core.c +index b677eab..66cc98d 100644 +--- a/net/wireless/core.c ++++ b/net/wireless/core.c +@@ -806,6 +806,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) +@@ -874,38 +914,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 3563097..49d79d9 100644 +--- a/net/wireless/core.h ++++ b/net/wireless/core.h +@@ -481,6 +481,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 6c0c819..08e4145 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 1f6f01e..a6a108b 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; + } +-- +1.8.1.2 + diff --git a/kernel.spec b/kernel.spec index 27ee3d054..db65fafc3 100644 --- a/kernel.spec +++ b/kernel.spec @@ -803,6 +803,10 @@ Patch24108: signal-always-clear-sa_restorer-on-execve.patch #CVE-2013-0913 rhbz 920471 920529 Patch24109: drm-i915-bounds-check-execbuffer-relocation-count.patch +#rhbz 865863 +Patch24110: mac80211-Fix-crash-due-to-un-canceled-work-items.patch +Patch24111: cfg80211-mac80211-disconnect-on-suspend.patch + # AMD64 EDAC reports a wrong dimm count with new API. Fix it Patch25000: amd64_edac_fix_rank_count.patch @@ -1560,6 +1564,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 mac80211-Fix-crash-due-to-un-canceled-work-items.patch +ApplyPatch cfg80211-mac80211-disconnect-on-suspend.patch # END OF PATCH APPLICATIONS @@ -2419,6 +2426,7 @@ fi # || || %changelog * Tue Mar 12 2013 Josh Boyer +- Add patches to fix cfg80211 issues with suspend (rhbz 856863) - Add patch to fix Cypress trackpad on XPS 12 machines (rhbz 912166) - CVE-2013-0913 drm/i915: head writing overflow (rhbz 920471 920529) - CVE-2013-0914 sa_restorer information leak (rhbz 920499 920510) diff --git a/mac80211-Fix-crash-due-to-un-canceled-work-items.patch b/mac80211-Fix-crash-due-to-un-canceled-work-items.patch new file mode 100644 index 000000000..71fd5963b --- /dev/null +++ b/mac80211-Fix-crash-due-to-un-canceled-work-items.patch @@ -0,0 +1,67 @@ +From 499218595a2e8296b7492af32fcca141b7b8184a Mon Sep 17 00:00:00 2001 +From: Ben Greear +Date: Wed, 20 Feb 2013 09:41:09 -0800 +Subject: [PATCH] mac80211: Fix crash due to un-canceled work-items + +Some mlme work structs are not cancelled on disassociation +nor interface deletion, which leads to them running after +the memory has been freed + +There is not a clean way to cancel these in the disassociation +logic because they must be canceled outside of the ifmgd->mtx +lock, so just cancel them in mgd_stop logic that tears down +the station. + +This fixes the crashes we see in 3.7.9+. The crash stack +trace itself isn't so helpful, but this warning gives +more useful info: + +WARNING: at /home/greearb/git/linux-3.7.dev.y/lib/debugobjects.c:261 debug_print_object+0x7c/0x8d() +ODEBUG: free active (active state 0) object type: work_struct hint: ieee80211_sta_monitor_work+0x0/0x14 [mac80211] +Modules linked in: [...] +Pid: 14743, comm: iw Tainted: G C O 3.7.9+ #11 +Call Trace: + [] warn_slowpath_common+0x80/0x98 + [] warn_slowpath_fmt+0x41/0x43 + [] debug_print_object+0x7c/0x8d + [] debug_check_no_obj_freed+0x95/0x1c3 + [] slab_free_hook+0x70/0x79 + [] kfree+0x62/0xb7 + [] netdev_release+0x39/0x3e + [] device_release+0x52/0x8a + [] kobject_release+0x121/0x158 + [] kobject_put+0x4c/0x50 + [] netdev_run_todo+0x25c/0x27e + +Cc: stable@vger.kernel.org +Signed-off-by: Ben Greear +Signed-off-by: Johannes Berg +--- + net/mac80211/mlme.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c +index 6044c6d..b756d29 100644 +--- a/net/mac80211/mlme.c ++++ b/net/mac80211/mlme.c +@@ -4319,6 +4319,17 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata) + { + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + ++ /* ++ * Make sure some work items will not run after this, ++ * they will not do anything but might not have been ++ * cancelled when disconnecting. ++ */ ++ cancel_work_sync(&ifmgd->monitor_work); ++ cancel_work_sync(&ifmgd->beacon_connection_loss_work); ++ cancel_work_sync(&ifmgd->request_smps_work); ++ cancel_work_sync(&ifmgd->csa_connection_drop_work); ++ cancel_work_sync(&ifmgd->chswitch_work); ++ + mutex_lock(&ifmgd->mtx); + if (ifmgd->assoc_data) + ieee80211_destroy_assoc_data(sdata, false); +-- +1.8.1.2 +