aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/cfg80211.h3
-rw-r--r--include/uapi/linux/nl80211.h4
-rw-r--r--net/wireless/core.c2
-rw-r--r--net/wireless/nl80211.c14
-rw-r--r--net/wireless/scan.c66
-rw-r--r--net/wireless/sme.c1
6 files changed, 66 insertions, 24 deletions
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index d95da8f55f6e..aa0e4a12308c 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1005,6 +1005,7 @@ struct cfg80211_ssid {
1005 * @flags: bit field of flags controlling operation 1005 * @flags: bit field of flags controlling operation
1006 * @rates: bitmap of rates to advertise for each band 1006 * @rates: bitmap of rates to advertise for each band
1007 * @wiphy: the wiphy this was for 1007 * @wiphy: the wiphy this was for
1008 * @scan_start: time (in jiffies) when the scan started
1008 * @wdev: the wireless device to scan for 1009 * @wdev: the wireless device to scan for
1009 * @aborted: (internal) scan request was notified as aborted 1010 * @aborted: (internal) scan request was notified as aborted
1010 * @no_cck: used to send probe requests at non CCK rate in 2GHz band 1011 * @no_cck: used to send probe requests at non CCK rate in 2GHz band
@@ -1023,6 +1024,7 @@ struct cfg80211_scan_request {
1023 1024
1024 /* internal */ 1025 /* internal */
1025 struct wiphy *wiphy; 1026 struct wiphy *wiphy;
1027 unsigned long scan_start;
1026 bool aborted; 1028 bool aborted;
1027 bool no_cck; 1029 bool no_cck;
1028 1030
@@ -1074,6 +1076,7 @@ struct cfg80211_sched_scan_request {
1074 /* internal */ 1076 /* internal */
1075 struct wiphy *wiphy; 1077 struct wiphy *wiphy;
1076 struct net_device *dev; 1078 struct net_device *dev;
1079 unsigned long scan_start;
1077 1080
1078 /* keep last */ 1081 /* keep last */
1079 struct ieee80211_channel *channels[0]; 1082 struct ieee80211_channel *channels[0];
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index c68e15e41321..0e6277a06c29 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -3049,6 +3049,7 @@ enum nl80211_ap_sme_features {
3049 * equals (SAE) with user space SME (NL80211_CMD_AUTHENTICATE) in station 3049 * equals (SAE) with user space SME (NL80211_CMD_AUTHENTICATE) in station
3050 * mode 3050 * mode
3051 * @NL80211_FEATURE_LOW_PRIORITY_SCAN: This driver supports low priority scan 3051 * @NL80211_FEATURE_LOW_PRIORITY_SCAN: This driver supports low priority scan
3052 * @NL80211_FEATURE_SCAN_FLUSH: Scan flush is supported
3052 */ 3053 */
3053enum nl80211_feature_flags { 3054enum nl80211_feature_flags {
3054 NL80211_FEATURE_SK_TX_STATUS = 1 << 0, 3055 NL80211_FEATURE_SK_TX_STATUS = 1 << 0,
@@ -3058,6 +3059,7 @@ enum nl80211_feature_flags {
3058 NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL = 1 << 4, 3059 NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL = 1 << 4,
3059 NL80211_FEATURE_SAE = 1 << 5, 3060 NL80211_FEATURE_SAE = 1 << 5,
3060 NL80211_FEATURE_LOW_PRIORITY_SCAN = 1 << 6, 3061 NL80211_FEATURE_LOW_PRIORITY_SCAN = 1 << 6,
3062 NL80211_FEATURE_SCAN_FLUSH = 1 << 7,
3061}; 3063};
3062 3064
3063/** 3065/**
@@ -3100,9 +3102,11 @@ enum nl80211_connect_failed_reason {
3100 * requests. 3102 * requests.
3101 * 3103 *
3102 * @NL80211_SCAN_FLAG_LOW_PRIORITY: scan request has low priority 3104 * @NL80211_SCAN_FLAG_LOW_PRIORITY: scan request has low priority
3105 * @NL80211_SCAN_FLAG_FLUSH: flush cache before scanning
3103 */ 3106 */
3104enum nl80211_scan_flags { 3107enum nl80211_scan_flags {
3105 NL80211_SCAN_FLAG_LOW_PRIORITY = 1<<0, 3108 NL80211_SCAN_FLAG_LOW_PRIORITY = 1<<0,
3109 NL80211_SCAN_FLAG_FLUSH = 1<<1,
3106}; 3110};
3107 3111
3108#endif /* __LINUX_NL80211_H */ 3112#endif /* __LINUX_NL80211_H */
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 443d4d7deea2..48c2ea4712e9 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -370,6 +370,8 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
370 rdev->wiphy.rts_threshold = (u32) -1; 370 rdev->wiphy.rts_threshold = (u32) -1;
371 rdev->wiphy.coverage_class = 0; 371 rdev->wiphy.coverage_class = 0;
372 372
373 rdev->wiphy.features = NL80211_FEATURE_SCAN_FLUSH;
374
373 return &rdev->wiphy; 375 return &rdev->wiphy;
374} 376}
375EXPORT_SYMBOL(wiphy_new); 377EXPORT_SYMBOL(wiphy_new);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index aee252d65b8f..9e5a7206b0b4 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -4371,8 +4371,10 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
4371 if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) { 4371 if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) {
4372 request->flags = nla_get_u32( 4372 request->flags = nla_get_u32(
4373 info->attrs[NL80211_ATTR_SCAN_FLAGS]); 4373 info->attrs[NL80211_ATTR_SCAN_FLAGS]);
4374 if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) && 4374 if (((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
4375 !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) { 4375 !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) ||
4376 ((request->flags & NL80211_SCAN_FLAG_FLUSH) &&
4377 !(wiphy->features & NL80211_FEATURE_SCAN_FLUSH))) {
4376 err = -EOPNOTSUPP; 4378 err = -EOPNOTSUPP;
4377 goto out_free; 4379 goto out_free;
4378 } 4380 }
@@ -4383,6 +4385,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
4383 4385
4384 request->wdev = wdev; 4386 request->wdev = wdev;
4385 request->wiphy = &rdev->wiphy; 4387 request->wiphy = &rdev->wiphy;
4388 request->scan_start = jiffies;
4386 4389
4387 rdev->scan_req = request; 4390 rdev->scan_req = request;
4388 err = rdev->ops->scan(&rdev->wiphy, request); 4391 err = rdev->ops->scan(&rdev->wiphy, request);
@@ -4612,8 +4615,10 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
4612 if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) { 4615 if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) {
4613 request->flags = nla_get_u32( 4616 request->flags = nla_get_u32(
4614 info->attrs[NL80211_ATTR_SCAN_FLAGS]); 4617 info->attrs[NL80211_ATTR_SCAN_FLAGS]);
4615 if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) && 4618 if (((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
4616 !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) { 4619 !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) ||
4620 ((request->flags & NL80211_SCAN_FLAG_FLUSH) &&
4621 !(wiphy->features & NL80211_FEATURE_SCAN_FLUSH))) {
4617 err = -EOPNOTSUPP; 4622 err = -EOPNOTSUPP;
4618 goto out_free; 4623 goto out_free;
4619 } 4624 }
@@ -4622,6 +4627,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
4622 request->dev = dev; 4627 request->dev = dev;
4623 request->wiphy = &rdev->wiphy; 4628 request->wiphy = &rdev->wiphy;
4624 request->interval = interval; 4629 request->interval = interval;
4630 request->scan_start = jiffies;
4625 4631
4626 err = rdev->ops->sched_scan_start(&rdev->wiphy, dev, request); 4632 err = rdev->ops->sched_scan_start(&rdev->wiphy, dev, request);
4627 if (!err) { 4633 if (!err) {
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 20050965abca..a8d5a9a07e49 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -47,6 +47,27 @@ static void __cfg80211_unlink_bss(struct cfg80211_registered_device *dev,
47 kref_put(&bss->ref, bss_release); 47 kref_put(&bss->ref, bss_release);
48} 48}
49 49
50/* must hold dev->bss_lock! */
51static void __cfg80211_bss_expire(struct cfg80211_registered_device *dev,
52 unsigned long expire_time)
53{
54 struct cfg80211_internal_bss *bss, *tmp;
55 bool expired = false;
56
57 list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) {
58 if (atomic_read(&bss->hold))
59 continue;
60 if (!time_after(expire_time, bss->ts))
61 continue;
62
63 __cfg80211_unlink_bss(dev, bss);
64 expired = true;
65 }
66
67 if (expired)
68 dev->bss_generation++;
69}
70
50void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak) 71void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
51{ 72{
52 struct cfg80211_scan_request *request; 73 struct cfg80211_scan_request *request;
@@ -72,10 +93,17 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
72 if (wdev->netdev) 93 if (wdev->netdev)
73 cfg80211_sme_scan_done(wdev->netdev); 94 cfg80211_sme_scan_done(wdev->netdev);
74 95
75 if (request->aborted) 96 if (request->aborted) {
76 nl80211_send_scan_aborted(rdev, wdev); 97 nl80211_send_scan_aborted(rdev, wdev);
77 else 98 } else {
99 if (request->flags & NL80211_SCAN_FLAG_FLUSH) {
100 /* flush entries from previous scans */
101 spin_lock_bh(&rdev->bss_lock);
102 __cfg80211_bss_expire(rdev, request->scan_start);
103 spin_unlock_bh(&rdev->bss_lock);
104 }
78 nl80211_send_scan_done(rdev, wdev); 105 nl80211_send_scan_done(rdev, wdev);
106 }
79 107
80#ifdef CONFIG_CFG80211_WEXT 108#ifdef CONFIG_CFG80211_WEXT
81 if (wdev->netdev && !request->aborted) { 109 if (wdev->netdev && !request->aborted) {
@@ -126,16 +154,27 @@ EXPORT_SYMBOL(cfg80211_scan_done);
126void __cfg80211_sched_scan_results(struct work_struct *wk) 154void __cfg80211_sched_scan_results(struct work_struct *wk)
127{ 155{
128 struct cfg80211_registered_device *rdev; 156 struct cfg80211_registered_device *rdev;
157 struct cfg80211_sched_scan_request *request;
129 158
130 rdev = container_of(wk, struct cfg80211_registered_device, 159 rdev = container_of(wk, struct cfg80211_registered_device,
131 sched_scan_results_wk); 160 sched_scan_results_wk);
132 161
162 request = rdev->sched_scan_req;
163
133 mutex_lock(&rdev->sched_scan_mtx); 164 mutex_lock(&rdev->sched_scan_mtx);
134 165
135 /* we don't have sched_scan_req anymore if the scan is stopping */ 166 /* we don't have sched_scan_req anymore if the scan is stopping */
136 if (rdev->sched_scan_req) 167 if (request) {
137 nl80211_send_sched_scan_results(rdev, 168 if (request->flags & NL80211_SCAN_FLAG_FLUSH) {
138 rdev->sched_scan_req->dev); 169 /* flush entries from previous scans */
170 spin_lock_bh(&rdev->bss_lock);
171 __cfg80211_bss_expire(rdev, request->scan_start);
172 spin_unlock_bh(&rdev->bss_lock);
173 request->scan_start =
174 jiffies + msecs_to_jiffies(request->interval);
175 }
176 nl80211_send_sched_scan_results(rdev, request->dev);
177 }
139 178
140 mutex_unlock(&rdev->sched_scan_mtx); 179 mutex_unlock(&rdev->sched_scan_mtx);
141} 180}
@@ -197,23 +236,9 @@ void cfg80211_bss_age(struct cfg80211_registered_device *dev,
197 } 236 }
198} 237}
199 238
200/* must hold dev->bss_lock! */
201void cfg80211_bss_expire(struct cfg80211_registered_device *dev) 239void cfg80211_bss_expire(struct cfg80211_registered_device *dev)
202{ 240{
203 struct cfg80211_internal_bss *bss, *tmp; 241 __cfg80211_bss_expire(dev, jiffies - IEEE80211_SCAN_RESULT_EXPIRE);
204 bool expired = false;
205
206 list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) {
207 if (atomic_read(&bss->hold))
208 continue;
209 if (!time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE))
210 continue;
211 __cfg80211_unlink_bss(dev, bss);
212 expired = true;
213 }
214
215 if (expired)
216 dev->bss_generation++;
217} 242}
218 243
219const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len) 244const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len)
@@ -962,6 +987,7 @@ int cfg80211_wext_siwscan(struct net_device *dev,
962 creq->ssids = (void *)&creq->channels[n_channels]; 987 creq->ssids = (void *)&creq->channels[n_channels];
963 creq->n_channels = n_channels; 988 creq->n_channels = n_channels;
964 creq->n_ssids = 1; 989 creq->n_ssids = 1;
990 creq->scan_start = jiffies;
965 991
966 /* translate "Scan on frequencies" request */ 992 /* translate "Scan on frequencies" request */
967 i = 0; 993 i = 0;
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 055d59643616..07d717eb9e2a 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -138,6 +138,7 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)
138 138
139 request->wdev = wdev; 139 request->wdev = wdev;
140 request->wiphy = &rdev->wiphy; 140 request->wiphy = &rdev->wiphy;
141 request->scan_start = jiffies;
141 142
142 rdev->scan_req = request; 143 rdev->scan_req = request;
143 144