aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-08-17 10:16:53 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-08-20 11:35:58 -0400
commit3ac64beecd27400d12cc7afb4108eef26c499f6a (patch)
treeda0220085f68e30fe61ba9b8833dc6311d6dc25e
parentea416a793d2b611f22b42ba094fd2e5bd30fff43 (diff)
mac80211: allow configure_filter callback to sleep
Over time, a whole bunch of drivers have come up with their own scheme to delay the configure_filter operation to a workqueue. To be able to simplify things, allow configure_filter to sleep, and add a new prepare_multicast callback that drivers that need the multicast address list implement. This new callback must be atomic, but most drivers either don't care or just calculate a hash which can be done atomically and then uploaded to the hardware non-atomically. A cursory look suggests that at76c50x-usb, ar9170, mwl8k (which is actually very broken now), rt2x00, wl1251, wl1271 and zd1211 should make use of this new capability. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/adm8211.c42
-rw-r--r--drivers/net/wireless/at76c50x-usb.c7
-rw-r--r--drivers/net/wireless/ath/ar9170/main.c43
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c64
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c3
-rw-r--r--drivers/net/wireless/b43/main.c2
-rw-r--r--drivers/net/wireless/b43legacy/main.c4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h3
-rw-r--r--drivers/net/wireless/libertas_tf/main.c37
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c4
-rw-r--r--drivers/net/wireless/mwl8k.c34
-rw-r--r--drivers/net/wireless/p54/main.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h2
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00mac.c2
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180_dev.c11
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187_dev.c11
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_main.c4
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_main.c4
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c44
-rw-r--r--include/net/mac80211.h21
-rw-r--r--net/mac80211/driver-ops.h24
-rw-r--r--net/mac80211/driver-trace.h36
-rw-r--r--net/mac80211/ieee80211_i.h3
-rw-r--r--net/mac80211/iface.c15
-rw-r--r--net/mac80211/main.c24
-rw-r--r--net/mac80211/scan.c16
-rw-r--r--net/mac80211/util.c2
28 files changed, 297 insertions, 169 deletions
diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c
index 5695911bc602..b80f514877d8 100644
--- a/drivers/net/wireless/adm8211.c
+++ b/drivers/net/wireless/adm8211.c
@@ -1328,16 +1328,39 @@ static void adm8211_bss_info_changed(struct ieee80211_hw *dev,
1328 } 1328 }
1329} 1329}
1330 1330
1331static u64 adm8211_prepare_multicast(struct ieee80211_hw *hw,
1332 int mc_count, struct dev_addr_list *mclist)
1333{
1334 unsigned int bit_nr, i;
1335 u32 mc_filter[2];
1336
1337 mc_filter[1] = mc_filter[0] = 0;
1338
1339 for (i = 0; i < mc_count; i++) {
1340 if (!mclist)
1341 break;
1342 bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
1343
1344 bit_nr &= 0x3F;
1345 mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
1346 mclist = mclist->next;
1347 }
1348
1349 return mc_filter[0] | ((u64)(mc_filter[1]) << 32);
1350}
1351
1331static void adm8211_configure_filter(struct ieee80211_hw *dev, 1352static void adm8211_configure_filter(struct ieee80211_hw *dev,
1332 unsigned int changed_flags, 1353 unsigned int changed_flags,
1333 unsigned int *total_flags, 1354 unsigned int *total_flags,
1334 int mc_count, struct dev_mc_list *mclist) 1355 u64 multicast)
1335{ 1356{
1336 static const u8 bcast[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; 1357 static const u8 bcast[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
1337 struct adm8211_priv *priv = dev->priv; 1358 struct adm8211_priv *priv = dev->priv;
1338 unsigned int bit_nr, new_flags; 1359 unsigned int new_flags;
1339 u32 mc_filter[2]; 1360 u32 mc_filter[2];
1340 int i; 1361
1362 mc_filter[0] = multicast;
1363 mc_filter[1] = multicast >> 32;
1341 1364
1342 new_flags = 0; 1365 new_flags = 0;
1343 1366
@@ -1346,23 +1369,13 @@ static void adm8211_configure_filter(struct ieee80211_hw *dev,
1346 priv->nar |= ADM8211_NAR_PR; 1369 priv->nar |= ADM8211_NAR_PR;
1347 priv->nar &= ~ADM8211_NAR_MM; 1370 priv->nar &= ~ADM8211_NAR_MM;
1348 mc_filter[1] = mc_filter[0] = ~0; 1371 mc_filter[1] = mc_filter[0] = ~0;
1349 } else if ((*total_flags & FIF_ALLMULTI) || (mc_count > 32)) { 1372 } else if (*total_flags & FIF_ALLMULTI || multicast == ~(0ULL)) {
1350 new_flags |= FIF_ALLMULTI; 1373 new_flags |= FIF_ALLMULTI;
1351 priv->nar &= ~ADM8211_NAR_PR; 1374 priv->nar &= ~ADM8211_NAR_PR;
1352 priv->nar |= ADM8211_NAR_MM; 1375 priv->nar |= ADM8211_NAR_MM;
1353 mc_filter[1] = mc_filter[0] = ~0; 1376 mc_filter[1] = mc_filter[0] = ~0;
1354 } else { 1377 } else {
1355 priv->nar &= ~(ADM8211_NAR_MM | ADM8211_NAR_PR); 1378 priv->nar &= ~(ADM8211_NAR_MM | ADM8211_NAR_PR);
1356 mc_filter[1] = mc_filter[0] = 0;
1357 for (i = 0; i < mc_count; i++) {
1358 if (!mclist)
1359 break;
1360 bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
1361
1362 bit_nr &= 0x3F;
1363 mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
1364 mclist = mclist->next;
1365 }
1366 } 1379 }
1367 1380
1368 ADM8211_IDLE_RX(); 1381 ADM8211_IDLE_RX();
@@ -1757,6 +1770,7 @@ static const struct ieee80211_ops adm8211_ops = {
1757 .remove_interface = adm8211_remove_interface, 1770 .remove_interface = adm8211_remove_interface,
1758 .config = adm8211_config, 1771 .config = adm8211_config,
1759 .bss_info_changed = adm8211_bss_info_changed, 1772 .bss_info_changed = adm8211_bss_info_changed,
1773 .prepare_multicast = adm8211_prepare_multicast,
1760 .configure_filter = adm8211_configure_filter, 1774 .configure_filter = adm8211_configure_filter,
1761 .get_stats = adm8211_get_stats, 1775 .get_stats = adm8211_get_stats,
1762 .get_tx_stats = adm8211_get_tx_stats, 1776 .get_tx_stats = adm8211_get_tx_stats,
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c
index 7218dbabad3e..a6e19545ac6a 100644
--- a/drivers/net/wireless/at76c50x-usb.c
+++ b/drivers/net/wireless/at76c50x-usb.c
@@ -1997,15 +1997,14 @@ static void at76_bss_info_changed(struct ieee80211_hw *hw,
1997/* must be atomic */ 1997/* must be atomic */
1998static void at76_configure_filter(struct ieee80211_hw *hw, 1998static void at76_configure_filter(struct ieee80211_hw *hw,
1999 unsigned int changed_flags, 1999 unsigned int changed_flags,
2000 unsigned int *total_flags, int mc_count, 2000 unsigned int *total_flags, u64 multicast)
2001 struct dev_addr_list *mc_list)
2002{ 2001{
2003 struct at76_priv *priv = hw->priv; 2002 struct at76_priv *priv = hw->priv;
2004 int flags; 2003 int flags;
2005 2004
2006 at76_dbg(DBG_MAC80211, "%s(): changed_flags=0x%08x " 2005 at76_dbg(DBG_MAC80211, "%s(): changed_flags=0x%08x "
2007 "total_flags=0x%08x mc_count=%d", 2006 "total_flags=0x%08x",
2008 __func__, changed_flags, *total_flags, mc_count); 2007 __func__, changed_flags, *total_flags);
2009 2008
2010 flags = changed_flags & AT76_SUPPORTED_FILTERS; 2009 flags = changed_flags & AT76_SUPPORTED_FILTERS;
2011 *total_flags = AT76_SUPPORTED_FILTERS; 2010 *total_flags = AT76_SUPPORTED_FILTERS;
diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c
index ea8c9419336d..6a9462e4fd87 100644
--- a/drivers/net/wireless/ath/ar9170/main.c
+++ b/drivers/net/wireless/ath/ar9170/main.c
@@ -2100,10 +2100,29 @@ unlock:
2100 mutex_unlock(&ar->mutex); 2100 mutex_unlock(&ar->mutex);
2101} 2101}
2102 2102
2103static u64 ar9170_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
2104 struct dev_addr_list *mclist)
2105{
2106 u64 mchash;
2107 int i;
2108
2109 /* always get broadcast frames */
2110 mchash = 1ULL << (0xff >> 2);
2111
2112 for (i = 0; i < mc_count; i++) {
2113 if (WARN_ON(!mclist))
2114 break;
2115 mchash |= 1ULL << (mclist->dmi_addr[5] >> 2);
2116 mclist = mclist->next;
2117 }
2118
2119 return mchash;
2120}
2121
2103static void ar9170_op_configure_filter(struct ieee80211_hw *hw, 2122static void ar9170_op_configure_filter(struct ieee80211_hw *hw,
2104 unsigned int changed_flags, 2123 unsigned int changed_flags,
2105 unsigned int *new_flags, 2124 unsigned int *new_flags,
2106 int mc_count, struct dev_mc_list *mclist) 2125 u64 multicast)
2107{ 2126{
2108 struct ar9170 *ar = hw->priv; 2127 struct ar9170 *ar = hw->priv;
2109 2128
@@ -2116,24 +2135,11 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw,
2116 * then checking the error flags, later. 2135 * then checking the error flags, later.
2117 */ 2136 */
2118 2137
2119 if (changed_flags & FIF_ALLMULTI) { 2138 if (changed_flags & FIF_ALLMULTI && *new_flags & FIF_ALLMULTI)
2120 if (*new_flags & FIF_ALLMULTI) { 2139 multicast = ~0ULL;
2121 ar->want_mc_hash = ~0ULL;
2122 } else {
2123 u64 mchash;
2124 int i;
2125
2126 /* always get broadcast frames */
2127 mchash = 1ULL << (0xff >> 2);
2128 2140
2129 for (i = 0; i < mc_count; i++) { 2141 if (multicast != ar->want_mc_hash) {
2130 if (WARN_ON(!mclist)) 2142 ar->want_mc_hash = multicast;
2131 break;
2132 mchash |= 1ULL << (mclist->dmi_addr[5] >> 2);
2133 mclist = mclist->next;
2134 }
2135 ar->want_mc_hash = mchash;
2136 }
2137 set_bit(AR9170_FILTER_CHANGED_MULTICAST, &ar->filter_changed); 2143 set_bit(AR9170_FILTER_CHANGED_MULTICAST, &ar->filter_changed);
2138 } 2144 }
2139 2145
@@ -2543,6 +2549,7 @@ static const struct ieee80211_ops ar9170_ops = {
2543 .add_interface = ar9170_op_add_interface, 2549 .add_interface = ar9170_op_add_interface,
2544 .remove_interface = ar9170_op_remove_interface, 2550 .remove_interface = ar9170_op_remove_interface,
2545 .config = ar9170_op_config, 2551 .config = ar9170_op_config,
2552 .prepare_multicast = ar9170_op_prepare_multicast,
2546 .configure_filter = ar9170_op_configure_filter, 2553 .configure_filter = ar9170_op_configure_filter,
2547 .conf_tx = ar9170_conf_tx, 2554 .conf_tx = ar9170_conf_tx,
2548 .bss_info_changed = ar9170_op_bss_info_changed, 2555 .bss_info_changed = ar9170_op_bss_info_changed,
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 2b3cf39dd4b1..3951b5b13424 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -229,10 +229,12 @@ static int ath5k_add_interface(struct ieee80211_hw *hw,
229static void ath5k_remove_interface(struct ieee80211_hw *hw, 229static void ath5k_remove_interface(struct ieee80211_hw *hw,
230 struct ieee80211_if_init_conf *conf); 230 struct ieee80211_if_init_conf *conf);
231static int ath5k_config(struct ieee80211_hw *hw, u32 changed); 231static int ath5k_config(struct ieee80211_hw *hw, u32 changed);
232static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw,
233 int mc_count, struct dev_addr_list *mc_list);
232static void ath5k_configure_filter(struct ieee80211_hw *hw, 234static void ath5k_configure_filter(struct ieee80211_hw *hw,
233 unsigned int changed_flags, 235 unsigned int changed_flags,
234 unsigned int *new_flags, 236 unsigned int *new_flags,
235 int mc_count, struct dev_mc_list *mclist); 237 u64 multicast);
236static int ath5k_set_key(struct ieee80211_hw *hw, 238static int ath5k_set_key(struct ieee80211_hw *hw,
237 enum set_key_cmd cmd, 239 enum set_key_cmd cmd,
238 struct ieee80211_vif *vif, struct ieee80211_sta *sta, 240 struct ieee80211_vif *vif, struct ieee80211_sta *sta,
@@ -260,6 +262,7 @@ static const struct ieee80211_ops ath5k_hw_ops = {
260 .add_interface = ath5k_add_interface, 262 .add_interface = ath5k_add_interface,
261 .remove_interface = ath5k_remove_interface, 263 .remove_interface = ath5k_remove_interface,
262 .config = ath5k_config, 264 .config = ath5k_config,
265 .prepare_multicast = ath5k_prepare_multicast,
263 .configure_filter = ath5k_configure_filter, 266 .configure_filter = ath5k_configure_filter,
264 .set_key = ath5k_set_key, 267 .set_key = ath5k_set_key,
265 .get_stats = ath5k_get_stats, 268 .get_stats = ath5k_get_stats,
@@ -2853,6 +2856,37 @@ unlock:
2853 return ret; 2856 return ret;
2854} 2857}
2855 2858
2859static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw,
2860 int mc_count, struct dev_addr_list *mclist)
2861{
2862 u32 mfilt[2], val;
2863 int i;
2864 u8 pos;
2865
2866 mfilt[0] = 0;
2867 mfilt[1] = 1;
2868
2869 for (i = 0; i < mc_count; i++) {
2870 if (!mclist)
2871 break;
2872 /* calculate XOR of eight 6-bit values */
2873 val = get_unaligned_le32(mclist->dmi_addr + 0);
2874 pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
2875 val = get_unaligned_le32(mclist->dmi_addr + 3);
2876 pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
2877 pos &= 0x3f;
2878 mfilt[pos / 32] |= (1 << (pos % 32));
2879 /* XXX: we might be able to just do this instead,
2880 * but not sure, needs testing, if we do use this we'd
2881 * neet to inform below to not reset the mcast */
2882 /* ath5k_hw_set_mcast_filterindex(ah,
2883 * mclist->dmi_addr[5]); */
2884 mclist = mclist->next;
2885 }
2886
2887 return ((u64)(mfilt[1]) << 32) | mfilt[0];
2888}
2889
2856#define SUPPORTED_FIF_FLAGS \ 2890#define SUPPORTED_FIF_FLAGS \
2857 FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | \ 2891 FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | \
2858 FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \ 2892 FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \
@@ -2878,16 +2912,14 @@ unlock:
2878static void ath5k_configure_filter(struct ieee80211_hw *hw, 2912static void ath5k_configure_filter(struct ieee80211_hw *hw,
2879 unsigned int changed_flags, 2913 unsigned int changed_flags,
2880 unsigned int *new_flags, 2914 unsigned int *new_flags,
2881 int mc_count, struct dev_mc_list *mclist) 2915 u64 multicast)
2882{ 2916{
2883 struct ath5k_softc *sc = hw->priv; 2917 struct ath5k_softc *sc = hw->priv;
2884 struct ath5k_hw *ah = sc->ah; 2918 struct ath5k_hw *ah = sc->ah;
2885 u32 mfilt[2], val, rfilt; 2919 u32 mfilt[2], rfilt;
2886 u8 pos;
2887 int i;
2888 2920
2889 mfilt[0] = 0; 2921 mfilt[0] = multicast;
2890 mfilt[1] = 0; 2922 mfilt[1] = multicast >> 32;
2891 2923
2892 /* Only deal with supported flags */ 2924 /* Only deal with supported flags */
2893 changed_flags &= SUPPORTED_FIF_FLAGS; 2925 changed_flags &= SUPPORTED_FIF_FLAGS;
@@ -2913,24 +2945,6 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw,
2913 if (*new_flags & FIF_ALLMULTI) { 2945 if (*new_flags & FIF_ALLMULTI) {
2914 mfilt[0] = ~0; 2946 mfilt[0] = ~0;
2915 mfilt[1] = ~0; 2947 mfilt[1] = ~0;
2916 } else {
2917 for (i = 0; i < mc_count; i++) {
2918 if (!mclist)
2919 break;
2920 /* calculate XOR of eight 6-bit values */
2921 val = get_unaligned_le32(mclist->dmi_addr + 0);
2922 pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
2923 val = get_unaligned_le32(mclist->dmi_addr + 3);
2924 pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
2925 pos &= 0x3f;
2926 mfilt[pos / 32] |= (1 << (pos % 32));
2927 /* XXX: we might be able to just do this instead,
2928 * but not sure, needs testing, if we do use this we'd
2929 * neet to inform below to not reset the mcast */
2930 /* ath5k_hw_set_mcast_filterindex(ah,
2931 * mclist->dmi_addr[5]); */
2932 mclist = mclist->next;
2933 }
2934 } 2948 }
2935 2949
2936 /* This is the best we can do */ 2950 /* This is the best we can do */
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 3e09b9ac165b..2f9c149fd481 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -2394,8 +2394,7 @@ skip_chan_change:
2394static void ath9k_configure_filter(struct ieee80211_hw *hw, 2394static void ath9k_configure_filter(struct ieee80211_hw *hw,
2395 unsigned int changed_flags, 2395 unsigned int changed_flags,
2396 unsigned int *total_flags, 2396 unsigned int *total_flags,
2397 int mc_count, 2397 u64 multicast)
2398 struct dev_mc_list *mclist)
2399{ 2398{
2400 struct ath_wiphy *aphy = hw->priv; 2399 struct ath_wiphy *aphy = hw->priv;
2401 struct ath_softc *sc = aphy->sc; 2400 struct ath_softc *sc = aphy->sc;
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index c5bece090420..78ddbc7f836b 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -3679,7 +3679,7 @@ out_unlock:
3679 3679
3680static void b43_op_configure_filter(struct ieee80211_hw *hw, 3680static void b43_op_configure_filter(struct ieee80211_hw *hw,
3681 unsigned int changed, unsigned int *fflags, 3681 unsigned int changed, unsigned int *fflags,
3682 int mc_count, struct dev_addr_list *mc_list) 3682 u64 multicast)
3683{ 3683{
3684 struct b43_wl *wl = hw_to_b43_wl(hw); 3684 struct b43_wl *wl = hw_to_b43_wl(hw);
3685 struct b43_wldev *dev = wl->current_dev; 3685 struct b43_wldev *dev = wl->current_dev;
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index b1435594921a..b166a6f9f055 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -2836,9 +2836,7 @@ static void b43legacy_op_bss_info_changed(struct ieee80211_hw *hw,
2836 2836
2837static void b43legacy_op_configure_filter(struct ieee80211_hw *hw, 2837static void b43legacy_op_configure_filter(struct ieee80211_hw *hw,
2838 unsigned int changed, 2838 unsigned int changed,
2839 unsigned int *fflags, 2839 unsigned int *fflags,u64 multicast)
2840 int mc_count,
2841 struct dev_addr_list *mc_list)
2842{ 2840{
2843 struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); 2841 struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
2844 struct b43legacy_wldev *dev = wl->current_dev; 2842 struct b43legacy_wldev *dev = wl->current_dev;
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index c0efa6623c09..f1f6dabd8fbd 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -1514,7 +1514,7 @@ EXPORT_SYMBOL(iwl_irq_handle_error);
1514void iwl_configure_filter(struct ieee80211_hw *hw, 1514void iwl_configure_filter(struct ieee80211_hw *hw,
1515 unsigned int changed_flags, 1515 unsigned int changed_flags,
1516 unsigned int *total_flags, 1516 unsigned int *total_flags,
1517 int mc_count, struct dev_addr_list *mc_list) 1517 u64 multicast)
1518{ 1518{
1519 struct iwl_priv *priv = hw->priv; 1519 struct iwl_priv *priv = hw->priv;
1520 __le32 *filter_flags = &priv->staging_rxon.filter_flags; 1520 __le32 *filter_flags = &priv->staging_rxon.filter_flags;
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 4ca025a34daf..62d90364b61d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -282,8 +282,7 @@ int iwl_set_decrypted_flag(struct iwl_priv *priv,
282void iwl_irq_handle_error(struct iwl_priv *priv); 282void iwl_irq_handle_error(struct iwl_priv *priv);
283void iwl_configure_filter(struct ieee80211_hw *hw, 283void iwl_configure_filter(struct ieee80211_hw *hw,
284 unsigned int changed_flags, 284 unsigned int changed_flags,
285 unsigned int *total_flags, 285 unsigned int *total_flags, u64 multicast);
286 int mc_count, struct dev_addr_list *mc_list);
287int iwl_hw_nic_init(struct iwl_priv *priv); 286int iwl_hw_nic_init(struct iwl_priv *priv);
288int iwl_setup_mac(struct iwl_priv *priv); 287int iwl_setup_mac(struct iwl_priv *priv);
289int iwl_set_hw_params(struct iwl_priv *priv); 288int iwl_set_hw_params(struct iwl_priv *priv);
diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c
index 4872345a2f61..019431d2f8a9 100644
--- a/drivers/net/wireless/libertas_tf/main.c
+++ b/drivers/net/wireless/libertas_tf/main.c
@@ -366,15 +366,35 @@ static int lbtf_op_config(struct ieee80211_hw *hw, u32 changed)
366 return 0; 366 return 0;
367} 367}
368 368
369static u64 lbtf_op_prepare_multicast(struct ieee80211_hw *hw,
370 int mc_count, struct dev_addr_list *mclist)
371{
372 struct lbtf_private *priv = hw->priv;
373 int i;
374
375 if (!mc_count || mc_count > MRVDRV_MAX_MULTICAST_LIST_SIZE)
376 return mc_count;
377
378 priv->nr_of_multicastmacaddr = mc_count;
379 for (i = 0; i < mc_count; i++) {
380 if (!mclist)
381 break;
382 memcpy(&priv->multicastlist[i], mclist->da_addr,
383 ETH_ALEN);
384 mclist = mclist->next;
385 }
386
387 return mc_count;
388}
389
369#define SUPPORTED_FIF_FLAGS (FIF_PROMISC_IN_BSS | FIF_ALLMULTI) 390#define SUPPORTED_FIF_FLAGS (FIF_PROMISC_IN_BSS | FIF_ALLMULTI)
370static void lbtf_op_configure_filter(struct ieee80211_hw *hw, 391static void lbtf_op_configure_filter(struct ieee80211_hw *hw,
371 unsigned int changed_flags, 392 unsigned int changed_flags,
372 unsigned int *new_flags, 393 unsigned int *new_flags,
373 int mc_count, struct dev_mc_list *mclist) 394 u64 multicast)
374{ 395{
375 struct lbtf_private *priv = hw->priv; 396 struct lbtf_private *priv = hw->priv;
376 int old_mac_control = priv->mac_control; 397 int old_mac_control = priv->mac_control;
377 int i;
378 changed_flags &= SUPPORTED_FIF_FLAGS; 398 changed_flags &= SUPPORTED_FIF_FLAGS;
379 *new_flags &= SUPPORTED_FIF_FLAGS; 399 *new_flags &= SUPPORTED_FIF_FLAGS;
380 400
@@ -386,20 +406,12 @@ static void lbtf_op_configure_filter(struct ieee80211_hw *hw,
386 else 406 else
387 priv->mac_control &= ~CMD_ACT_MAC_PROMISCUOUS_ENABLE; 407 priv->mac_control &= ~CMD_ACT_MAC_PROMISCUOUS_ENABLE;
388 if (*new_flags & (FIF_ALLMULTI) || 408 if (*new_flags & (FIF_ALLMULTI) ||
389 mc_count > MRVDRV_MAX_MULTICAST_LIST_SIZE) { 409 multicast > MRVDRV_MAX_MULTICAST_LIST_SIZE) {
390 priv->mac_control |= CMD_ACT_MAC_ALL_MULTICAST_ENABLE; 410 priv->mac_control |= CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
391 priv->mac_control &= ~CMD_ACT_MAC_MULTICAST_ENABLE; 411 priv->mac_control &= ~CMD_ACT_MAC_MULTICAST_ENABLE;
392 } else if (mc_count) { 412 } else if (multicast) {
393 priv->mac_control |= CMD_ACT_MAC_MULTICAST_ENABLE; 413 priv->mac_control |= CMD_ACT_MAC_MULTICAST_ENABLE;
394 priv->mac_control &= ~CMD_ACT_MAC_ALL_MULTICAST_ENABLE; 414 priv->mac_control &= ~CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
395 priv->nr_of_multicastmacaddr = mc_count;
396 for (i = 0; i < mc_count; i++) {
397 if (!mclist)
398 break;
399 memcpy(&priv->multicastlist[i], mclist->da_addr,
400 ETH_ALEN);
401 mclist = mclist->next;
402 }
403 lbtf_cmd_set_mac_multicast_addr(priv); 415 lbtf_cmd_set_mac_multicast_addr(priv);
404 } else { 416 } else {
405 priv->mac_control &= ~(CMD_ACT_MAC_MULTICAST_ENABLE | 417 priv->mac_control &= ~(CMD_ACT_MAC_MULTICAST_ENABLE |
@@ -461,6 +473,7 @@ static const struct ieee80211_ops lbtf_ops = {
461 .add_interface = lbtf_op_add_interface, 473 .add_interface = lbtf_op_add_interface,
462 .remove_interface = lbtf_op_remove_interface, 474 .remove_interface = lbtf_op_remove_interface,
463 .config = lbtf_op_config, 475 .config = lbtf_op_config,
476 .prepare_multicast = lbtf_op_prepare_multicast,
464 .configure_filter = lbtf_op_configure_filter, 477 .configure_filter = lbtf_op_configure_filter,
465 .bss_info_changed = lbtf_op_bss_info_changed, 478 .bss_info_changed = lbtf_op_bss_info_changed,
466}; 479};
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 930f5c7da4a6..6f6cd43592c8 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -582,9 +582,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
582 582
583static void mac80211_hwsim_configure_filter(struct ieee80211_hw *hw, 583static void mac80211_hwsim_configure_filter(struct ieee80211_hw *hw,
584 unsigned int changed_flags, 584 unsigned int changed_flags,
585 unsigned int *total_flags, 585 unsigned int *total_flags,u64 multicast)
586 int mc_count,
587 struct dev_addr_list *mc_list)
588{ 586{
589 struct mac80211_hwsim_data *data = hw->priv; 587 struct mac80211_hwsim_data *data = hw->priv;
590 588
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 8a6d3afe4122..f84387083e73 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -3251,31 +3251,50 @@ mwl8k_configure_filter_exit:
3251 return rc; 3251 return rc;
3252} 3252}
3253 3253
3254static u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw,
3255 int mc_count, struct dev_addr_list *mclist)
3256{
3257 struct mwl8k_configure_filter_worker *worker;
3258
3259 worker = kzalloc(sizeof(*worker), GFP_ATOMIC);
3260
3261 if (!worker)
3262 return 0;
3263
3264 /*
3265 * XXX: This is _HORRIBLY_ broken!!
3266 *
3267 * No locking, the mclist pointer might be invalid as soon as this
3268 * function returns, something in the list might be invalidated
3269 * once we get to the worker, etc...
3270 */
3271 worker->mc_count = mc_count;
3272 worker->mclist = mclist;
3273
3274 return (u64)worker;
3275}
3276
3254static void mwl8k_configure_filter(struct ieee80211_hw *hw, 3277static void mwl8k_configure_filter(struct ieee80211_hw *hw,
3255 unsigned int changed_flags, 3278 unsigned int changed_flags,
3256 unsigned int *total_flags, 3279 unsigned int *total_flags,
3257 int mc_count, 3280 u64 multicast)
3258 struct dev_addr_list *mclist)
3259{ 3281{
3260 3282
3261 struct mwl8k_configure_filter_worker *worker; 3283 struct mwl8k_configure_filter_worker *worker = (void *)multicast;
3262 struct mwl8k_priv *priv = hw->priv; 3284 struct mwl8k_priv *priv = hw->priv;
3263 3285
3264 /* Clear unsupported feature flags */ 3286 /* Clear unsupported feature flags */
3265 *total_flags &= MWL8K_SUPPORTED_IF_FLAGS; 3287 *total_flags &= MWL8K_SUPPORTED_IF_FLAGS;
3266 3288
3267 if (!(changed_flags & MWL8K_SUPPORTED_IF_FLAGS) && !mc_count) 3289 if (!(changed_flags & MWL8K_SUPPORTED_IF_FLAGS))
3268 return; 3290 return;
3269 3291
3270 worker = kzalloc(sizeof(*worker), GFP_ATOMIC);
3271 if (worker == NULL) 3292 if (worker == NULL)
3272 return; 3293 return;
3273 3294
3274 worker->header.options = MWL8K_WQ_QUEUE_ONLY | MWL8K_WQ_TX_WAIT_EMPTY; 3295 worker->header.options = MWL8K_WQ_QUEUE_ONLY | MWL8K_WQ_TX_WAIT_EMPTY;
3275 worker->changed_flags = changed_flags; 3296 worker->changed_flags = changed_flags;
3276 worker->total_flags = total_flags; 3297 worker->total_flags = total_flags;
3277 worker->mc_count = mc_count;
3278 worker->mclist = mclist;
3279 3298
3280 mwl8k_queue_work(hw, &worker->header, priv->config_wq, 3299 mwl8k_queue_work(hw, &worker->header, priv->config_wq,
3281 mwl8k_configure_filter_wt); 3300 mwl8k_configure_filter_wt);
@@ -3441,6 +3460,7 @@ static const struct ieee80211_ops mwl8k_ops = {
3441 .remove_interface = mwl8k_remove_interface, 3460 .remove_interface = mwl8k_remove_interface,
3442 .config = mwl8k_config, 3461 .config = mwl8k_config,
3443 .bss_info_changed = mwl8k_bss_info_changed, 3462 .bss_info_changed = mwl8k_bss_info_changed,
3463 .prepare_multicast = mwl8k_prepare_multicast,
3444 .configure_filter = mwl8k_configure_filter, 3464 .configure_filter = mwl8k_configure_filter,
3445 .set_rts_threshold = mwl8k_set_rts_threshold, 3465 .set_rts_threshold = mwl8k_set_rts_threshold,
3446 .conf_tx = mwl8k_conf_tx, 3466 .conf_tx = mwl8k_conf_tx,
diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c
index 77203e346cda..4d486bf9f725 100644
--- a/drivers/net/wireless/p54/main.c
+++ b/drivers/net/wireless/p54/main.c
@@ -302,7 +302,7 @@ out:
302static void p54_configure_filter(struct ieee80211_hw *dev, 302static void p54_configure_filter(struct ieee80211_hw *dev,
303 unsigned int changed_flags, 303 unsigned int changed_flags,
304 unsigned int *total_flags, 304 unsigned int *total_flags,
305 int mc_count, struct dev_mc_list *mclist) 305 u64 multicast)
306{ 306{
307 struct p54_common *priv = dev->priv; 307 struct p54_common *priv = dev->priv;
308 308
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 99e89596cef6..39d7d9baafdd 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -978,7 +978,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed);
978void rt2x00mac_configure_filter(struct ieee80211_hw *hw, 978void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
979 unsigned int changed_flags, 979 unsigned int changed_flags,
980 unsigned int *total_flags, 980 unsigned int *total_flags,
981 int mc_count, struct dev_addr_list *mc_list); 981 u64 multicast);
982int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, 982int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
983 bool set); 983 bool set);
984#ifdef CONFIG_RT2X00_LIB_CRYPTO 984#ifdef CONFIG_RT2X00_LIB_CRYPTO
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index cb7b6d459331..602f12699718 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -379,7 +379,7 @@ EXPORT_SYMBOL_GPL(rt2x00mac_config);
379void rt2x00mac_configure_filter(struct ieee80211_hw *hw, 379void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
380 unsigned int changed_flags, 380 unsigned int changed_flags,
381 unsigned int *total_flags, 381 unsigned int *total_flags,
382 int mc_count, struct dev_addr_list *mc_list) 382 u64 multicast)
383{ 383{
384 struct rt2x00_dev *rt2x00dev = hw->priv; 384 struct rt2x00_dev *rt2x00dev = hw->priv;
385 385
diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c
index 09f46abc730a..16429c49139c 100644
--- a/drivers/net/wireless/rtl818x/rtl8180_dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c
@@ -728,10 +728,16 @@ static void rtl8180_bss_info_changed(struct ieee80211_hw *dev,
728 priv->rf->conf_erp(dev, info); 728 priv->rf->conf_erp(dev, info);
729} 729}
730 730
731static u64 rtl8180_prepare_multicast(struct ieee80211_hw *dev, int mc_count,
732 struct dev_addr_list *mc_list)
733{
734 return mc_count;
735}
736
731static void rtl8180_configure_filter(struct ieee80211_hw *dev, 737static void rtl8180_configure_filter(struct ieee80211_hw *dev,
732 unsigned int changed_flags, 738 unsigned int changed_flags,
733 unsigned int *total_flags, 739 unsigned int *total_flags,
734 int mc_count, struct dev_addr_list *mclist) 740 u64 multicast)
735{ 741{
736 struct rtl8180_priv *priv = dev->priv; 742 struct rtl8180_priv *priv = dev->priv;
737 743
@@ -741,7 +747,7 @@ static void rtl8180_configure_filter(struct ieee80211_hw *dev,
741 priv->rx_conf ^= RTL818X_RX_CONF_CTRL; 747 priv->rx_conf ^= RTL818X_RX_CONF_CTRL;
742 if (changed_flags & FIF_OTHER_BSS) 748 if (changed_flags & FIF_OTHER_BSS)
743 priv->rx_conf ^= RTL818X_RX_CONF_MONITOR; 749 priv->rx_conf ^= RTL818X_RX_CONF_MONITOR;
744 if (*total_flags & FIF_ALLMULTI || mc_count > 0) 750 if (*total_flags & FIF_ALLMULTI || multicast > 0)
745 priv->rx_conf |= RTL818X_RX_CONF_MULTICAST; 751 priv->rx_conf |= RTL818X_RX_CONF_MULTICAST;
746 else 752 else
747 priv->rx_conf &= ~RTL818X_RX_CONF_MULTICAST; 753 priv->rx_conf &= ~RTL818X_RX_CONF_MULTICAST;
@@ -768,6 +774,7 @@ static const struct ieee80211_ops rtl8180_ops = {
768 .remove_interface = rtl8180_remove_interface, 774 .remove_interface = rtl8180_remove_interface,
769 .config = rtl8180_config, 775 .config = rtl8180_config,
770 .bss_info_changed = rtl8180_bss_info_changed, 776 .bss_info_changed = rtl8180_bss_info_changed,
777 .prepare_multicast = rtl8180_prepare_multicast,
771 .configure_filter = rtl8180_configure_filter, 778 .configure_filter = rtl8180_configure_filter,
772}; 779};
773 780
diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c
index 53f57dc52226..90f38357393c 100644
--- a/drivers/net/wireless/rtl818x/rtl8187_dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c
@@ -1192,10 +1192,16 @@ static void rtl8187_bss_info_changed(struct ieee80211_hw *dev,
1192 info->use_short_preamble); 1192 info->use_short_preamble);
1193} 1193}
1194 1194
1195static u64 rtl8187_prepare_multicast(struct ieee80211_hw *dev,
1196 int mc_count, struct dev_addr_list *mc_list)
1197{
1198 return mc_count;
1199}
1200
1195static void rtl8187_configure_filter(struct ieee80211_hw *dev, 1201static void rtl8187_configure_filter(struct ieee80211_hw *dev,
1196 unsigned int changed_flags, 1202 unsigned int changed_flags,
1197 unsigned int *total_flags, 1203 unsigned int *total_flags,
1198 int mc_count, struct dev_addr_list *mclist) 1204 u64 multicast)
1199{ 1205{
1200 struct rtl8187_priv *priv = dev->priv; 1206 struct rtl8187_priv *priv = dev->priv;
1201 1207
@@ -1205,7 +1211,7 @@ static void rtl8187_configure_filter(struct ieee80211_hw *dev,
1205 priv->rx_conf ^= RTL818X_RX_CONF_CTRL; 1211 priv->rx_conf ^= RTL818X_RX_CONF_CTRL;
1206 if (changed_flags & FIF_OTHER_BSS) 1212 if (changed_flags & FIF_OTHER_BSS)
1207 priv->rx_conf ^= RTL818X_RX_CONF_MONITOR; 1213 priv->rx_conf ^= RTL818X_RX_CONF_MONITOR;
1208 if (*total_flags & FIF_ALLMULTI || mc_count > 0) 1214 if (*total_flags & FIF_ALLMULTI || multicast > 0)
1209 priv->rx_conf |= RTL818X_RX_CONF_MULTICAST; 1215 priv->rx_conf |= RTL818X_RX_CONF_MULTICAST;
1210 else 1216 else
1211 priv->rx_conf &= ~RTL818X_RX_CONF_MULTICAST; 1217 priv->rx_conf &= ~RTL818X_RX_CONF_MULTICAST;
@@ -1268,6 +1274,7 @@ static const struct ieee80211_ops rtl8187_ops = {
1268 .remove_interface = rtl8187_remove_interface, 1274 .remove_interface = rtl8187_remove_interface,
1269 .config = rtl8187_config, 1275 .config = rtl8187_config,
1270 .bss_info_changed = rtl8187_bss_info_changed, 1276 .bss_info_changed = rtl8187_bss_info_changed,
1277 .prepare_multicast = rtl8187_prepare_multicast,
1271 .configure_filter = rtl8187_configure_filter, 1278 .configure_filter = rtl8187_configure_filter,
1272 .conf_tx = rtl8187_conf_tx 1279 .conf_tx = rtl8187_conf_tx
1273}; 1280};
diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c
index 7148934e464d..5809ef5b18f8 100644
--- a/drivers/net/wireless/wl12xx/wl1251_main.c
+++ b/drivers/net/wireless/wl12xx/wl1251_main.c
@@ -652,9 +652,7 @@ out:
652 652
653static void wl1251_op_configure_filter(struct ieee80211_hw *hw, 653static void wl1251_op_configure_filter(struct ieee80211_hw *hw,
654 unsigned int changed, 654 unsigned int changed,
655 unsigned int *total, 655 unsigned int *total,u64 multicast)
656 int mc_count,
657 struct dev_addr_list *mc_list)
658{ 656{
659 struct wl1251 *wl = hw->priv; 657 struct wl1251 *wl = hw->priv;
660 658
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
index 4102d590b798..754be8179307 100644
--- a/drivers/net/wireless/wl12xx/wl1271_main.c
+++ b/drivers/net/wireless/wl12xx/wl1271_main.c
@@ -793,9 +793,7 @@ out:
793 793
794static void wl1271_op_configure_filter(struct ieee80211_hw *hw, 794static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
795 unsigned int changed, 795 unsigned int changed,
796 unsigned int *total, 796 unsigned int *total,u64 multicast)
797 int mc_count,
798 struct dev_addr_list *mc_list)
799{ 797{
800 struct wl1271 *wl = hw->priv; 798 struct wl1271 *wl = hw->priv;
801 799
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index 55b7fbdc85dc..6d666359a42f 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -796,18 +796,40 @@ static void set_rx_filter_handler(struct work_struct *work)
796 dev_err(zd_mac_dev(mac), "set_rx_filter_handler error %d\n", r); 796 dev_err(zd_mac_dev(mac), "set_rx_filter_handler error %d\n", r);
797} 797}
798 798
799static u64 zd_op_prepare_multicast(struct ieee80211_hw *hw,
800 int mc_count, struct dev_addr_list *mclist)
801{
802 struct zd_mac *mac = zd_hw_mac(hw);
803 struct zd_mc_hash hash;
804 int i;
805
806 zd_mc_clear(&hash);
807
808 for (i = 0; i < mc_count; i++) {
809 if (!mclist)
810 break;
811 dev_dbg_f(zd_mac_dev(mac), "mc addr %pM\n", mclist->dmi_addr);
812 zd_mc_add_addr(&hash, mclist->dmi_addr);
813 mclist = mclist->next;
814 }
815
816 return hash.low | ((u64)hash.high << 32);
817}
818
799#define SUPPORTED_FIF_FLAGS \ 819#define SUPPORTED_FIF_FLAGS \
800 (FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | FIF_CONTROL | \ 820 (FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | FIF_CONTROL | \
801 FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC) 821 FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC)
802static void zd_op_configure_filter(struct ieee80211_hw *hw, 822static void zd_op_configure_filter(struct ieee80211_hw *hw,
803 unsigned int changed_flags, 823 unsigned int changed_flags,
804 unsigned int *new_flags, 824 unsigned int *new_flags,
805 int mc_count, struct dev_mc_list *mclist) 825 u64 multicast)
806{ 826{
807 struct zd_mc_hash hash; 827 struct zd_mc_hash hash = {
828 .low = multicast,
829 .high = multicast >> 32,
830 };
808 struct zd_mac *mac = zd_hw_mac(hw); 831 struct zd_mac *mac = zd_hw_mac(hw);
809 unsigned long flags; 832 unsigned long flags;
810 int i;
811 833
812 /* Only deal with supported flags */ 834 /* Only deal with supported flags */
813 changed_flags &= SUPPORTED_FIF_FLAGS; 835 changed_flags &= SUPPORTED_FIF_FLAGS;
@@ -819,25 +841,16 @@ static void zd_op_configure_filter(struct ieee80211_hw *hw,
819 if (!changed_flags) 841 if (!changed_flags)
820 return; 842 return;
821 843
822 if (*new_flags & (FIF_PROMISC_IN_BSS | FIF_ALLMULTI)) { 844 if (*new_flags & (FIF_PROMISC_IN_BSS | FIF_ALLMULTI))
823 zd_mc_add_all(&hash); 845 zd_mc_add_all(&hash);
824 } else {
825 zd_mc_clear(&hash);
826 for (i = 0; i < mc_count; i++) {
827 if (!mclist)
828 break;
829 dev_dbg_f(zd_mac_dev(mac), "mc addr %pM\n",
830 mclist->dmi_addr);
831 zd_mc_add_addr(&hash, mclist->dmi_addr);
832 mclist = mclist->next;
833 }
834 }
835 846
836 spin_lock_irqsave(&mac->lock, flags); 847 spin_lock_irqsave(&mac->lock, flags);
837 mac->pass_failed_fcs = !!(*new_flags & FIF_FCSFAIL); 848 mac->pass_failed_fcs = !!(*new_flags & FIF_FCSFAIL);
838 mac->pass_ctrl = !!(*new_flags & FIF_CONTROL); 849 mac->pass_ctrl = !!(*new_flags & FIF_CONTROL);
839 mac->multicast_hash = hash; 850 mac->multicast_hash = hash;
840 spin_unlock_irqrestore(&mac->lock, flags); 851 spin_unlock_irqrestore(&mac->lock, flags);
852
853 /* XXX: these can be called here now, can sleep now! */
841 queue_work(zd_workqueue, &mac->set_multicast_hash_work); 854 queue_work(zd_workqueue, &mac->set_multicast_hash_work);
842 855
843 if (changed_flags & FIF_CONTROL) 856 if (changed_flags & FIF_CONTROL)
@@ -940,6 +953,7 @@ static const struct ieee80211_ops zd_ops = {
940 .add_interface = zd_op_add_interface, 953 .add_interface = zd_op_add_interface,
941 .remove_interface = zd_op_remove_interface, 954 .remove_interface = zd_op_remove_interface,
942 .config = zd_op_config, 955 .config = zd_op_config,
956 .prepare_multicast = zd_op_prepare_multicast,
943 .configure_filter = zd_op_configure_filter, 957 .configure_filter = zd_op_configure_filter,
944 .bss_info_changed = zd_op_bss_info_changed, 958 .bss_info_changed = zd_op_bss_info_changed,
945 .get_tsf = zd_op_get_tsf, 959 .get_tsf = zd_op_get_tsf,
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 76d43e12cc29..bc865206e5f1 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1219,10 +1219,13 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw,
1219 * the driver's configure_filter() function which frames should be 1219 * the driver's configure_filter() function which frames should be
1220 * passed to mac80211 and which should be filtered out. 1220 * passed to mac80211 and which should be filtered out.
1221 * 1221 *
1222 * The configure_filter() callback is invoked with the parameters 1222 * Before configure_filter() is invoked, the prepare_multicast()
1223 * @mc_count and @mc_list for the combined multicast address list 1223 * callback is invoked with the parameters @mc_count and @mc_list
1224 * of all virtual interfaces, @changed_flags telling which flags 1224 * for the combined multicast address list of all virtual interfaces.
1225 * were changed and @total_flags with the new flag states. 1225 * It's use is optional, and it returns a u64 that is passed to
1226 * configure_filter(). Additionally, configure_filter() has the
1227 * arguments @changed_flags telling which flags were changed and
1228 * @total_flags with the new flag states.
1226 * 1229 *
1227 * If your device has no multicast address filters your driver will 1230 * If your device has no multicast address filters your driver will
1228 * need to check both the %FIF_ALLMULTI flag and the @mc_count 1231 * need to check both the %FIF_ALLMULTI flag and the @mc_count
@@ -1375,9 +1378,13 @@ enum ieee80211_ampdu_mlme_action {
1375 * for association indication. The @changed parameter indicates which 1378 * for association indication. The @changed parameter indicates which
1376 * of the bss parameters has changed when a call is made. 1379 * of the bss parameters has changed when a call is made.
1377 * 1380 *
1381 * @prepare_multicast: Prepare for multicast filter configuration.
1382 * This callback is optional, and its return value is passed
1383 * to configure_filter(). This callback must be atomic.
1384 *
1378 * @configure_filter: Configure the device's RX filter. 1385 * @configure_filter: Configure the device's RX filter.
1379 * See the section "Frame filtering" for more information. 1386 * See the section "Frame filtering" for more information.
1380 * This callback must be implemented and atomic. 1387 * This callback must be implemented.
1381 * 1388 *
1382 * @set_tim: Set TIM bit. mac80211 calls this function when a TIM bit 1389 * @set_tim: Set TIM bit. mac80211 calls this function when a TIM bit
1383 * must be set or cleared for a given STA. Must be atomic. 1390 * must be set or cleared for a given STA. Must be atomic.
@@ -1479,10 +1486,12 @@ struct ieee80211_ops {
1479 struct ieee80211_vif *vif, 1486 struct ieee80211_vif *vif,
1480 struct ieee80211_bss_conf *info, 1487 struct ieee80211_bss_conf *info,
1481 u32 changed); 1488 u32 changed);
1489 u64 (*prepare_multicast)(struct ieee80211_hw *hw,
1490 int mc_count, struct dev_addr_list *mc_list);
1482 void (*configure_filter)(struct ieee80211_hw *hw, 1491 void (*configure_filter)(struct ieee80211_hw *hw,
1483 unsigned int changed_flags, 1492 unsigned int changed_flags,
1484 unsigned int *total_flags, 1493 unsigned int *total_flags,
1485 int mc_count, struct dev_addr_list *mc_list); 1494 u64 multicast);
1486 int (*set_tim)(struct ieee80211_hw *hw, struct ieee80211_sta *sta, 1495 int (*set_tim)(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
1487 bool set); 1496 bool set);
1488 int (*set_key)(struct ieee80211_hw *hw, enum set_key_cmd cmd, 1497 int (*set_key)(struct ieee80211_hw *hw, enum set_key_cmd cmd,
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 4100c361a99d..d231c9323ad1 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -55,16 +55,32 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local,
55 trace_drv_bss_info_changed(local, vif, info, changed); 55 trace_drv_bss_info_changed(local, vif, info, changed);
56} 56}
57 57
58static inline u64 drv_prepare_multicast(struct ieee80211_local *local,
59 int mc_count,
60 struct dev_addr_list *mc_list)
61{
62 u64 ret = 0;
63
64 if (local->ops->prepare_multicast)
65 ret = local->ops->prepare_multicast(&local->hw, mc_count,
66 mc_list);
67
68 trace_drv_prepare_multicast(local, mc_count, ret);
69
70 return ret;
71}
72
58static inline void drv_configure_filter(struct ieee80211_local *local, 73static inline void drv_configure_filter(struct ieee80211_local *local,
59 unsigned int changed_flags, 74 unsigned int changed_flags,
60 unsigned int *total_flags, 75 unsigned int *total_flags,
61 int mc_count, 76 u64 multicast)
62 struct dev_addr_list *mc_list)
63{ 77{
78 might_sleep();
79
64 local->ops->configure_filter(&local->hw, changed_flags, total_flags, 80 local->ops->configure_filter(&local->hw, changed_flags, total_flags,
65 mc_count, mc_list); 81 multicast);
66 trace_drv_configure_filter(local, changed_flags, total_flags, 82 trace_drv_configure_filter(local, changed_flags, total_flags,
67 mc_count); 83 multicast);
68} 84}
69 85
70static inline int drv_set_tim(struct ieee80211_local *local, 86static inline int drv_set_tim(struct ieee80211_local *local,
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h
index 5a10da2d70fd..37b9051afcf3 100644
--- a/net/mac80211/driver-trace.h
+++ b/net/mac80211/driver-trace.h
@@ -191,31 +191,55 @@ TRACE_EVENT(drv_bss_info_changed,
191 ) 191 )
192); 192);
193 193
194TRACE_EVENT(drv_prepare_multicast,
195 TP_PROTO(struct ieee80211_local *local, int mc_count, u64 ret),
196
197 TP_ARGS(local, mc_count, ret),
198
199 TP_STRUCT__entry(
200 LOCAL_ENTRY
201 __field(int, mc_count)
202 __field(u64, ret)
203 ),
204
205 TP_fast_assign(
206 LOCAL_ASSIGN;
207 __entry->mc_count = mc_count;
208 __entry->ret = ret;
209 ),
210
211 TP_printk(
212 LOCAL_PR_FMT " prepare mc (%d): %llx",
213 LOCAL_PR_ARG, __entry->mc_count,
214 (unsigned long long) __entry->ret
215 )
216);
217
194TRACE_EVENT(drv_configure_filter, 218TRACE_EVENT(drv_configure_filter,
195 TP_PROTO(struct ieee80211_local *local, 219 TP_PROTO(struct ieee80211_local *local,
196 unsigned int changed_flags, 220 unsigned int changed_flags,
197 unsigned int *total_flags, 221 unsigned int *total_flags,
198 int mc_count), 222 u64 multicast),
199 223
200 TP_ARGS(local, changed_flags, total_flags, mc_count), 224 TP_ARGS(local, changed_flags, total_flags, multicast),
201 225
202 TP_STRUCT__entry( 226 TP_STRUCT__entry(
203 LOCAL_ENTRY 227 LOCAL_ENTRY
204 __field(unsigned int, changed) 228 __field(unsigned int, changed)
205 __field(unsigned int, total) 229 __field(unsigned int, total)
206 __field(int, mc) 230 __field(u64, multicast)
207 ), 231 ),
208 232
209 TP_fast_assign( 233 TP_fast_assign(
210 LOCAL_ASSIGN; 234 LOCAL_ASSIGN;
211 __entry->changed = changed_flags; 235 __entry->changed = changed_flags;
212 __entry->total = *total_flags; 236 __entry->total = *total_flags;
213 __entry->mc = mc_count; 237 __entry->multicast = multicast;
214 ), 238 ),
215 239
216 TP_printk( 240 TP_printk(
217 LOCAL_PR_FMT " changed:%#x total:%#x mc:%d", 241 LOCAL_PR_FMT " changed:%#x total:%#x",
218 LOCAL_PR_ARG, __entry->changed, __entry->total, __entry->mc 242 LOCAL_PR_ARG, __entry->changed, __entry->total
219 ) 243 )
220); 244);
221 245
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index a6abc7dfd903..a07f01736a91 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -636,6 +636,9 @@ struct ieee80211_local {
636 /* protects the aggregated multicast list and filter calls */ 636 /* protects the aggregated multicast list and filter calls */
637 spinlock_t filter_lock; 637 spinlock_t filter_lock;
638 638
639 /* used for uploading changed mc list */
640 struct work_struct reconfig_filter;
641
639 /* aggregated multicast list */ 642 /* aggregated multicast list */
640 struct dev_addr_list *mc_list; 643 struct dev_addr_list *mc_list;
641 int mc_count; 644 int mc_count;
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index e8fb03b91a44..b161301056df 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -227,9 +227,7 @@ static int ieee80211_open(struct net_device *dev)
227 if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) 227 if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
228 local->fif_other_bss++; 228 local->fif_other_bss++;
229 229
230 spin_lock_bh(&local->filter_lock);
231 ieee80211_configure_filter(local); 230 ieee80211_configure_filter(local);
232 spin_unlock_bh(&local->filter_lock);
233 break; 231 break;
234 default: 232 default:
235 conf.vif = &sdata->vif; 233 conf.vif = &sdata->vif;
@@ -241,17 +239,13 @@ static int ieee80211_open(struct net_device *dev)
241 239
242 if (ieee80211_vif_is_mesh(&sdata->vif)) { 240 if (ieee80211_vif_is_mesh(&sdata->vif)) {
243 local->fif_other_bss++; 241 local->fif_other_bss++;
244 spin_lock_bh(&local->filter_lock);
245 ieee80211_configure_filter(local); 242 ieee80211_configure_filter(local);
246 spin_unlock_bh(&local->filter_lock);
247 243
248 ieee80211_start_mesh(sdata); 244 ieee80211_start_mesh(sdata);
249 } else if (sdata->vif.type == NL80211_IFTYPE_AP) { 245 } else if (sdata->vif.type == NL80211_IFTYPE_AP) {
250 local->fif_pspoll++; 246 local->fif_pspoll++;
251 247
252 spin_lock_bh(&local->filter_lock);
253 ieee80211_configure_filter(local); 248 ieee80211_configure_filter(local);
254 spin_unlock_bh(&local->filter_lock);
255 } 249 }
256 250
257 changed |= ieee80211_reset_erp_info(sdata); 251 changed |= ieee80211_reset_erp_info(sdata);
@@ -404,10 +398,11 @@ static int ieee80211_stop(struct net_device *dev)
404 spin_lock_bh(&local->filter_lock); 398 spin_lock_bh(&local->filter_lock);
405 __dev_addr_unsync(&local->mc_list, &local->mc_count, 399 __dev_addr_unsync(&local->mc_list, &local->mc_count,
406 &dev->mc_list, &dev->mc_count); 400 &dev->mc_list, &dev->mc_count);
407 ieee80211_configure_filter(local);
408 spin_unlock_bh(&local->filter_lock); 401 spin_unlock_bh(&local->filter_lock);
409 netif_addr_unlock_bh(dev); 402 netif_addr_unlock_bh(dev);
410 403
404 ieee80211_configure_filter(local);
405
411 del_timer_sync(&local->dynamic_ps_timer); 406 del_timer_sync(&local->dynamic_ps_timer);
412 cancel_work_sync(&local->dynamic_ps_enable_work); 407 cancel_work_sync(&local->dynamic_ps_enable_work);
413 408
@@ -458,9 +453,7 @@ static int ieee80211_stop(struct net_device *dev)
458 if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) 453 if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
459 local->fif_other_bss--; 454 local->fif_other_bss--;
460 455
461 spin_lock_bh(&local->filter_lock);
462 ieee80211_configure_filter(local); 456 ieee80211_configure_filter(local);
463 spin_unlock_bh(&local->filter_lock);
464 break; 457 break;
465 case NL80211_IFTYPE_STATION: 458 case NL80211_IFTYPE_STATION:
466 del_timer_sync(&sdata->u.mgd.chswitch_timer); 459 del_timer_sync(&sdata->u.mgd.chswitch_timer);
@@ -503,9 +496,7 @@ static int ieee80211_stop(struct net_device *dev)
503 local->fif_other_bss--; 496 local->fif_other_bss--;
504 atomic_dec(&local->iff_allmultis); 497 atomic_dec(&local->iff_allmultis);
505 498
506 spin_lock_bh(&local->filter_lock);
507 ieee80211_configure_filter(local); 499 ieee80211_configure_filter(local);
508 spin_unlock_bh(&local->filter_lock);
509 500
510 ieee80211_stop_mesh(sdata); 501 ieee80211_stop_mesh(sdata);
511 } 502 }
@@ -622,8 +613,8 @@ static void ieee80211_set_multicast_list(struct net_device *dev)
622 spin_lock_bh(&local->filter_lock); 613 spin_lock_bh(&local->filter_lock);
623 __dev_addr_sync(&local->mc_list, &local->mc_count, 614 __dev_addr_sync(&local->mc_list, &local->mc_count,
624 &dev->mc_list, &dev->mc_count); 615 &dev->mc_list, &dev->mc_count);
625 ieee80211_configure_filter(local);
626 spin_unlock_bh(&local->filter_lock); 616 spin_unlock_bh(&local->filter_lock);
617 ieee80211_queue_work(&local->hw, &local->reconfig_filter);
627} 618}
628 619
629/* 620/*
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index b03fd84777fa..05f923575fee 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -50,9 +50,9 @@ struct ieee80211_tx_status_rtap_hdr {
50} __attribute__ ((packed)); 50} __attribute__ ((packed));
51 51
52 52
53/* must be called under mdev tx lock */
54void ieee80211_configure_filter(struct ieee80211_local *local) 53void ieee80211_configure_filter(struct ieee80211_local *local)
55{ 54{
55 u64 mc;
56 unsigned int changed_flags; 56 unsigned int changed_flags;
57 unsigned int new_flags = 0; 57 unsigned int new_flags = 0;
58 58
@@ -62,7 +62,7 @@ void ieee80211_configure_filter(struct ieee80211_local *local)
62 if (atomic_read(&local->iff_allmultis)) 62 if (atomic_read(&local->iff_allmultis))
63 new_flags |= FIF_ALLMULTI; 63 new_flags |= FIF_ALLMULTI;
64 64
65 if (local->monitors) 65 if (local->monitors || local->scanning)
66 new_flags |= FIF_BCN_PRBRESP_PROMISC; 66 new_flags |= FIF_BCN_PRBRESP_PROMISC;
67 67
68 if (local->fif_fcsfail) 68 if (local->fif_fcsfail)
@@ -80,20 +80,30 @@ void ieee80211_configure_filter(struct ieee80211_local *local)
80 if (local->fif_pspoll) 80 if (local->fif_pspoll)
81 new_flags |= FIF_PSPOLL; 81 new_flags |= FIF_PSPOLL;
82 82
83 spin_lock_bh(&local->filter_lock);
83 changed_flags = local->filter_flags ^ new_flags; 84 changed_flags = local->filter_flags ^ new_flags;
84 85
86 mc = drv_prepare_multicast(local, local->mc_count, local->mc_list);
87 spin_unlock_bh(&local->filter_lock);
88
85 /* be a bit nasty */ 89 /* be a bit nasty */
86 new_flags |= (1<<31); 90 new_flags |= (1<<31);
87 91
88 drv_configure_filter(local, changed_flags, &new_flags, 92 drv_configure_filter(local, changed_flags, &new_flags, mc);
89 local->mc_count,
90 local->mc_list);
91 93
92 WARN_ON(new_flags & (1<<31)); 94 WARN_ON(new_flags & (1<<31));
93 95
94 local->filter_flags = new_flags & ~(1<<31); 96 local->filter_flags = new_flags & ~(1<<31);
95} 97}
96 98
99static void ieee80211_reconfig_filter(struct work_struct *work)
100{
101 struct ieee80211_local *local =
102 container_of(work, struct ieee80211_local, reconfig_filter);
103
104 ieee80211_configure_filter(local);
105}
106
97int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) 107int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
98{ 108{
99 struct ieee80211_channel *chan, *scan_chan; 109 struct ieee80211_channel *chan, *scan_chan;
@@ -692,6 +702,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
692 702
693 INIT_WORK(&local->restart_work, ieee80211_restart_work); 703 INIT_WORK(&local->restart_work, ieee80211_restart_work);
694 704
705 INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter);
706
695 INIT_WORK(&local->dynamic_ps_enable_work, 707 INIT_WORK(&local->dynamic_ps_enable_work,
696 ieee80211_dynamic_ps_enable_work); 708 ieee80211_dynamic_ps_enable_work);
697 INIT_WORK(&local->dynamic_ps_disable_work, 709 INIT_WORK(&local->dynamic_ps_disable_work,
@@ -946,6 +958,8 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
946 958
947 rtnl_unlock(); 959 rtnl_unlock();
948 960
961 cancel_work_sync(&local->reconfig_filter);
962
949 ieee80211_clear_tx_pending(local); 963 ieee80211_clear_tx_pending(local);
950 sta_info_stop(local); 964 sta_info_stop(local);
951 rate_control_deinitialize(local); 965 rate_control_deinitialize(local);
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index e091cbc3434f..1e04be6b9129 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -292,13 +292,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
292 if (was_hw_scan) 292 if (was_hw_scan)
293 goto done; 293 goto done;
294 294
295 spin_lock_bh(&local->filter_lock); 295 ieee80211_configure_filter(local);
296 local->filter_flags &= ~FIF_BCN_PRBRESP_PROMISC;
297 drv_configure_filter(local, FIF_BCN_PRBRESP_PROMISC,
298 &local->filter_flags,
299 local->mc_count,
300 local->mc_list);
301 spin_unlock_bh(&local->filter_lock);
302 296
303 drv_sw_scan_complete(local); 297 drv_sw_scan_complete(local);
304 298
@@ -376,13 +370,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
376 local->next_scan_state = SCAN_DECISION; 370 local->next_scan_state = SCAN_DECISION;
377 local->scan_channel_idx = 0; 371 local->scan_channel_idx = 0;
378 372
379 spin_lock_bh(&local->filter_lock); 373 ieee80211_configure_filter(local);
380 local->filter_flags |= FIF_BCN_PRBRESP_PROMISC;
381 drv_configure_filter(local, FIF_BCN_PRBRESP_PROMISC,
382 &local->filter_flags,
383 local->mc_count,
384 local->mc_list);
385 spin_unlock_bh(&local->filter_lock);
386 374
387 /* TODO: start scan as soon as all nullfunc frames are ACKed */ 375 /* TODO: start scan as soon as all nullfunc frames are ACKed */
388 ieee80211_queue_delayed_work(&local->hw, 376 ieee80211_queue_delayed_work(&local->hw,
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index e55d57f559ec..5eb306377c63 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1076,9 +1076,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
1076 /* reconfigure hardware */ 1076 /* reconfigure hardware */
1077 ieee80211_hw_config(local, ~0); 1077 ieee80211_hw_config(local, ~0);
1078 1078
1079 spin_lock_bh(&local->filter_lock);
1080 ieee80211_configure_filter(local); 1079 ieee80211_configure_filter(local);
1081 spin_unlock_bh(&local->filter_lock);
1082 1080
1083 /* Finally also reconfigure all the BSS information */ 1081 /* Finally also reconfigure all the BSS information */
1084 list_for_each_entry(sdata, &local->interfaces, list) { 1082 list_for_each_entry(sdata, &local->interfaces, list) {