aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2007-09-17 01:29:23 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-10 19:52:57 -0400
commit4150c57212ad134765dd78c654a4b9906252b66d (patch)
treec37ab7a3f75532a623ed00339782d769514422d2 /net/mac80211
parent070ac3a2651e3c1c4d277c5f1981517427c386a7 (diff)
[PATCH] mac80211: revamp interface and filter configuration
Drivers are currently supposed to keep track of monitor interfaces if they allow so-called "hard" monitor, and they are also supposed to keep track of multicast etc. This patch changes that, replaces the set_multicast_list() callback with a new configure_filter() callback that takes filter flags (FIF_*) instead of interface flags (IFF_*). For a driver, this means it should open the filter as much as necessary to get all frames requested by the filter flags. Accordingly, the filter flags are named "positively", e.g. FIF_ALLMULTI. Multicast filtering is a bit special in that drivers that have no multicast address filters need to allow multicast frames through when either the FIF_ALLMULTI flag is set or when the mc_count value is positive. At the same time, drivers are no longer notified about monitor interfaces at all, this means they now need to implement the start() and stop() callbacks and the new change_filter_flags() callback. Also, the start()/stop() ordering changed, start() is now called *before* any add_interface() as it really should be, and stop() after any remove_interface(). The patch also changes the behaviour of setting the bssid to multicast for scanning when IEEE80211_HW_NO_PROBE_FILTERING is set; the IEEE80211_HW_NO_PROBE_FILTERING flag is removed and the filter flag FIF_BCN_PRBRESP_PROMISC introduced. This is a lot more efficient for hardware like b43 that supports it and other hardware can still set the BSSID to all-ones. Driver modifications by Johannes Berg (b43 & iwlwifi), Michael Wu (rtl8187, adm8211, and p54), Larry Finger (b43legacy), and Ivo van Doorn (rt2x00). Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: Michael Wu <flamingice@sourmilk.net> Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net> Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/debugfs_netdev.c16
-rw-r--r--net/mac80211/ieee80211.c360
-rw-r--r--net/mac80211/ieee80211_i.h3
-rw-r--r--net/mac80211/ieee80211_sta.c26
-rw-r--r--net/mac80211/rx.c4
5 files changed, 162 insertions, 247 deletions
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index 9efb84c47bb0..c9948fa58e08 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -165,20 +165,6 @@ IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC);
165/* VLAN attributes */ 165/* VLAN attributes */
166IEEE80211_IF_FILE(vlan_id, u.vlan.id, DEC); 166IEEE80211_IF_FILE(vlan_id, u.vlan.id, DEC);
167 167
168/* MONITOR attributes */
169static ssize_t ieee80211_if_fmt_mode(
170 const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
171{
172 struct ieee80211_local *local = sdata->local;
173
174 return scnprintf(buf, buflen, "%s\n",
175 ((local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER) ||
176 local->open_count == local->monitors) ?
177 "hard" : "soft");
178}
179__IEEE80211_IF_FILE(mode);
180
181
182#define DEBUGFS_ADD(name, type)\ 168#define DEBUGFS_ADD(name, type)\
183 sdata->debugfs.type.name = debugfs_create_file(#name, 0444,\ 169 sdata->debugfs.type.name = debugfs_create_file(#name, 0444,\
184 sdata->debugfsdir, sdata, &name##_ops); 170 sdata->debugfsdir, sdata, &name##_ops);
@@ -242,7 +228,6 @@ static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
242 228
243static void add_monitor_files(struct ieee80211_sub_if_data *sdata) 229static void add_monitor_files(struct ieee80211_sub_if_data *sdata)
244{ 230{
245 DEBUGFS_ADD(mode, monitor);
246} 231}
247 232
248static void add_files(struct ieee80211_sub_if_data *sdata) 233static void add_files(struct ieee80211_sub_if_data *sdata)
@@ -337,7 +322,6 @@ static void del_vlan_files(struct ieee80211_sub_if_data *sdata)
337 322
338static void del_monitor_files(struct ieee80211_sub_if_data *sdata) 323static void del_monitor_files(struct ieee80211_sub_if_data *sdata)
339{ 324{
340 DEBUGFS_DEL(mode, monitor);
341} 325}
342 326
343static void del_files(struct ieee80211_sub_if_data *sdata, int type) 327static void del_files(struct ieee80211_sub_if_data *sdata, int type)
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c
index 57ec8880bb1a..319ec2a1d84f 100644
--- a/net/mac80211/ieee80211.c
+++ b/net/mac80211/ieee80211.c
@@ -53,6 +53,38 @@ static int header_parse_80211(const struct sk_buff *skb, unsigned char *haddr)
53 return ETH_ALEN; 53 return ETH_ALEN;
54} 54}
55 55
56/* must be called under mdev tx lock */
57static void ieee80211_configure_filter(struct ieee80211_local *local)
58{
59 unsigned int changed_flags;
60 unsigned int new_flags = 0;
61
62 if (local->iff_promiscs)
63 new_flags |= FIF_PROMISC_IN_BSS;
64
65 if (local->iff_allmultis)
66 new_flags |= FIF_ALLMULTI;
67
68 if (local->monitors)
69 new_flags |= FIF_CONTROL |
70 FIF_OTHER_BSS |
71 FIF_BCN_PRBRESP_PROMISC;
72
73 changed_flags = local->filter_flags ^ new_flags;
74
75 /* be a bit nasty */
76 new_flags |= (1<<31);
77
78 local->ops->configure_filter(local_to_hw(local),
79 changed_flags, &new_flags,
80 local->mdev->mc_count,
81 local->mdev->mc_list);
82
83 WARN_ON(new_flags & (1<<31));
84
85 local->filter_flags = new_flags & ~(1<<31);
86}
87
56/* master interface */ 88/* master interface */
57 89
58static int ieee80211_master_open(struct net_device *dev) 90static int ieee80211_master_open(struct net_device *dev)
@@ -86,6 +118,13 @@ static int ieee80211_master_stop(struct net_device *dev)
86 return 0; 118 return 0;
87} 119}
88 120
121static void ieee80211_master_set_multicast_list(struct net_device *dev)
122{
123 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
124
125 ieee80211_configure_filter(local);
126}
127
89/* management interface */ 128/* management interface */
90 129
91static void 130static void
@@ -267,49 +306,6 @@ static inline int identical_mac_addr_allowed(int type1, int type2)
267 type2 == IEEE80211_IF_TYPE_VLAN))); 306 type2 == IEEE80211_IF_TYPE_VLAN)));
268} 307}
269 308
270/* Check if running monitor interfaces should go to a "soft monitor" mode
271 * and switch them if necessary. */
272static inline void ieee80211_start_soft_monitor(struct ieee80211_local *local)
273{
274 struct ieee80211_if_init_conf conf;
275
276 if (local->open_count && local->open_count == local->monitors &&
277 !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER) &&
278 local->ops->remove_interface) {
279 conf.if_id = -1;
280 conf.type = IEEE80211_IF_TYPE_MNTR;
281 conf.mac_addr = NULL;
282 local->ops->remove_interface(local_to_hw(local), &conf);
283 }
284}
285
286/* Check if running monitor interfaces should go to a "hard monitor" mode
287 * and switch them if necessary. */
288static void ieee80211_start_hard_monitor(struct ieee80211_local *local)
289{
290 struct ieee80211_if_init_conf conf;
291
292 if (local->open_count && local->open_count == local->monitors &&
293 !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) {
294 conf.if_id = -1;
295 conf.type = IEEE80211_IF_TYPE_MNTR;
296 conf.mac_addr = NULL;
297 local->ops->add_interface(local_to_hw(local), &conf);
298 }
299}
300
301static void ieee80211_if_open(struct net_device *dev)
302{
303 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
304
305 switch (sdata->type) {
306 case IEEE80211_IF_TYPE_STA:
307 case IEEE80211_IF_TYPE_IBSS:
308 sdata->u.sta.flags &= ~IEEE80211_STA_PREV_BSSID_SET;
309 break;
310 }
311}
312
313static int ieee80211_open(struct net_device *dev) 309static int ieee80211_open(struct net_device *dev)
314{ 310{
315 struct ieee80211_sub_if_data *sdata, *nsdata; 311 struct ieee80211_sub_if_data *sdata, *nsdata;
@@ -335,84 +331,96 @@ static int ieee80211_open(struct net_device *dev)
335 is_zero_ether_addr(sdata->u.wds.remote_addr)) 331 is_zero_ether_addr(sdata->u.wds.remote_addr))
336 return -ENOLINK; 332 return -ENOLINK;
337 333
338 if (sdata->type == IEEE80211_IF_TYPE_MNTR && local->open_count &&
339 !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) {
340 /* run the interface in a "soft monitor" mode */
341 local->monitors++;
342 local->open_count++;
343 local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
344 return 0;
345 }
346 ieee80211_if_open(dev);
347 ieee80211_start_soft_monitor(local);
348
349 conf.if_id = dev->ifindex;
350 conf.type = sdata->type;
351 if (sdata->type == IEEE80211_IF_TYPE_MNTR)
352 conf.mac_addr = NULL;
353 else
354 conf.mac_addr = dev->dev_addr;
355 res = local->ops->add_interface(local_to_hw(local), &conf);
356 if (res) {
357 if (sdata->type == IEEE80211_IF_TYPE_MNTR)
358 ieee80211_start_hard_monitor(local);
359 return res;
360 }
361
362 if (local->open_count == 0) { 334 if (local->open_count == 0) {
363 res = 0; 335 res = 0;
364 tasklet_enable(&local->tx_pending_tasklet); 336 if (local->ops->start)
365 tasklet_enable(&local->tasklet); 337 res = local->ops->start(local_to_hw(local));
366 if (local->ops->open) 338 if (res)
367 res = local->ops->open(local_to_hw(local));
368 if (res == 0) {
369 res = dev_open(local->mdev);
370 if (res) {
371 if (local->ops->stop)
372 local->ops->stop(local_to_hw(local));
373 } else {
374 res = ieee80211_hw_config(local);
375 if (res && local->ops->stop)
376 local->ops->stop(local_to_hw(local));
377 else if (!res && local->apdev)
378 dev_open(local->apdev);
379 }
380 }
381 if (res) {
382 if (local->ops->remove_interface)
383 local->ops->remove_interface(local_to_hw(local),
384 &conf);
385 return res; 339 return res;
386 }
387 } 340 }
388 local->open_count++;
389 341
390 if (sdata->type == IEEE80211_IF_TYPE_MNTR) { 342 switch (sdata->type) {
343 case IEEE80211_IF_TYPE_MNTR:
344 /* must be before the call to ieee80211_configure_filter */
391 local->monitors++; 345 local->monitors++;
392 local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP; 346 if (local->monitors == 1) {
393 } else { 347 netif_tx_lock_bh(local->mdev);
348 ieee80211_configure_filter(local);
349 netif_tx_unlock_bh(local->mdev);
350
351 local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
352 ieee80211_hw_config(local);
353 }
354 break;
355 case IEEE80211_IF_TYPE_STA:
356 case IEEE80211_IF_TYPE_IBSS:
357 sdata->u.sta.flags &= ~IEEE80211_STA_PREV_BSSID_SET;
358 /* fall through */
359 default:
360 conf.if_id = dev->ifindex;
361 conf.type = sdata->type;
362 conf.mac_addr = dev->dev_addr;
363 res = local->ops->add_interface(local_to_hw(local), &conf);
364 if (res && !local->open_count && local->ops->stop)
365 local->ops->stop(local_to_hw(local));
366 if (res)
367 return res;
368
394 ieee80211_if_config(dev); 369 ieee80211_if_config(dev);
395 ieee80211_reset_erp_info(dev); 370 ieee80211_reset_erp_info(dev);
396 ieee80211_enable_keys(sdata); 371 ieee80211_enable_keys(sdata);
372
373 if (sdata->type == IEEE80211_IF_TYPE_STA &&
374 !local->user_space_mlme)
375 netif_carrier_off(dev);
376 else
377 netif_carrier_on(dev);
397 } 378 }
398 379
399 if (sdata->type == IEEE80211_IF_TYPE_STA && 380 if (local->open_count == 0) {
400 !local->user_space_mlme) 381 res = dev_open(local->mdev);
401 netif_carrier_off(dev); 382 WARN_ON(res);
402 else 383 if (local->apdev) {
403 netif_carrier_on(dev); 384 res = dev_open(local->apdev);
385 WARN_ON(res);
386 }
387 tasklet_enable(&local->tx_pending_tasklet);
388 tasklet_enable(&local->tasklet);
389 }
390
391 local->open_count++;
404 392
405 netif_start_queue(dev); 393 netif_start_queue(dev);
394
406 return 0; 395 return 0;
407} 396}
408 397
409static void ieee80211_if_shutdown(struct net_device *dev) 398static int ieee80211_stop(struct net_device *dev)
410{ 399{
400 struct ieee80211_sub_if_data *sdata;
411 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); 401 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
412 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 402 struct ieee80211_if_init_conf conf;
403
404 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
405
406 netif_stop_queue(dev);
407
408 dev_mc_unsync(local->mdev, dev);
409
410 local->open_count--;
413 411
414 ASSERT_RTNL();
415 switch (sdata->type) { 412 switch (sdata->type) {
413 case IEEE80211_IF_TYPE_MNTR:
414 local->monitors--;
415 if (local->monitors == 0) {
416 netif_tx_lock_bh(local->mdev);
417 ieee80211_configure_filter(local);
418 netif_tx_unlock_bh(local->mdev);
419
420 local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
421 ieee80211_hw_config(local);
422 }
423 break;
416 case IEEE80211_IF_TYPE_STA: 424 case IEEE80211_IF_TYPE_STA:
417 case IEEE80211_IF_TYPE_IBSS: 425 case IEEE80211_IF_TYPE_IBSS:
418 sdata->u.sta.state = IEEE80211_DISABLED; 426 sdata->u.sta.state = IEEE80211_DISABLED;
@@ -433,116 +441,61 @@ static void ieee80211_if_shutdown(struct net_device *dev)
433 cancel_delayed_work(&local->scan_work); 441 cancel_delayed_work(&local->scan_work);
434 } 442 }
435 flush_workqueue(local->hw.workqueue); 443 flush_workqueue(local->hw.workqueue);
436 break; 444 /* fall through */
437 } 445 default:
438} 446 conf.if_id = dev->ifindex;
439 447 conf.type = sdata->type;
440static int ieee80211_stop(struct net_device *dev) 448 conf.mac_addr = dev->dev_addr;
441{
442 struct ieee80211_sub_if_data *sdata;
443 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
444
445 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
446
447 if (sdata->type == IEEE80211_IF_TYPE_MNTR &&
448 local->open_count > 1 &&
449 !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) {
450 /* remove "soft monitor" interface */
451 local->open_count--;
452 local->monitors--;
453 if (!local->monitors)
454 local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP;
455 return 0;
456 }
457
458 netif_stop_queue(dev);
459 ieee80211_if_shutdown(dev);
460
461 if (sdata->type == IEEE80211_IF_TYPE_MNTR) {
462 local->monitors--;
463 if (!local->monitors)
464 local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP;
465 } else {
466 /* disable all keys for as long as this netdev is down */ 449 /* disable all keys for as long as this netdev is down */
467 ieee80211_disable_keys(sdata); 450 ieee80211_disable_keys(sdata);
451 local->ops->remove_interface(local_to_hw(local), &conf);
468 } 452 }
469 453
470 local->open_count--;
471 if (local->open_count == 0) { 454 if (local->open_count == 0) {
472 if (netif_running(local->mdev)) 455 if (netif_running(local->mdev))
473 dev_close(local->mdev); 456 dev_close(local->mdev);
457
474 if (local->apdev) 458 if (local->apdev)
475 dev_close(local->apdev); 459 dev_close(local->apdev);
460
476 if (local->ops->stop) 461 if (local->ops->stop)
477 local->ops->stop(local_to_hw(local)); 462 local->ops->stop(local_to_hw(local));
463
478 tasklet_disable(&local->tx_pending_tasklet); 464 tasklet_disable(&local->tx_pending_tasklet);
479 tasklet_disable(&local->tasklet); 465 tasklet_disable(&local->tasklet);
480 } 466 }
481 if (local->ops->remove_interface) {
482 struct ieee80211_if_init_conf conf;
483
484 conf.if_id = dev->ifindex;
485 conf.type = sdata->type;
486 conf.mac_addr = dev->dev_addr;
487 local->ops->remove_interface(local_to_hw(local), &conf);
488 }
489
490 ieee80211_start_hard_monitor(local);
491 467
492 return 0; 468 return 0;
493} 469}
494 470
495enum netif_tx_lock_class {
496 TX_LOCK_NORMAL,
497 TX_LOCK_MASTER,
498};
499
500static inline void netif_tx_lock_nested(struct net_device *dev, int subclass)
501{
502 spin_lock_nested(&dev->_xmit_lock, subclass);
503 dev->xmit_lock_owner = smp_processor_id();
504}
505
506static void ieee80211_set_multicast_list(struct net_device *dev) 471static void ieee80211_set_multicast_list(struct net_device *dev)
507{ 472{
508 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); 473 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
509 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 474 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
510 unsigned short flags; 475 int allmulti, promisc, sdata_allmulti, sdata_promisc;
511 476
512 netif_tx_lock_nested(local->mdev, TX_LOCK_MASTER); 477 allmulti = !!(dev->flags & IFF_ALLMULTI);
513 if (((dev->flags & IFF_ALLMULTI) != 0) ^ 478 promisc = !!(dev->flags & IFF_PROMISC);
514 ((sdata->flags & IEEE80211_SDATA_ALLMULTI) != 0)) { 479 sdata_allmulti = sdata->flags & IEEE80211_SDATA_ALLMULTI;
515 if (sdata->flags & IEEE80211_SDATA_ALLMULTI) 480 sdata_promisc = sdata->flags & IEEE80211_SDATA_PROMISC;
516 local->iff_allmultis--; 481
517 else 482 if (allmulti != sdata_allmulti) {
483 if (dev->flags & IFF_ALLMULTI)
518 local->iff_allmultis++; 484 local->iff_allmultis++;
485 else
486 local->iff_allmultis--;
519 sdata->flags ^= IEEE80211_SDATA_ALLMULTI; 487 sdata->flags ^= IEEE80211_SDATA_ALLMULTI;
520 } 488 }
521 if (((dev->flags & IFF_PROMISC) != 0) ^ 489
522 ((sdata->flags & IEEE80211_SDATA_PROMISC) != 0)) { 490 if (promisc != sdata_promisc) {
523 if (sdata->flags & IEEE80211_SDATA_PROMISC) 491 if (dev->flags & IFF_PROMISC)
524 local->iff_promiscs--;
525 else
526 local->iff_promiscs++; 492 local->iff_promiscs++;
493 else
494 local->iff_promiscs--;
527 sdata->flags ^= IEEE80211_SDATA_PROMISC; 495 sdata->flags ^= IEEE80211_SDATA_PROMISC;
528 } 496 }
529 if (dev->mc_count != sdata->mc_count) { 497
530 local->mc_count = local->mc_count - sdata->mc_count + 498 dev_mc_sync(local->mdev, dev);
531 dev->mc_count;
532 sdata->mc_count = dev->mc_count;
533 }
534 if (local->ops->set_multicast_list) {
535 flags = local->mdev->flags;
536 if (local->iff_allmultis)
537 flags |= IFF_ALLMULTI;
538 if (local->iff_promiscs)
539 flags |= IFF_PROMISC;
540 read_lock(&local->sub_if_lock);
541 local->ops->set_multicast_list(local_to_hw(local), flags,
542 local->mc_count);
543 read_unlock(&local->sub_if_lock);
544 }
545 netif_tx_unlock(local->mdev);
546} 499}
547 500
548static const struct header_ops ieee80211_header_ops = { 501static const struct header_ops ieee80211_header_ops = {
@@ -612,7 +565,6 @@ static int __ieee80211_if_config(struct net_device *dev,
612 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 565 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
613 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); 566 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
614 struct ieee80211_if_conf conf; 567 struct ieee80211_if_conf conf;
615 static u8 scan_bssid[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
616 568
617 if (!local->ops->config_interface || !netif_running(dev)) 569 if (!local->ops->config_interface || !netif_running(dev))
618 return 0; 570 return 0;
@@ -621,11 +573,7 @@ static int __ieee80211_if_config(struct net_device *dev,
621 conf.type = sdata->type; 573 conf.type = sdata->type;
622 if (sdata->type == IEEE80211_IF_TYPE_STA || 574 if (sdata->type == IEEE80211_IF_TYPE_STA ||
623 sdata->type == IEEE80211_IF_TYPE_IBSS) { 575 sdata->type == IEEE80211_IF_TYPE_IBSS) {
624 if (local->sta_scanning && 576 conf.bssid = sdata->u.sta.bssid;
625 local->scan_dev == dev)
626 conf.bssid = scan_bssid;
627 else
628 conf.bssid = sdata->u.sta.bssid;
629 conf.ssid = sdata->u.sta.ssid; 577 conf.ssid = sdata->u.sta.ssid;
630 conf.ssid_len = sdata->u.sta.ssid_len; 578 conf.ssid_len = sdata->u.sta.ssid_len;
631 conf.generic_elem = sdata->u.sta.extra_ie; 579 conf.generic_elem = sdata->u.sta.extra_ie;
@@ -722,37 +670,6 @@ void ieee80211_reset_erp_info(struct net_device *dev)
722 IEEE80211_ERP_CHANGE_PREAMBLE); 670 IEEE80211_ERP_CHANGE_PREAMBLE);
723} 671}
724 672
725struct dev_mc_list *ieee80211_get_mc_list_item(struct ieee80211_hw *hw,
726 struct dev_mc_list *prev,
727 void **ptr)
728{
729 struct ieee80211_local *local = hw_to_local(hw);
730 struct ieee80211_sub_if_data *sdata = *ptr;
731 struct dev_mc_list *mc;
732
733 if (!prev) {
734 WARN_ON(sdata);
735 sdata = NULL;
736 }
737 if (!prev || !prev->next) {
738 if (sdata)
739 sdata = list_entry(sdata->list.next,
740 struct ieee80211_sub_if_data, list);
741 else
742 sdata = list_entry(local->sub_if_list.next,
743 struct ieee80211_sub_if_data, list);
744 if (&sdata->list != &local->sub_if_list)
745 mc = sdata->dev->mc_list;
746 else
747 mc = NULL;
748 } else
749 mc = prev->next;
750
751 *ptr = sdata;
752 return mc;
753}
754EXPORT_SYMBOL(ieee80211_get_mc_list_item);
755
756void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, 673void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
757 struct sk_buff *skb, 674 struct sk_buff *skb,
758 struct ieee80211_tx_status *status) 675 struct ieee80211_tx_status *status)
@@ -1158,8 +1075,12 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
1158 NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST); 1075 NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST);
1159 1076
1160 BUG_ON(!ops->tx); 1077 BUG_ON(!ops->tx);
1078 BUG_ON(!ops->start);
1079 BUG_ON(!ops->stop);
1161 BUG_ON(!ops->config); 1080 BUG_ON(!ops->config);
1162 BUG_ON(!ops->add_interface); 1081 BUG_ON(!ops->add_interface);
1082 BUG_ON(!ops->remove_interface);
1083 BUG_ON(!ops->configure_filter);
1163 local->ops = ops; 1084 local->ops = ops;
1164 1085
1165 /* for now, mdev needs sub_if_data :/ */ 1086 /* for now, mdev needs sub_if_data :/ */
@@ -1206,6 +1127,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
1206 mdev->stop = ieee80211_master_stop; 1127 mdev->stop = ieee80211_master_stop;
1207 mdev->type = ARPHRD_IEEE80211; 1128 mdev->type = ARPHRD_IEEE80211;
1208 mdev->header_ops = &ieee80211_header_ops; 1129 mdev->header_ops = &ieee80211_header_ops;
1130 mdev->set_multicast_list = ieee80211_master_set_multicast_list;
1209 1131
1210 sdata->type = IEEE80211_IF_TYPE_AP; 1132 sdata->type = IEEE80211_IF_TYPE_AP;
1211 sdata->dev = mdev; 1133 sdata->dev = mdev;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index c3f6f89755b1..74deecd09677 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -297,8 +297,6 @@ struct ieee80211_sub_if_data {
297 struct net_device *dev; 297 struct net_device *dev;
298 struct ieee80211_local *local; 298 struct ieee80211_local *local;
299 299
300 int mc_count;
301
302 unsigned int flags; 300 unsigned int flags;
303 301
304 int drop_unencrypted; 302 int drop_unencrypted;
@@ -411,6 +409,7 @@ struct ieee80211_local {
411 struct net_device *apdev; /* wlan#ap - management frames (hostapd) */ 409 struct net_device *apdev; /* wlan#ap - management frames (hostapd) */
412 int open_count; 410 int open_count;
413 int monitors; 411 int monitors;
412 unsigned int filter_flags; /* FIF_* */
414 struct iw_statistics wstats; 413 struct iw_statistics wstats;
415 u8 wstats_flags; 414 u8 wstats_flags;
416 int tx_headroom; /* required headroom for hardware/radiotap */ 415 int tx_headroom; /* required headroom for hardware/radiotap */
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c
index 3f0a2faf37d4..17455c6a5229 100644
--- a/net/mac80211/ieee80211_sta.c
+++ b/net/mac80211/ieee80211_sta.c
@@ -2662,10 +2662,16 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw)
2662 printk(KERN_DEBUG "%s: failed to restore operational" 2662 printk(KERN_DEBUG "%s: failed to restore operational"
2663 "channel after scan\n", dev->name); 2663 "channel after scan\n", dev->name);
2664 2664
2665 if (!(local->hw.flags & IEEE80211_HW_NO_PROBE_FILTERING) && 2665
2666 ieee80211_if_config(dev)) 2666 netif_tx_lock_bh(local->mdev);
2667 printk(KERN_DEBUG "%s: failed to restore operational" 2667 local->filter_flags &= ~FIF_BCN_PRBRESP_PROMISC;
2668 "BSSID after scan\n", dev->name); 2668 local->ops->configure_filter(local_to_hw(local),
2669 FIF_BCN_PRBRESP_PROMISC,
2670 &local->filter_flags,
2671 local->mdev->mc_count,
2672 local->mdev->mc_list);
2673
2674 netif_tx_unlock_bh(local->mdev);
2669 2675
2670 memset(&wrqu, 0, sizeof(wrqu)); 2676 memset(&wrqu, 0, sizeof(wrqu));
2671 wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); 2677 wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
@@ -2849,10 +2855,14 @@ static int ieee80211_sta_start_scan(struct net_device *dev,
2849 local->scan_channel_idx = 0; 2855 local->scan_channel_idx = 0;
2850 local->scan_dev = dev; 2856 local->scan_dev = dev;
2851 2857
2852 if (!(local->hw.flags & IEEE80211_HW_NO_PROBE_FILTERING) && 2858 netif_tx_lock_bh(local->mdev);
2853 ieee80211_if_config(dev)) 2859 local->filter_flags |= FIF_BCN_PRBRESP_PROMISC;
2854 printk(KERN_DEBUG "%s: failed to set BSSID for scan\n", 2860 local->ops->configure_filter(local_to_hw(local),
2855 dev->name); 2861 FIF_BCN_PRBRESP_PROMISC,
2862 &local->filter_flags,
2863 local->mdev->mc_count,
2864 local->mdev->mc_list);
2865 netif_tx_unlock_bh(local->mdev);
2856 2866
2857 /* TODO: start scan as soon as all nullfunc frames are ACKed */ 2867 /* TODO: start scan as soon as all nullfunc frames are ACKed */
2858 queue_delayed_work(local->hw.workqueue, &local->scan_work, 2868 queue_delayed_work(local->hw.workqueue, &local->scan_work,
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index b5f2e4c25c7e..2535d8d4ce90 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1307,7 +1307,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
1307 } else if (!multicast && 1307 } else if (!multicast &&
1308 compare_ether_addr(sdata->dev->dev_addr, 1308 compare_ether_addr(sdata->dev->dev_addr,
1309 hdr->addr1) != 0) { 1309 hdr->addr1) != 0) {
1310 if (!(sdata->flags & IEEE80211_SDATA_PROMISC)) 1310 if (!(sdata->dev->flags & IFF_PROMISC))
1311 return 0; 1311 return 0;
1312 rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH; 1312 rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH;
1313 } 1313 }
@@ -1322,7 +1322,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
1322 } else if (!multicast && 1322 } else if (!multicast &&
1323 compare_ether_addr(sdata->dev->dev_addr, 1323 compare_ether_addr(sdata->dev->dev_addr,
1324 hdr->addr1) != 0) { 1324 hdr->addr1) != 0) {
1325 if (!(sdata->flags & IEEE80211_SDATA_PROMISC)) 1325 if (!(sdata->dev->flags & IFF_PROMISC))
1326 return 0; 1326 return 0;
1327 rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH; 1327 rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH;
1328 } else if (!rx->sta) 1328 } else if (!rx->sta)