ssb: sync with wireless-2.6
[openwrt.git] / package / mac80211 / patches / 100-cfg80211_fix_scan_check_again.patch
1 Subject: cfg80211: check lost scans later, fix bug
2
3 When we lose a scan, cfg80211 tries to clean up after
4 the driver. However, it currently does this too early,
5 it does this in GOING_DOWN already instead of DOWN, so
6 it may happen with mac80211. Besides fixing this, also
7 make it more robust by leaking the scan request so if
8 the driver later actually finishes the scan, it won't
9 crash. Also check in ___cfg80211_scan_done whether a
10 scan request is still pending and exit if not.
11
12 Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
13 ---
14  net/wireless/core.c |    4 +++-
15  net/wireless/core.h |    2 +-
16  net/wireless/scan.c |   19 ++++++++++++++++---
17  3 files changed, 20 insertions(+), 5 deletions(-)
18
19 --- a/net/wireless/core.c
20 +++ b/net/wireless/core.c
21 @@ -664,7 +664,7 @@ static void wdev_cleanup_work(struct wor
22  
23         if (WARN_ON(rdev->scan_req && rdev->scan_req->dev == wdev->netdev)) {
24                 rdev->scan_req->aborted = true;
25 -               ___cfg80211_scan_done(rdev);
26 +               ___cfg80211_scan_done(rdev, true);
27         }
28  
29         cfg80211_unlock_rdev(rdev);
30 @@ -755,6 +755,8 @@ static int cfg80211_netdev_notifier_call
31                 default:
32                         break;
33                 }
34 +               break;
35 +       case NETDEV_DOWN:
36                 dev_hold(dev);
37                 schedule_work(&wdev->cleanup_work);
38                 break;
39 --- a/net/wireless/core.h
40 +++ b/net/wireless/core.h
41 @@ -374,7 +374,7 @@ void cfg80211_sme_scan_done(struct net_d
42  void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len);
43  void cfg80211_sme_disassoc(struct net_device *dev, int idx);
44  void __cfg80211_scan_done(struct work_struct *wk);
45 -void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev);
46 +void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak);
47  void cfg80211_upload_connect_keys(struct wireless_dev *wdev);
48  
49  struct ieee80211_channel *
50 --- a/net/wireless/scan.c
51 +++ b/net/wireless/scan.c
52 @@ -18,7 +18,7 @@
53  
54  #define IEEE80211_SCAN_RESULT_EXPIRE   (15 * HZ)
55  
56 -void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev)
57 +void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
58  {
59         struct cfg80211_scan_request *request;
60         struct net_device *dev;
61 @@ -28,6 +28,9 @@ void ___cfg80211_scan_done(struct cfg802
62  
63         request = rdev->scan_req;
64  
65 +       if (!request)
66 +               return;
67 +
68         dev = request->dev;
69  
70         /*
71 @@ -53,7 +56,17 @@ void ___cfg80211_scan_done(struct cfg802
72         dev_put(dev);
73  
74         rdev->scan_req = NULL;
75 -       kfree(request);
76 +
77 +       /*
78 +        * OK. If this is invoked with "leak" then we can't
79 +        * free this ... but we've cleaned it up anyway. The
80 +        * driver failed to call the scan_done callback, so
81 +        * all bets are off, it might still be trying to use
82 +        * the scan request or not ... if it accesses the dev
83 +        * in there (it shouldn't anyway) then it may crash.
84 +        */
85 +       if (!leak)
86 +               kfree(request);
87  }
88  
89  void __cfg80211_scan_done(struct work_struct *wk)
90 @@ -64,7 +77,7 @@ void __cfg80211_scan_done(struct work_st
91                             scan_done_wk);
92  
93         cfg80211_lock_rdev(rdev);
94 -       ___cfg80211_scan_done(rdev);
95 +       ___cfg80211_scan_done(rdev, false);
96         cfg80211_unlock_rdev(rdev);
97  }
98