aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/scan.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-07-06 16:19:27 -0400
committerJohannes Berg <johannes.berg@intel.com>2012-07-12 06:10:44 -0400
commitd48b296850f25cb559cb9b907d6d8c09eca3e89d (patch)
treeca2603b4ebfa210dda48c1a311996d826084835e /net/mac80211/scan.c
parent5260a5b2c3524f198ea062fe0a6a4faa724e6a9d (diff)
mac80211: redesign scan RX
Scan receive is rather inefficient when there are multiple virtual interfaces. We iterate all of the virtual interfaces and then notify cfg80211 about each beacon many times. Redesign scan RX to happen before everything else. Then we can also get rid of IEEE80211_RX_IN_SCAN since we don't have to accept frames into the RX handlers for scanning or scheduled scanning any more. Overall, this simplifies the code. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/scan.c')
-rw-r--r--net/mac80211/scan.c57
1 files changed, 23 insertions, 34 deletions
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index a619c1ea9bd5..1a893f3637c5 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -165,52 +165,47 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
165 return bss; 165 return bss;
166} 166}
167 167
168ieee80211_rx_result 168void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb)
169ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
170{ 169{
171 struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); 170 struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
172 struct ieee80211_mgmt *mgmt; 171 struct ieee80211_sub_if_data *sdata1, *sdata2;
172 struct ieee80211_mgmt *mgmt = (void *)skb->data;
173 struct ieee80211_bss *bss; 173 struct ieee80211_bss *bss;
174 u8 *elements; 174 u8 *elements;
175 struct ieee80211_channel *channel; 175 struct ieee80211_channel *channel;
176 size_t baselen; 176 size_t baselen;
177 int freq; 177 int freq;
178 __le16 fc; 178 bool beacon;
179 bool presp, beacon = false;
180 struct ieee802_11_elems elems; 179 struct ieee802_11_elems elems;
181 180
182 if (skb->len < 2) 181 if (skb->len < 24 ||
183 return RX_DROP_UNUSABLE; 182 (!ieee80211_is_probe_resp(mgmt->frame_control) &&
184 183 !ieee80211_is_beacon(mgmt->frame_control)))
185 mgmt = (struct ieee80211_mgmt *) skb->data; 184 return;
186 fc = mgmt->frame_control;
187 185
188 if (ieee80211_is_ctl(fc)) 186 sdata1 = rcu_dereference(local->scan_sdata);
189 return RX_CONTINUE; 187 sdata2 = rcu_dereference(local->sched_scan_sdata);
190 188
191 if (skb->len < 24) 189 if (likely(!sdata1 && !sdata2))
192 return RX_CONTINUE; 190 return;
193 191
194 presp = ieee80211_is_probe_resp(fc); 192 if (ieee80211_is_probe_resp(mgmt->frame_control)) {
195 if (presp) {
196 /* ignore ProbeResp to foreign address */ 193 /* ignore ProbeResp to foreign address */
197 if (!ether_addr_equal(mgmt->da, sdata->vif.addr)) 194 if ((!sdata1 || !ether_addr_equal(mgmt->da, sdata1->vif.addr)) &&
198 return RX_DROP_MONITOR; 195 (!sdata2 || !ether_addr_equal(mgmt->da, sdata2->vif.addr)))
196 return;
199 197
200 presp = true;
201 elements = mgmt->u.probe_resp.variable; 198 elements = mgmt->u.probe_resp.variable;
202 baselen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); 199 baselen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
200 beacon = false;
203 } else { 201 } else {
204 beacon = ieee80211_is_beacon(fc);
205 baselen = offsetof(struct ieee80211_mgmt, u.beacon.variable); 202 baselen = offsetof(struct ieee80211_mgmt, u.beacon.variable);
206 elements = mgmt->u.beacon.variable; 203 elements = mgmt->u.beacon.variable;
204 beacon = true;
207 } 205 }
208 206
209 if (!presp && !beacon)
210 return RX_CONTINUE;
211
212 if (baselen > skb->len) 207 if (baselen > skb->len)
213 return RX_DROP_MONITOR; 208 return;
214 209
215 ieee802_11_parse_elems(elements, skb->len - baselen, &elems); 210 ieee802_11_parse_elems(elements, skb->len - baselen, &elems);
216 211
@@ -220,22 +215,16 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
220 else 215 else
221 freq = rx_status->freq; 216 freq = rx_status->freq;
222 217
223 channel = ieee80211_get_channel(sdata->local->hw.wiphy, freq); 218 channel = ieee80211_get_channel(local->hw.wiphy, freq);
224 219
225 if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) 220 if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
226 return RX_DROP_MONITOR; 221 return;
227 222
228 bss = ieee80211_bss_info_update(sdata->local, rx_status, 223 bss = ieee80211_bss_info_update(local, rx_status,
229 mgmt, skb->len, &elems, 224 mgmt, skb->len, &elems,
230 channel, beacon); 225 channel, beacon);
231 if (bss) 226 if (bss)
232 ieee80211_rx_bss_put(sdata->local, bss); 227 ieee80211_rx_bss_put(local, bss);
233
234 if (channel == sdata->local->oper_channel)
235 return RX_CONTINUE;
236
237 dev_kfree_skb(skb);
238 return RX_QUEUED;
239} 228}
240 229
241/* return false if no more work */ 230/* return false if no more work */