diff options
-rw-r--r-- | include/net/cfg80211.h | 3 | ||||
-rw-r--r-- | include/uapi/linux/nl80211.h | 4 | ||||
-rw-r--r-- | net/wireless/core.c | 2 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 14 | ||||
-rw-r--r-- | net/wireless/scan.c | 66 | ||||
-rw-r--r-- | net/wireless/sme.c | 1 |
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 | */ |
3053 | enum nl80211_feature_flags { | 3054 | enum 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 | */ |
3104 | enum nl80211_scan_flags { | 3107 | enum 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 | } |
375 | EXPORT_SYMBOL(wiphy_new); | 377 | EXPORT_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! */ | ||
51 | static 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 | |||
50 | void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak) | 71 | void ___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); | |||
126 | void __cfg80211_sched_scan_results(struct work_struct *wk) | 154 | void __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! */ | ||
201 | void cfg80211_bss_expire(struct cfg80211_registered_device *dev) | 239 | void 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 | ||
219 | const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len) | 244 | const 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 | ||