diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2009-08-17 10:16:53 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-08-20 11:35:58 -0400 |
commit | 3ac64beecd27400d12cc7afb4108eef26c499f6a (patch) | |
tree | da0220085f68e30fe61ba9b8833dc6311d6dc25e | |
parent | ea416a793d2b611f22b42ba094fd2e5bd30fff43 (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>
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 | ||
1331 | static 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 | |||
1331 | static void adm8211_configure_filter(struct ieee80211_hw *dev, | 1352 | static 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 */ |
1998 | static void at76_configure_filter(struct ieee80211_hw *hw, | 1998 | static 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 | ||
2103 | static 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 | |||
2103 | static void ar9170_op_configure_filter(struct ieee80211_hw *hw, | 2122 | static 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, | |||
229 | static void ath5k_remove_interface(struct ieee80211_hw *hw, | 229 | static void ath5k_remove_interface(struct ieee80211_hw *hw, |
230 | struct ieee80211_if_init_conf *conf); | 230 | struct ieee80211_if_init_conf *conf); |
231 | static int ath5k_config(struct ieee80211_hw *hw, u32 changed); | 231 | static int ath5k_config(struct ieee80211_hw *hw, u32 changed); |
232 | static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw, | ||
233 | int mc_count, struct dev_addr_list *mc_list); | ||
232 | static void ath5k_configure_filter(struct ieee80211_hw *hw, | 234 | static 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); |
236 | static int ath5k_set_key(struct ieee80211_hw *hw, | 238 | static 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 | ||
2859 | static 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: | |||
2878 | static void ath5k_configure_filter(struct ieee80211_hw *hw, | 2912 | static 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: | |||
2394 | static void ath9k_configure_filter(struct ieee80211_hw *hw, | 2394 | static 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 | ||
3680 | static void b43_op_configure_filter(struct ieee80211_hw *hw, | 3680 | static 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 | ||
2837 | static void b43legacy_op_configure_filter(struct ieee80211_hw *hw, | 2837 | static 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); | |||
1514 | void iwl_configure_filter(struct ieee80211_hw *hw, | 1514 | void 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, | |||
282 | void iwl_irq_handle_error(struct iwl_priv *priv); | 282 | void iwl_irq_handle_error(struct iwl_priv *priv); |
283 | void iwl_configure_filter(struct ieee80211_hw *hw, | 283 | void 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); | ||
287 | int iwl_hw_nic_init(struct iwl_priv *priv); | 286 | int iwl_hw_nic_init(struct iwl_priv *priv); |
288 | int iwl_setup_mac(struct iwl_priv *priv); | 287 | int iwl_setup_mac(struct iwl_priv *priv); |
289 | int iwl_set_hw_params(struct iwl_priv *priv); | 288 | int 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 | ||
369 | static 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) |
370 | static void lbtf_op_configure_filter(struct ieee80211_hw *hw, | 391 | static 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 | ||
583 | static void mac80211_hwsim_configure_filter(struct ieee80211_hw *hw, | 583 | static 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 | ||
3254 | static 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 | |||
3254 | static void mwl8k_configure_filter(struct ieee80211_hw *hw, | 3277 | static 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: | |||
302 | static void p54_configure_filter(struct ieee80211_hw *dev, | 302 | static 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); | |||
978 | void rt2x00mac_configure_filter(struct ieee80211_hw *hw, | 978 | void 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); |
982 | int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, | 982 | int 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); | |||
379 | void rt2x00mac_configure_filter(struct ieee80211_hw *hw, | 379 | void 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 | ||
731 | static 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 | |||
731 | static void rtl8180_configure_filter(struct ieee80211_hw *dev, | 737 | static 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 | ||
1195 | static 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 | |||
1195 | static void rtl8187_configure_filter(struct ieee80211_hw *dev, | 1201 | static 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 | ||
653 | static void wl1251_op_configure_filter(struct ieee80211_hw *hw, | 653 | static 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 | ||
794 | static void wl1271_op_configure_filter(struct ieee80211_hw *hw, | 794 | static 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 | ||
799 | static 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) |
802 | static void zd_op_configure_filter(struct ieee80211_hw *hw, | 822 | static 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 | ||
58 | static 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 | |||
58 | static inline void drv_configure_filter(struct ieee80211_local *local, | 73 | static 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 | ||
70 | static inline int drv_set_tim(struct ieee80211_local *local, | 86 | static 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 | ||
194 | TRACE_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 | |||
194 | TRACE_EVENT(drv_configure_filter, | 218 | TRACE_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 */ | ||
54 | void ieee80211_configure_filter(struct ieee80211_local *local) | 53 | void 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 | ||
99 | static 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 | |||
97 | int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) | 107 | int 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) { |