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>
This commit is contained in:
parent
ea416a793d
commit
3ac64beecd
@ -1328,16 +1328,39 @@ static void adm8211_bss_info_changed(struct ieee80211_hw *dev,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u64 adm8211_prepare_multicast(struct ieee80211_hw *hw,
|
||||||
|
int mc_count, struct dev_addr_list *mclist)
|
||||||
|
{
|
||||||
|
unsigned int bit_nr, i;
|
||||||
|
u32 mc_filter[2];
|
||||||
|
|
||||||
|
mc_filter[1] = mc_filter[0] = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < mc_count; i++) {
|
||||||
|
if (!mclist)
|
||||||
|
break;
|
||||||
|
bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
|
||||||
|
|
||||||
|
bit_nr &= 0x3F;
|
||||||
|
mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
|
||||||
|
mclist = mclist->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mc_filter[0] | ((u64)(mc_filter[1]) << 32);
|
||||||
|
}
|
||||||
|
|
||||||
static void adm8211_configure_filter(struct ieee80211_hw *dev,
|
static void adm8211_configure_filter(struct ieee80211_hw *dev,
|
||||||
unsigned int changed_flags,
|
unsigned int changed_flags,
|
||||||
unsigned int *total_flags,
|
unsigned int *total_flags,
|
||||||
int mc_count, struct dev_mc_list *mclist)
|
u64 multicast)
|
||||||
{
|
{
|
||||||
static const u8 bcast[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
static const u8 bcast[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||||
struct adm8211_priv *priv = dev->priv;
|
struct adm8211_priv *priv = dev->priv;
|
||||||
unsigned int bit_nr, new_flags;
|
unsigned int new_flags;
|
||||||
u32 mc_filter[2];
|
u32 mc_filter[2];
|
||||||
int i;
|
|
||||||
|
mc_filter[0] = multicast;
|
||||||
|
mc_filter[1] = multicast >> 32;
|
||||||
|
|
||||||
new_flags = 0;
|
new_flags = 0;
|
||||||
|
|
||||||
@ -1346,23 +1369,13 @@ static void adm8211_configure_filter(struct ieee80211_hw *dev,
|
|||||||
priv->nar |= ADM8211_NAR_PR;
|
priv->nar |= ADM8211_NAR_PR;
|
||||||
priv->nar &= ~ADM8211_NAR_MM;
|
priv->nar &= ~ADM8211_NAR_MM;
|
||||||
mc_filter[1] = mc_filter[0] = ~0;
|
mc_filter[1] = mc_filter[0] = ~0;
|
||||||
} else if ((*total_flags & FIF_ALLMULTI) || (mc_count > 32)) {
|
} else if (*total_flags & FIF_ALLMULTI || multicast == ~(0ULL)) {
|
||||||
new_flags |= FIF_ALLMULTI;
|
new_flags |= FIF_ALLMULTI;
|
||||||
priv->nar &= ~ADM8211_NAR_PR;
|
priv->nar &= ~ADM8211_NAR_PR;
|
||||||
priv->nar |= ADM8211_NAR_MM;
|
priv->nar |= ADM8211_NAR_MM;
|
||||||
mc_filter[1] = mc_filter[0] = ~0;
|
mc_filter[1] = mc_filter[0] = ~0;
|
||||||
} else {
|
} else {
|
||||||
priv->nar &= ~(ADM8211_NAR_MM | ADM8211_NAR_PR);
|
priv->nar &= ~(ADM8211_NAR_MM | ADM8211_NAR_PR);
|
||||||
mc_filter[1] = mc_filter[0] = 0;
|
|
||||||
for (i = 0; i < mc_count; i++) {
|
|
||||||
if (!mclist)
|
|
||||||
break;
|
|
||||||
bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
|
|
||||||
|
|
||||||
bit_nr &= 0x3F;
|
|
||||||
mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
|
|
||||||
mclist = mclist->next;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ADM8211_IDLE_RX();
|
ADM8211_IDLE_RX();
|
||||||
@ -1757,6 +1770,7 @@ static const struct ieee80211_ops adm8211_ops = {
|
|||||||
.remove_interface = adm8211_remove_interface,
|
.remove_interface = adm8211_remove_interface,
|
||||||
.config = adm8211_config,
|
.config = adm8211_config,
|
||||||
.bss_info_changed = adm8211_bss_info_changed,
|
.bss_info_changed = adm8211_bss_info_changed,
|
||||||
|
.prepare_multicast = adm8211_prepare_multicast,
|
||||||
.configure_filter = adm8211_configure_filter,
|
.configure_filter = adm8211_configure_filter,
|
||||||
.get_stats = adm8211_get_stats,
|
.get_stats = adm8211_get_stats,
|
||||||
.get_tx_stats = adm8211_get_tx_stats,
|
.get_tx_stats = adm8211_get_tx_stats,
|
||||||
|
@ -1997,15 +1997,14 @@ static void at76_bss_info_changed(struct ieee80211_hw *hw,
|
|||||||
/* must be atomic */
|
/* must be atomic */
|
||||||
static void at76_configure_filter(struct ieee80211_hw *hw,
|
static void at76_configure_filter(struct ieee80211_hw *hw,
|
||||||
unsigned int changed_flags,
|
unsigned int changed_flags,
|
||||||
unsigned int *total_flags, int mc_count,
|
unsigned int *total_flags, u64 multicast)
|
||||||
struct dev_addr_list *mc_list)
|
|
||||||
{
|
{
|
||||||
struct at76_priv *priv = hw->priv;
|
struct at76_priv *priv = hw->priv;
|
||||||
int flags;
|
int flags;
|
||||||
|
|
||||||
at76_dbg(DBG_MAC80211, "%s(): changed_flags=0x%08x "
|
at76_dbg(DBG_MAC80211, "%s(): changed_flags=0x%08x "
|
||||||
"total_flags=0x%08x mc_count=%d",
|
"total_flags=0x%08x",
|
||||||
__func__, changed_flags, *total_flags, mc_count);
|
__func__, changed_flags, *total_flags);
|
||||||
|
|
||||||
flags = changed_flags & AT76_SUPPORTED_FILTERS;
|
flags = changed_flags & AT76_SUPPORTED_FILTERS;
|
||||||
*total_flags = AT76_SUPPORTED_FILTERS;
|
*total_flags = AT76_SUPPORTED_FILTERS;
|
||||||
|
@ -2100,10 +2100,29 @@ static void ar9170_set_filters(struct work_struct *work)
|
|||||||
mutex_unlock(&ar->mutex);
|
mutex_unlock(&ar->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u64 ar9170_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
|
||||||
|
struct dev_addr_list *mclist)
|
||||||
|
{
|
||||||
|
u64 mchash;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* always get broadcast frames */
|
||||||
|
mchash = 1ULL << (0xff >> 2);
|
||||||
|
|
||||||
|
for (i = 0; i < mc_count; i++) {
|
||||||
|
if (WARN_ON(!mclist))
|
||||||
|
break;
|
||||||
|
mchash |= 1ULL << (mclist->dmi_addr[5] >> 2);
|
||||||
|
mclist = mclist->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mchash;
|
||||||
|
}
|
||||||
|
|
||||||
static void ar9170_op_configure_filter(struct ieee80211_hw *hw,
|
static void ar9170_op_configure_filter(struct ieee80211_hw *hw,
|
||||||
unsigned int changed_flags,
|
unsigned int changed_flags,
|
||||||
unsigned int *new_flags,
|
unsigned int *new_flags,
|
||||||
int mc_count, struct dev_mc_list *mclist)
|
u64 multicast)
|
||||||
{
|
{
|
||||||
struct ar9170 *ar = hw->priv;
|
struct ar9170 *ar = hw->priv;
|
||||||
|
|
||||||
@ -2116,24 +2135,11 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw,
|
|||||||
* then checking the error flags, later.
|
* then checking the error flags, later.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (changed_flags & FIF_ALLMULTI) {
|
if (changed_flags & FIF_ALLMULTI && *new_flags & FIF_ALLMULTI)
|
||||||
if (*new_flags & FIF_ALLMULTI) {
|
multicast = ~0ULL;
|
||||||
ar->want_mc_hash = ~0ULL;
|
|
||||||
} else {
|
|
||||||
u64 mchash;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* always get broadcast frames */
|
if (multicast != ar->want_mc_hash) {
|
||||||
mchash = 1ULL << (0xff >> 2);
|
ar->want_mc_hash = multicast;
|
||||||
|
|
||||||
for (i = 0; i < mc_count; i++) {
|
|
||||||
if (WARN_ON(!mclist))
|
|
||||||
break;
|
|
||||||
mchash |= 1ULL << (mclist->dmi_addr[5] >> 2);
|
|
||||||
mclist = mclist->next;
|
|
||||||
}
|
|
||||||
ar->want_mc_hash = mchash;
|
|
||||||
}
|
|
||||||
set_bit(AR9170_FILTER_CHANGED_MULTICAST, &ar->filter_changed);
|
set_bit(AR9170_FILTER_CHANGED_MULTICAST, &ar->filter_changed);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2543,6 +2549,7 @@ static const struct ieee80211_ops ar9170_ops = {
|
|||||||
.add_interface = ar9170_op_add_interface,
|
.add_interface = ar9170_op_add_interface,
|
||||||
.remove_interface = ar9170_op_remove_interface,
|
.remove_interface = ar9170_op_remove_interface,
|
||||||
.config = ar9170_op_config,
|
.config = ar9170_op_config,
|
||||||
|
.prepare_multicast = ar9170_op_prepare_multicast,
|
||||||
.configure_filter = ar9170_op_configure_filter,
|
.configure_filter = ar9170_op_configure_filter,
|
||||||
.conf_tx = ar9170_conf_tx,
|
.conf_tx = ar9170_conf_tx,
|
||||||
.bss_info_changed = ar9170_op_bss_info_changed,
|
.bss_info_changed = ar9170_op_bss_info_changed,
|
||||||
|
@ -229,10 +229,12 @@ static int ath5k_add_interface(struct ieee80211_hw *hw,
|
|||||||
static void ath5k_remove_interface(struct ieee80211_hw *hw,
|
static void ath5k_remove_interface(struct ieee80211_hw *hw,
|
||||||
struct ieee80211_if_init_conf *conf);
|
struct ieee80211_if_init_conf *conf);
|
||||||
static int ath5k_config(struct ieee80211_hw *hw, u32 changed);
|
static int ath5k_config(struct ieee80211_hw *hw, u32 changed);
|
||||||
|
static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw,
|
||||||
|
int mc_count, struct dev_addr_list *mc_list);
|
||||||
static void ath5k_configure_filter(struct ieee80211_hw *hw,
|
static void ath5k_configure_filter(struct ieee80211_hw *hw,
|
||||||
unsigned int changed_flags,
|
unsigned int changed_flags,
|
||||||
unsigned int *new_flags,
|
unsigned int *new_flags,
|
||||||
int mc_count, struct dev_mc_list *mclist);
|
u64 multicast);
|
||||||
static int ath5k_set_key(struct ieee80211_hw *hw,
|
static int ath5k_set_key(struct ieee80211_hw *hw,
|
||||||
enum set_key_cmd cmd,
|
enum set_key_cmd cmd,
|
||||||
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
|
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
|
||||||
@ -260,6 +262,7 @@ static const struct ieee80211_ops ath5k_hw_ops = {
|
|||||||
.add_interface = ath5k_add_interface,
|
.add_interface = ath5k_add_interface,
|
||||||
.remove_interface = ath5k_remove_interface,
|
.remove_interface = ath5k_remove_interface,
|
||||||
.config = ath5k_config,
|
.config = ath5k_config,
|
||||||
|
.prepare_multicast = ath5k_prepare_multicast,
|
||||||
.configure_filter = ath5k_configure_filter,
|
.configure_filter = ath5k_configure_filter,
|
||||||
.set_key = ath5k_set_key,
|
.set_key = ath5k_set_key,
|
||||||
.get_stats = ath5k_get_stats,
|
.get_stats = ath5k_get_stats,
|
||||||
@ -2853,6 +2856,37 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw,
|
||||||
|
int mc_count, struct dev_addr_list *mclist)
|
||||||
|
{
|
||||||
|
u32 mfilt[2], val;
|
||||||
|
int i;
|
||||||
|
u8 pos;
|
||||||
|
|
||||||
|
mfilt[0] = 0;
|
||||||
|
mfilt[1] = 1;
|
||||||
|
|
||||||
|
for (i = 0; i < mc_count; i++) {
|
||||||
|
if (!mclist)
|
||||||
|
break;
|
||||||
|
/* calculate XOR of eight 6-bit values */
|
||||||
|
val = get_unaligned_le32(mclist->dmi_addr + 0);
|
||||||
|
pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
|
||||||
|
val = get_unaligned_le32(mclist->dmi_addr + 3);
|
||||||
|
pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
|
||||||
|
pos &= 0x3f;
|
||||||
|
mfilt[pos / 32] |= (1 << (pos % 32));
|
||||||
|
/* XXX: we might be able to just do this instead,
|
||||||
|
* but not sure, needs testing, if we do use this we'd
|
||||||
|
* neet to inform below to not reset the mcast */
|
||||||
|
/* ath5k_hw_set_mcast_filterindex(ah,
|
||||||
|
* mclist->dmi_addr[5]); */
|
||||||
|
mclist = mclist->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ((u64)(mfilt[1]) << 32) | mfilt[0];
|
||||||
|
}
|
||||||
|
|
||||||
#define SUPPORTED_FIF_FLAGS \
|
#define SUPPORTED_FIF_FLAGS \
|
||||||
FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | \
|
FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | \
|
||||||
FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \
|
FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \
|
||||||
@ -2878,16 +2912,14 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed)
|
|||||||
static void ath5k_configure_filter(struct ieee80211_hw *hw,
|
static void ath5k_configure_filter(struct ieee80211_hw *hw,
|
||||||
unsigned int changed_flags,
|
unsigned int changed_flags,
|
||||||
unsigned int *new_flags,
|
unsigned int *new_flags,
|
||||||
int mc_count, struct dev_mc_list *mclist)
|
u64 multicast)
|
||||||
{
|
{
|
||||||
struct ath5k_softc *sc = hw->priv;
|
struct ath5k_softc *sc = hw->priv;
|
||||||
struct ath5k_hw *ah = sc->ah;
|
struct ath5k_hw *ah = sc->ah;
|
||||||
u32 mfilt[2], val, rfilt;
|
u32 mfilt[2], rfilt;
|
||||||
u8 pos;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
mfilt[0] = 0;
|
mfilt[0] = multicast;
|
||||||
mfilt[1] = 0;
|
mfilt[1] = multicast >> 32;
|
||||||
|
|
||||||
/* Only deal with supported flags */
|
/* Only deal with supported flags */
|
||||||
changed_flags &= SUPPORTED_FIF_FLAGS;
|
changed_flags &= SUPPORTED_FIF_FLAGS;
|
||||||
@ -2913,24 +2945,6 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw,
|
|||||||
if (*new_flags & FIF_ALLMULTI) {
|
if (*new_flags & FIF_ALLMULTI) {
|
||||||
mfilt[0] = ~0;
|
mfilt[0] = ~0;
|
||||||
mfilt[1] = ~0;
|
mfilt[1] = ~0;
|
||||||
} else {
|
|
||||||
for (i = 0; i < mc_count; i++) {
|
|
||||||
if (!mclist)
|
|
||||||
break;
|
|
||||||
/* calculate XOR of eight 6-bit values */
|
|
||||||
val = get_unaligned_le32(mclist->dmi_addr + 0);
|
|
||||||
pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
|
|
||||||
val = get_unaligned_le32(mclist->dmi_addr + 3);
|
|
||||||
pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
|
|
||||||
pos &= 0x3f;
|
|
||||||
mfilt[pos / 32] |= (1 << (pos % 32));
|
|
||||||
/* XXX: we might be able to just do this instead,
|
|
||||||
* but not sure, needs testing, if we do use this we'd
|
|
||||||
* neet to inform below to not reset the mcast */
|
|
||||||
/* ath5k_hw_set_mcast_filterindex(ah,
|
|
||||||
* mclist->dmi_addr[5]); */
|
|
||||||
mclist = mclist->next;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is the best we can do */
|
/* This is the best we can do */
|
||||||
|
@ -2394,8 +2394,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
|
|||||||
static void ath9k_configure_filter(struct ieee80211_hw *hw,
|
static void ath9k_configure_filter(struct ieee80211_hw *hw,
|
||||||
unsigned int changed_flags,
|
unsigned int changed_flags,
|
||||||
unsigned int *total_flags,
|
unsigned int *total_flags,
|
||||||
int mc_count,
|
u64 multicast)
|
||||||
struct dev_mc_list *mclist)
|
|
||||||
{
|
{
|
||||||
struct ath_wiphy *aphy = hw->priv;
|
struct ath_wiphy *aphy = hw->priv;
|
||||||
struct ath_softc *sc = aphy->sc;
|
struct ath_softc *sc = aphy->sc;
|
||||||
|
@ -3679,7 +3679,7 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
|||||||
|
|
||||||
static void b43_op_configure_filter(struct ieee80211_hw *hw,
|
static void b43_op_configure_filter(struct ieee80211_hw *hw,
|
||||||
unsigned int changed, unsigned int *fflags,
|
unsigned int changed, unsigned int *fflags,
|
||||||
int mc_count, struct dev_addr_list *mc_list)
|
u64 multicast)
|
||||||
{
|
{
|
||||||
struct b43_wl *wl = hw_to_b43_wl(hw);
|
struct b43_wl *wl = hw_to_b43_wl(hw);
|
||||||
struct b43_wldev *dev = wl->current_dev;
|
struct b43_wldev *dev = wl->current_dev;
|
||||||
|
@ -2836,9 +2836,7 @@ static void b43legacy_op_bss_info_changed(struct ieee80211_hw *hw,
|
|||||||
|
|
||||||
static void b43legacy_op_configure_filter(struct ieee80211_hw *hw,
|
static void b43legacy_op_configure_filter(struct ieee80211_hw *hw,
|
||||||
unsigned int changed,
|
unsigned int changed,
|
||||||
unsigned int *fflags,
|
unsigned int *fflags,u64 multicast)
|
||||||
int mc_count,
|
|
||||||
struct dev_addr_list *mc_list)
|
|
||||||
{
|
{
|
||||||
struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
|
struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
|
||||||
struct b43legacy_wldev *dev = wl->current_dev;
|
struct b43legacy_wldev *dev = wl->current_dev;
|
||||||
|
@ -1514,7 +1514,7 @@ EXPORT_SYMBOL(iwl_irq_handle_error);
|
|||||||
void iwl_configure_filter(struct ieee80211_hw *hw,
|
void iwl_configure_filter(struct ieee80211_hw *hw,
|
||||||
unsigned int changed_flags,
|
unsigned int changed_flags,
|
||||||
unsigned int *total_flags,
|
unsigned int *total_flags,
|
||||||
int mc_count, struct dev_addr_list *mc_list)
|
u64 multicast)
|
||||||
{
|
{
|
||||||
struct iwl_priv *priv = hw->priv;
|
struct iwl_priv *priv = hw->priv;
|
||||||
__le32 *filter_flags = &priv->staging_rxon.filter_flags;
|
__le32 *filter_flags = &priv->staging_rxon.filter_flags;
|
||||||
|
@ -282,8 +282,7 @@ int iwl_set_decrypted_flag(struct iwl_priv *priv,
|
|||||||
void iwl_irq_handle_error(struct iwl_priv *priv);
|
void iwl_irq_handle_error(struct iwl_priv *priv);
|
||||||
void iwl_configure_filter(struct ieee80211_hw *hw,
|
void iwl_configure_filter(struct ieee80211_hw *hw,
|
||||||
unsigned int changed_flags,
|
unsigned int changed_flags,
|
||||||
unsigned int *total_flags,
|
unsigned int *total_flags, u64 multicast);
|
||||||
int mc_count, struct dev_addr_list *mc_list);
|
|
||||||
int iwl_hw_nic_init(struct iwl_priv *priv);
|
int iwl_hw_nic_init(struct iwl_priv *priv);
|
||||||
int iwl_setup_mac(struct iwl_priv *priv);
|
int iwl_setup_mac(struct iwl_priv *priv);
|
||||||
int iwl_set_hw_params(struct iwl_priv *priv);
|
int iwl_set_hw_params(struct iwl_priv *priv);
|
||||||
|
@ -366,15 +366,35 @@ static int lbtf_op_config(struct ieee80211_hw *hw, u32 changed)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u64 lbtf_op_prepare_multicast(struct ieee80211_hw *hw,
|
||||||
|
int mc_count, struct dev_addr_list *mclist)
|
||||||
|
{
|
||||||
|
struct lbtf_private *priv = hw->priv;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!mc_count || mc_count > MRVDRV_MAX_MULTICAST_LIST_SIZE)
|
||||||
|
return mc_count;
|
||||||
|
|
||||||
|
priv->nr_of_multicastmacaddr = mc_count;
|
||||||
|
for (i = 0; i < mc_count; i++) {
|
||||||
|
if (!mclist)
|
||||||
|
break;
|
||||||
|
memcpy(&priv->multicastlist[i], mclist->da_addr,
|
||||||
|
ETH_ALEN);
|
||||||
|
mclist = mclist->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mc_count;
|
||||||
|
}
|
||||||
|
|
||||||
#define SUPPORTED_FIF_FLAGS (FIF_PROMISC_IN_BSS | FIF_ALLMULTI)
|
#define SUPPORTED_FIF_FLAGS (FIF_PROMISC_IN_BSS | FIF_ALLMULTI)
|
||||||
static void lbtf_op_configure_filter(struct ieee80211_hw *hw,
|
static void lbtf_op_configure_filter(struct ieee80211_hw *hw,
|
||||||
unsigned int changed_flags,
|
unsigned int changed_flags,
|
||||||
unsigned int *new_flags,
|
unsigned int *new_flags,
|
||||||
int mc_count, struct dev_mc_list *mclist)
|
u64 multicast)
|
||||||
{
|
{
|
||||||
struct lbtf_private *priv = hw->priv;
|
struct lbtf_private *priv = hw->priv;
|
||||||
int old_mac_control = priv->mac_control;
|
int old_mac_control = priv->mac_control;
|
||||||
int i;
|
|
||||||
changed_flags &= SUPPORTED_FIF_FLAGS;
|
changed_flags &= SUPPORTED_FIF_FLAGS;
|
||||||
*new_flags &= SUPPORTED_FIF_FLAGS;
|
*new_flags &= SUPPORTED_FIF_FLAGS;
|
||||||
|
|
||||||
@ -386,20 +406,12 @@ static void lbtf_op_configure_filter(struct ieee80211_hw *hw,
|
|||||||
else
|
else
|
||||||
priv->mac_control &= ~CMD_ACT_MAC_PROMISCUOUS_ENABLE;
|
priv->mac_control &= ~CMD_ACT_MAC_PROMISCUOUS_ENABLE;
|
||||||
if (*new_flags & (FIF_ALLMULTI) ||
|
if (*new_flags & (FIF_ALLMULTI) ||
|
||||||
mc_count > MRVDRV_MAX_MULTICAST_LIST_SIZE) {
|
multicast > MRVDRV_MAX_MULTICAST_LIST_SIZE) {
|
||||||
priv->mac_control |= CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
|
priv->mac_control |= CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
|
||||||
priv->mac_control &= ~CMD_ACT_MAC_MULTICAST_ENABLE;
|
priv->mac_control &= ~CMD_ACT_MAC_MULTICAST_ENABLE;
|
||||||
} else if (mc_count) {
|
} else if (multicast) {
|
||||||
priv->mac_control |= CMD_ACT_MAC_MULTICAST_ENABLE;
|
priv->mac_control |= CMD_ACT_MAC_MULTICAST_ENABLE;
|
||||||
priv->mac_control &= ~CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
|
priv->mac_control &= ~CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
|
||||||
priv->nr_of_multicastmacaddr = mc_count;
|
|
||||||
for (i = 0; i < mc_count; i++) {
|
|
||||||
if (!mclist)
|
|
||||||
break;
|
|
||||||
memcpy(&priv->multicastlist[i], mclist->da_addr,
|
|
||||||
ETH_ALEN);
|
|
||||||
mclist = mclist->next;
|
|
||||||
}
|
|
||||||
lbtf_cmd_set_mac_multicast_addr(priv);
|
lbtf_cmd_set_mac_multicast_addr(priv);
|
||||||
} else {
|
} else {
|
||||||
priv->mac_control &= ~(CMD_ACT_MAC_MULTICAST_ENABLE |
|
priv->mac_control &= ~(CMD_ACT_MAC_MULTICAST_ENABLE |
|
||||||
@ -461,6 +473,7 @@ static const struct ieee80211_ops lbtf_ops = {
|
|||||||
.add_interface = lbtf_op_add_interface,
|
.add_interface = lbtf_op_add_interface,
|
||||||
.remove_interface = lbtf_op_remove_interface,
|
.remove_interface = lbtf_op_remove_interface,
|
||||||
.config = lbtf_op_config,
|
.config = lbtf_op_config,
|
||||||
|
.prepare_multicast = lbtf_op_prepare_multicast,
|
||||||
.configure_filter = lbtf_op_configure_filter,
|
.configure_filter = lbtf_op_configure_filter,
|
||||||
.bss_info_changed = lbtf_op_bss_info_changed,
|
.bss_info_changed = lbtf_op_bss_info_changed,
|
||||||
};
|
};
|
||||||
|
@ -582,9 +582,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
|
|||||||
|
|
||||||
static void mac80211_hwsim_configure_filter(struct ieee80211_hw *hw,
|
static void mac80211_hwsim_configure_filter(struct ieee80211_hw *hw,
|
||||||
unsigned int changed_flags,
|
unsigned int changed_flags,
|
||||||
unsigned int *total_flags,
|
unsigned int *total_flags,u64 multicast)
|
||||||
int mc_count,
|
|
||||||
struct dev_addr_list *mc_list)
|
|
||||||
{
|
{
|
||||||
struct mac80211_hwsim_data *data = hw->priv;
|
struct mac80211_hwsim_data *data = hw->priv;
|
||||||
|
|
||||||
|
@ -3251,31 +3251,50 @@ static int mwl8k_configure_filter_wt(struct work_struct *wt)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw,
|
||||||
|
int mc_count, struct dev_addr_list *mclist)
|
||||||
|
{
|
||||||
|
struct mwl8k_configure_filter_worker *worker;
|
||||||
|
|
||||||
|
worker = kzalloc(sizeof(*worker), GFP_ATOMIC);
|
||||||
|
|
||||||
|
if (!worker)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXX: This is _HORRIBLY_ broken!!
|
||||||
|
*
|
||||||
|
* No locking, the mclist pointer might be invalid as soon as this
|
||||||
|
* function returns, something in the list might be invalidated
|
||||||
|
* once we get to the worker, etc...
|
||||||
|
*/
|
||||||
|
worker->mc_count = mc_count;
|
||||||
|
worker->mclist = mclist;
|
||||||
|
|
||||||
|
return (u64)worker;
|
||||||
|
}
|
||||||
|
|
||||||
static void mwl8k_configure_filter(struct ieee80211_hw *hw,
|
static void mwl8k_configure_filter(struct ieee80211_hw *hw,
|
||||||
unsigned int changed_flags,
|
unsigned int changed_flags,
|
||||||
unsigned int *total_flags,
|
unsigned int *total_flags,
|
||||||
int mc_count,
|
u64 multicast)
|
||||||
struct dev_addr_list *mclist)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
struct mwl8k_configure_filter_worker *worker;
|
struct mwl8k_configure_filter_worker *worker = (void *)multicast;
|
||||||
struct mwl8k_priv *priv = hw->priv;
|
struct mwl8k_priv *priv = hw->priv;
|
||||||
|
|
||||||
/* Clear unsupported feature flags */
|
/* Clear unsupported feature flags */
|
||||||
*total_flags &= MWL8K_SUPPORTED_IF_FLAGS;
|
*total_flags &= MWL8K_SUPPORTED_IF_FLAGS;
|
||||||
|
|
||||||
if (!(changed_flags & MWL8K_SUPPORTED_IF_FLAGS) && !mc_count)
|
if (!(changed_flags & MWL8K_SUPPORTED_IF_FLAGS))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
worker = kzalloc(sizeof(*worker), GFP_ATOMIC);
|
|
||||||
if (worker == NULL)
|
if (worker == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
worker->header.options = MWL8K_WQ_QUEUE_ONLY | MWL8K_WQ_TX_WAIT_EMPTY;
|
worker->header.options = MWL8K_WQ_QUEUE_ONLY | MWL8K_WQ_TX_WAIT_EMPTY;
|
||||||
worker->changed_flags = changed_flags;
|
worker->changed_flags = changed_flags;
|
||||||
worker->total_flags = total_flags;
|
worker->total_flags = total_flags;
|
||||||
worker->mc_count = mc_count;
|
|
||||||
worker->mclist = mclist;
|
|
||||||
|
|
||||||
mwl8k_queue_work(hw, &worker->header, priv->config_wq,
|
mwl8k_queue_work(hw, &worker->header, priv->config_wq,
|
||||||
mwl8k_configure_filter_wt);
|
mwl8k_configure_filter_wt);
|
||||||
@ -3441,6 +3460,7 @@ static const struct ieee80211_ops mwl8k_ops = {
|
|||||||
.remove_interface = mwl8k_remove_interface,
|
.remove_interface = mwl8k_remove_interface,
|
||||||
.config = mwl8k_config,
|
.config = mwl8k_config,
|
||||||
.bss_info_changed = mwl8k_bss_info_changed,
|
.bss_info_changed = mwl8k_bss_info_changed,
|
||||||
|
.prepare_multicast = mwl8k_prepare_multicast,
|
||||||
.configure_filter = mwl8k_configure_filter,
|
.configure_filter = mwl8k_configure_filter,
|
||||||
.set_rts_threshold = mwl8k_set_rts_threshold,
|
.set_rts_threshold = mwl8k_set_rts_threshold,
|
||||||
.conf_tx = mwl8k_conf_tx,
|
.conf_tx = mwl8k_conf_tx,
|
||||||
|
@ -302,7 +302,7 @@ static int p54_config(struct ieee80211_hw *dev, u32 changed)
|
|||||||
static void p54_configure_filter(struct ieee80211_hw *dev,
|
static void p54_configure_filter(struct ieee80211_hw *dev,
|
||||||
unsigned int changed_flags,
|
unsigned int changed_flags,
|
||||||
unsigned int *total_flags,
|
unsigned int *total_flags,
|
||||||
int mc_count, struct dev_mc_list *mclist)
|
u64 multicast)
|
||||||
{
|
{
|
||||||
struct p54_common *priv = dev->priv;
|
struct p54_common *priv = dev->priv;
|
||||||
|
|
||||||
|
@ -978,7 +978,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed);
|
|||||||
void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
|
void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
|
||||||
unsigned int changed_flags,
|
unsigned int changed_flags,
|
||||||
unsigned int *total_flags,
|
unsigned int *total_flags,
|
||||||
int mc_count, struct dev_addr_list *mc_list);
|
u64 multicast);
|
||||||
int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
|
int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
|
||||||
bool set);
|
bool set);
|
||||||
#ifdef CONFIG_RT2X00_LIB_CRYPTO
|
#ifdef CONFIG_RT2X00_LIB_CRYPTO
|
||||||
|
@ -379,7 +379,7 @@ EXPORT_SYMBOL_GPL(rt2x00mac_config);
|
|||||||
void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
|
void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
|
||||||
unsigned int changed_flags,
|
unsigned int changed_flags,
|
||||||
unsigned int *total_flags,
|
unsigned int *total_flags,
|
||||||
int mc_count, struct dev_addr_list *mc_list)
|
u64 multicast)
|
||||||
{
|
{
|
||||||
struct rt2x00_dev *rt2x00dev = hw->priv;
|
struct rt2x00_dev *rt2x00dev = hw->priv;
|
||||||
|
|
||||||
|
@ -728,10 +728,16 @@ static void rtl8180_bss_info_changed(struct ieee80211_hw *dev,
|
|||||||
priv->rf->conf_erp(dev, info);
|
priv->rf->conf_erp(dev, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u64 rtl8180_prepare_multicast(struct ieee80211_hw *dev, int mc_count,
|
||||||
|
struct dev_addr_list *mc_list)
|
||||||
|
{
|
||||||
|
return mc_count;
|
||||||
|
}
|
||||||
|
|
||||||
static void rtl8180_configure_filter(struct ieee80211_hw *dev,
|
static void rtl8180_configure_filter(struct ieee80211_hw *dev,
|
||||||
unsigned int changed_flags,
|
unsigned int changed_flags,
|
||||||
unsigned int *total_flags,
|
unsigned int *total_flags,
|
||||||
int mc_count, struct dev_addr_list *mclist)
|
u64 multicast)
|
||||||
{
|
{
|
||||||
struct rtl8180_priv *priv = dev->priv;
|
struct rtl8180_priv *priv = dev->priv;
|
||||||
|
|
||||||
@ -741,7 +747,7 @@ static void rtl8180_configure_filter(struct ieee80211_hw *dev,
|
|||||||
priv->rx_conf ^= RTL818X_RX_CONF_CTRL;
|
priv->rx_conf ^= RTL818X_RX_CONF_CTRL;
|
||||||
if (changed_flags & FIF_OTHER_BSS)
|
if (changed_flags & FIF_OTHER_BSS)
|
||||||
priv->rx_conf ^= RTL818X_RX_CONF_MONITOR;
|
priv->rx_conf ^= RTL818X_RX_CONF_MONITOR;
|
||||||
if (*total_flags & FIF_ALLMULTI || mc_count > 0)
|
if (*total_flags & FIF_ALLMULTI || multicast > 0)
|
||||||
priv->rx_conf |= RTL818X_RX_CONF_MULTICAST;
|
priv->rx_conf |= RTL818X_RX_CONF_MULTICAST;
|
||||||
else
|
else
|
||||||
priv->rx_conf &= ~RTL818X_RX_CONF_MULTICAST;
|
priv->rx_conf &= ~RTL818X_RX_CONF_MULTICAST;
|
||||||
@ -768,6 +774,7 @@ static const struct ieee80211_ops rtl8180_ops = {
|
|||||||
.remove_interface = rtl8180_remove_interface,
|
.remove_interface = rtl8180_remove_interface,
|
||||||
.config = rtl8180_config,
|
.config = rtl8180_config,
|
||||||
.bss_info_changed = rtl8180_bss_info_changed,
|
.bss_info_changed = rtl8180_bss_info_changed,
|
||||||
|
.prepare_multicast = rtl8180_prepare_multicast,
|
||||||
.configure_filter = rtl8180_configure_filter,
|
.configure_filter = rtl8180_configure_filter,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1192,10 +1192,16 @@ static void rtl8187_bss_info_changed(struct ieee80211_hw *dev,
|
|||||||
info->use_short_preamble);
|
info->use_short_preamble);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u64 rtl8187_prepare_multicast(struct ieee80211_hw *dev,
|
||||||
|
int mc_count, struct dev_addr_list *mc_list)
|
||||||
|
{
|
||||||
|
return mc_count;
|
||||||
|
}
|
||||||
|
|
||||||
static void rtl8187_configure_filter(struct ieee80211_hw *dev,
|
static void rtl8187_configure_filter(struct ieee80211_hw *dev,
|
||||||
unsigned int changed_flags,
|
unsigned int changed_flags,
|
||||||
unsigned int *total_flags,
|
unsigned int *total_flags,
|
||||||
int mc_count, struct dev_addr_list *mclist)
|
u64 multicast)
|
||||||
{
|
{
|
||||||
struct rtl8187_priv *priv = dev->priv;
|
struct rtl8187_priv *priv = dev->priv;
|
||||||
|
|
||||||
@ -1205,7 +1211,7 @@ static void rtl8187_configure_filter(struct ieee80211_hw *dev,
|
|||||||
priv->rx_conf ^= RTL818X_RX_CONF_CTRL;
|
priv->rx_conf ^= RTL818X_RX_CONF_CTRL;
|
||||||
if (changed_flags & FIF_OTHER_BSS)
|
if (changed_flags & FIF_OTHER_BSS)
|
||||||
priv->rx_conf ^= RTL818X_RX_CONF_MONITOR;
|
priv->rx_conf ^= RTL818X_RX_CONF_MONITOR;
|
||||||
if (*total_flags & FIF_ALLMULTI || mc_count > 0)
|
if (*total_flags & FIF_ALLMULTI || multicast > 0)
|
||||||
priv->rx_conf |= RTL818X_RX_CONF_MULTICAST;
|
priv->rx_conf |= RTL818X_RX_CONF_MULTICAST;
|
||||||
else
|
else
|
||||||
priv->rx_conf &= ~RTL818X_RX_CONF_MULTICAST;
|
priv->rx_conf &= ~RTL818X_RX_CONF_MULTICAST;
|
||||||
@ -1268,6 +1274,7 @@ static const struct ieee80211_ops rtl8187_ops = {
|
|||||||
.remove_interface = rtl8187_remove_interface,
|
.remove_interface = rtl8187_remove_interface,
|
||||||
.config = rtl8187_config,
|
.config = rtl8187_config,
|
||||||
.bss_info_changed = rtl8187_bss_info_changed,
|
.bss_info_changed = rtl8187_bss_info_changed,
|
||||||
|
.prepare_multicast = rtl8187_prepare_multicast,
|
||||||
.configure_filter = rtl8187_configure_filter,
|
.configure_filter = rtl8187_configure_filter,
|
||||||
.conf_tx = rtl8187_conf_tx
|
.conf_tx = rtl8187_conf_tx
|
||||||
};
|
};
|
||||||
|
@ -652,9 +652,7 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
|
|||||||
|
|
||||||
static void wl1251_op_configure_filter(struct ieee80211_hw *hw,
|
static void wl1251_op_configure_filter(struct ieee80211_hw *hw,
|
||||||
unsigned int changed,
|
unsigned int changed,
|
||||||
unsigned int *total,
|
unsigned int *total,u64 multicast)
|
||||||
int mc_count,
|
|
||||||
struct dev_addr_list *mc_list)
|
|
||||||
{
|
{
|
||||||
struct wl1251 *wl = hw->priv;
|
struct wl1251 *wl = hw->priv;
|
||||||
|
|
||||||
|
@ -793,9 +793,7 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
|
|||||||
|
|
||||||
static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
|
static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
|
||||||
unsigned int changed,
|
unsigned int changed,
|
||||||
unsigned int *total,
|
unsigned int *total,u64 multicast)
|
||||||
int mc_count,
|
|
||||||
struct dev_addr_list *mc_list)
|
|
||||||
{
|
{
|
||||||
struct wl1271 *wl = hw->priv;
|
struct wl1271 *wl = hw->priv;
|
||||||
|
|
||||||
|
@ -796,18 +796,40 @@ static void set_rx_filter_handler(struct work_struct *work)
|
|||||||
dev_err(zd_mac_dev(mac), "set_rx_filter_handler error %d\n", r);
|
dev_err(zd_mac_dev(mac), "set_rx_filter_handler error %d\n", r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u64 zd_op_prepare_multicast(struct ieee80211_hw *hw,
|
||||||
|
int mc_count, struct dev_addr_list *mclist)
|
||||||
|
{
|
||||||
|
struct zd_mac *mac = zd_hw_mac(hw);
|
||||||
|
struct zd_mc_hash hash;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
zd_mc_clear(&hash);
|
||||||
|
|
||||||
|
for (i = 0; i < mc_count; i++) {
|
||||||
|
if (!mclist)
|
||||||
|
break;
|
||||||
|
dev_dbg_f(zd_mac_dev(mac), "mc addr %pM\n", mclist->dmi_addr);
|
||||||
|
zd_mc_add_addr(&hash, mclist->dmi_addr);
|
||||||
|
mclist = mclist->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hash.low | ((u64)hash.high << 32);
|
||||||
|
}
|
||||||
|
|
||||||
#define SUPPORTED_FIF_FLAGS \
|
#define SUPPORTED_FIF_FLAGS \
|
||||||
(FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | FIF_CONTROL | \
|
(FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | FIF_CONTROL | \
|
||||||
FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC)
|
FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC)
|
||||||
static void zd_op_configure_filter(struct ieee80211_hw *hw,
|
static void zd_op_configure_filter(struct ieee80211_hw *hw,
|
||||||
unsigned int changed_flags,
|
unsigned int changed_flags,
|
||||||
unsigned int *new_flags,
|
unsigned int *new_flags,
|
||||||
int mc_count, struct dev_mc_list *mclist)
|
u64 multicast)
|
||||||
{
|
{
|
||||||
struct zd_mc_hash hash;
|
struct zd_mc_hash hash = {
|
||||||
|
.low = multicast,
|
||||||
|
.high = multicast >> 32,
|
||||||
|
};
|
||||||
struct zd_mac *mac = zd_hw_mac(hw);
|
struct zd_mac *mac = zd_hw_mac(hw);
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int i;
|
|
||||||
|
|
||||||
/* Only deal with supported flags */
|
/* Only deal with supported flags */
|
||||||
changed_flags &= SUPPORTED_FIF_FLAGS;
|
changed_flags &= SUPPORTED_FIF_FLAGS;
|
||||||
@ -819,25 +841,16 @@ static void zd_op_configure_filter(struct ieee80211_hw *hw,
|
|||||||
if (!changed_flags)
|
if (!changed_flags)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (*new_flags & (FIF_PROMISC_IN_BSS | FIF_ALLMULTI)) {
|
if (*new_flags & (FIF_PROMISC_IN_BSS | FIF_ALLMULTI))
|
||||||
zd_mc_add_all(&hash);
|
zd_mc_add_all(&hash);
|
||||||
} else {
|
|
||||||
zd_mc_clear(&hash);
|
|
||||||
for (i = 0; i < mc_count; i++) {
|
|
||||||
if (!mclist)
|
|
||||||
break;
|
|
||||||
dev_dbg_f(zd_mac_dev(mac), "mc addr %pM\n",
|
|
||||||
mclist->dmi_addr);
|
|
||||||
zd_mc_add_addr(&hash, mclist->dmi_addr);
|
|
||||||
mclist = mclist->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
spin_lock_irqsave(&mac->lock, flags);
|
spin_lock_irqsave(&mac->lock, flags);
|
||||||
mac->pass_failed_fcs = !!(*new_flags & FIF_FCSFAIL);
|
mac->pass_failed_fcs = !!(*new_flags & FIF_FCSFAIL);
|
||||||
mac->pass_ctrl = !!(*new_flags & FIF_CONTROL);
|
mac->pass_ctrl = !!(*new_flags & FIF_CONTROL);
|
||||||
mac->multicast_hash = hash;
|
mac->multicast_hash = hash;
|
||||||
spin_unlock_irqrestore(&mac->lock, flags);
|
spin_unlock_irqrestore(&mac->lock, flags);
|
||||||
|
|
||||||
|
/* XXX: these can be called here now, can sleep now! */
|
||||||
queue_work(zd_workqueue, &mac->set_multicast_hash_work);
|
queue_work(zd_workqueue, &mac->set_multicast_hash_work);
|
||||||
|
|
||||||
if (changed_flags & FIF_CONTROL)
|
if (changed_flags & FIF_CONTROL)
|
||||||
@ -940,6 +953,7 @@ static const struct ieee80211_ops zd_ops = {
|
|||||||
.add_interface = zd_op_add_interface,
|
.add_interface = zd_op_add_interface,
|
||||||
.remove_interface = zd_op_remove_interface,
|
.remove_interface = zd_op_remove_interface,
|
||||||
.config = zd_op_config,
|
.config = zd_op_config,
|
||||||
|
.prepare_multicast = zd_op_prepare_multicast,
|
||||||
.configure_filter = zd_op_configure_filter,
|
.configure_filter = zd_op_configure_filter,
|
||||||
.bss_info_changed = zd_op_bss_info_changed,
|
.bss_info_changed = zd_op_bss_info_changed,
|
||||||
.get_tsf = zd_op_get_tsf,
|
.get_tsf = zd_op_get_tsf,
|
||||||
|
@ -1219,10 +1219,13 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw,
|
|||||||
* the driver's configure_filter() function which frames should be
|
* the driver's configure_filter() function which frames should be
|
||||||
* passed to mac80211 and which should be filtered out.
|
* passed to mac80211 and which should be filtered out.
|
||||||
*
|
*
|
||||||
* The configure_filter() callback is invoked with the parameters
|
* Before configure_filter() is invoked, the prepare_multicast()
|
||||||
* @mc_count and @mc_list for the combined multicast address list
|
* callback is invoked with the parameters @mc_count and @mc_list
|
||||||
* of all virtual interfaces, @changed_flags telling which flags
|
* for the combined multicast address list of all virtual interfaces.
|
||||||
* were changed and @total_flags with the new flag states.
|
* It's use is optional, and it returns a u64 that is passed to
|
||||||
|
* configure_filter(). Additionally, configure_filter() has the
|
||||||
|
* arguments @changed_flags telling which flags were changed and
|
||||||
|
* @total_flags with the new flag states.
|
||||||
*
|
*
|
||||||
* If your device has no multicast address filters your driver will
|
* If your device has no multicast address filters your driver will
|
||||||
* need to check both the %FIF_ALLMULTI flag and the @mc_count
|
* need to check both the %FIF_ALLMULTI flag and the @mc_count
|
||||||
@ -1375,9 +1378,13 @@ enum ieee80211_ampdu_mlme_action {
|
|||||||
* for association indication. The @changed parameter indicates which
|
* for association indication. The @changed parameter indicates which
|
||||||
* of the bss parameters has changed when a call is made.
|
* of the bss parameters has changed when a call is made.
|
||||||
*
|
*
|
||||||
|
* @prepare_multicast: Prepare for multicast filter configuration.
|
||||||
|
* This callback is optional, and its return value is passed
|
||||||
|
* to configure_filter(). This callback must be atomic.
|
||||||
|
*
|
||||||
* @configure_filter: Configure the device's RX filter.
|
* @configure_filter: Configure the device's RX filter.
|
||||||
* See the section "Frame filtering" for more information.
|
* See the section "Frame filtering" for more information.
|
||||||
* This callback must be implemented and atomic.
|
* This callback must be implemented.
|
||||||
*
|
*
|
||||||
* @set_tim: Set TIM bit. mac80211 calls this function when a TIM bit
|
* @set_tim: Set TIM bit. mac80211 calls this function when a TIM bit
|
||||||
* must be set or cleared for a given STA. Must be atomic.
|
* must be set or cleared for a given STA. Must be atomic.
|
||||||
@ -1479,10 +1486,12 @@ struct ieee80211_ops {
|
|||||||
struct ieee80211_vif *vif,
|
struct ieee80211_vif *vif,
|
||||||
struct ieee80211_bss_conf *info,
|
struct ieee80211_bss_conf *info,
|
||||||
u32 changed);
|
u32 changed);
|
||||||
|
u64 (*prepare_multicast)(struct ieee80211_hw *hw,
|
||||||
|
int mc_count, struct dev_addr_list *mc_list);
|
||||||
void (*configure_filter)(struct ieee80211_hw *hw,
|
void (*configure_filter)(struct ieee80211_hw *hw,
|
||||||
unsigned int changed_flags,
|
unsigned int changed_flags,
|
||||||
unsigned int *total_flags,
|
unsigned int *total_flags,
|
||||||
int mc_count, struct dev_addr_list *mc_list);
|
u64 multicast);
|
||||||
int (*set_tim)(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
|
int (*set_tim)(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
|
||||||
bool set);
|
bool set);
|
||||||
int (*set_key)(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
int (*set_key)(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||||||
|
@ -55,16 +55,32 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local,
|
|||||||
trace_drv_bss_info_changed(local, vif, info, changed);
|
trace_drv_bss_info_changed(local, vif, info, changed);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void drv_configure_filter(struct ieee80211_local *local,
|
static inline u64 drv_prepare_multicast(struct ieee80211_local *local,
|
||||||
unsigned int changed_flags,
|
|
||||||
unsigned int *total_flags,
|
|
||||||
int mc_count,
|
int mc_count,
|
||||||
struct dev_addr_list *mc_list)
|
struct dev_addr_list *mc_list)
|
||||||
{
|
{
|
||||||
|
u64 ret = 0;
|
||||||
|
|
||||||
|
if (local->ops->prepare_multicast)
|
||||||
|
ret = local->ops->prepare_multicast(&local->hw, mc_count,
|
||||||
|
mc_list);
|
||||||
|
|
||||||
|
trace_drv_prepare_multicast(local, mc_count, ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void drv_configure_filter(struct ieee80211_local *local,
|
||||||
|
unsigned int changed_flags,
|
||||||
|
unsigned int *total_flags,
|
||||||
|
u64 multicast)
|
||||||
|
{
|
||||||
|
might_sleep();
|
||||||
|
|
||||||
local->ops->configure_filter(&local->hw, changed_flags, total_flags,
|
local->ops->configure_filter(&local->hw, changed_flags, total_flags,
|
||||||
mc_count, mc_list);
|
multicast);
|
||||||
trace_drv_configure_filter(local, changed_flags, total_flags,
|
trace_drv_configure_filter(local, changed_flags, total_flags,
|
||||||
mc_count);
|
multicast);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int drv_set_tim(struct ieee80211_local *local,
|
static inline int drv_set_tim(struct ieee80211_local *local,
|
||||||
|
@ -191,31 +191,55 @@ TRACE_EVENT(drv_bss_info_changed,
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
TRACE_EVENT(drv_prepare_multicast,
|
||||||
|
TP_PROTO(struct ieee80211_local *local, int mc_count, u64 ret),
|
||||||
|
|
||||||
|
TP_ARGS(local, mc_count, ret),
|
||||||
|
|
||||||
|
TP_STRUCT__entry(
|
||||||
|
LOCAL_ENTRY
|
||||||
|
__field(int, mc_count)
|
||||||
|
__field(u64, ret)
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_fast_assign(
|
||||||
|
LOCAL_ASSIGN;
|
||||||
|
__entry->mc_count = mc_count;
|
||||||
|
__entry->ret = ret;
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_printk(
|
||||||
|
LOCAL_PR_FMT " prepare mc (%d): %llx",
|
||||||
|
LOCAL_PR_ARG, __entry->mc_count,
|
||||||
|
(unsigned long long) __entry->ret
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
TRACE_EVENT(drv_configure_filter,
|
TRACE_EVENT(drv_configure_filter,
|
||||||
TP_PROTO(struct ieee80211_local *local,
|
TP_PROTO(struct ieee80211_local *local,
|
||||||
unsigned int changed_flags,
|
unsigned int changed_flags,
|
||||||
unsigned int *total_flags,
|
unsigned int *total_flags,
|
||||||
int mc_count),
|
u64 multicast),
|
||||||
|
|
||||||
TP_ARGS(local, changed_flags, total_flags, mc_count),
|
TP_ARGS(local, changed_flags, total_flags, multicast),
|
||||||
|
|
||||||
TP_STRUCT__entry(
|
TP_STRUCT__entry(
|
||||||
LOCAL_ENTRY
|
LOCAL_ENTRY
|
||||||
__field(unsigned int, changed)
|
__field(unsigned int, changed)
|
||||||
__field(unsigned int, total)
|
__field(unsigned int, total)
|
||||||
__field(int, mc)
|
__field(u64, multicast)
|
||||||
),
|
),
|
||||||
|
|
||||||
TP_fast_assign(
|
TP_fast_assign(
|
||||||
LOCAL_ASSIGN;
|
LOCAL_ASSIGN;
|
||||||
__entry->changed = changed_flags;
|
__entry->changed = changed_flags;
|
||||||
__entry->total = *total_flags;
|
__entry->total = *total_flags;
|
||||||
__entry->mc = mc_count;
|
__entry->multicast = multicast;
|
||||||
),
|
),
|
||||||
|
|
||||||
TP_printk(
|
TP_printk(
|
||||||
LOCAL_PR_FMT " changed:%#x total:%#x mc:%d",
|
LOCAL_PR_FMT " changed:%#x total:%#x",
|
||||||
LOCAL_PR_ARG, __entry->changed, __entry->total, __entry->mc
|
LOCAL_PR_ARG, __entry->changed, __entry->total
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -636,6 +636,9 @@ struct ieee80211_local {
|
|||||||
/* protects the aggregated multicast list and filter calls */
|
/* protects the aggregated multicast list and filter calls */
|
||||||
spinlock_t filter_lock;
|
spinlock_t filter_lock;
|
||||||
|
|
||||||
|
/* used for uploading changed mc list */
|
||||||
|
struct work_struct reconfig_filter;
|
||||||
|
|
||||||
/* aggregated multicast list */
|
/* aggregated multicast list */
|
||||||
struct dev_addr_list *mc_list;
|
struct dev_addr_list *mc_list;
|
||||||
int mc_count;
|
int mc_count;
|
||||||
|
@ -227,9 +227,7 @@ static int ieee80211_open(struct net_device *dev)
|
|||||||
if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
|
if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
|
||||||
local->fif_other_bss++;
|
local->fif_other_bss++;
|
||||||
|
|
||||||
spin_lock_bh(&local->filter_lock);
|
|
||||||
ieee80211_configure_filter(local);
|
ieee80211_configure_filter(local);
|
||||||
spin_unlock_bh(&local->filter_lock);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
conf.vif = &sdata->vif;
|
conf.vif = &sdata->vif;
|
||||||
@ -241,17 +239,13 @@ static int ieee80211_open(struct net_device *dev)
|
|||||||
|
|
||||||
if (ieee80211_vif_is_mesh(&sdata->vif)) {
|
if (ieee80211_vif_is_mesh(&sdata->vif)) {
|
||||||
local->fif_other_bss++;
|
local->fif_other_bss++;
|
||||||
spin_lock_bh(&local->filter_lock);
|
|
||||||
ieee80211_configure_filter(local);
|
ieee80211_configure_filter(local);
|
||||||
spin_unlock_bh(&local->filter_lock);
|
|
||||||
|
|
||||||
ieee80211_start_mesh(sdata);
|
ieee80211_start_mesh(sdata);
|
||||||
} else if (sdata->vif.type == NL80211_IFTYPE_AP) {
|
} else if (sdata->vif.type == NL80211_IFTYPE_AP) {
|
||||||
local->fif_pspoll++;
|
local->fif_pspoll++;
|
||||||
|
|
||||||
spin_lock_bh(&local->filter_lock);
|
|
||||||
ieee80211_configure_filter(local);
|
ieee80211_configure_filter(local);
|
||||||
spin_unlock_bh(&local->filter_lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
changed |= ieee80211_reset_erp_info(sdata);
|
changed |= ieee80211_reset_erp_info(sdata);
|
||||||
@ -404,10 +398,11 @@ static int ieee80211_stop(struct net_device *dev)
|
|||||||
spin_lock_bh(&local->filter_lock);
|
spin_lock_bh(&local->filter_lock);
|
||||||
__dev_addr_unsync(&local->mc_list, &local->mc_count,
|
__dev_addr_unsync(&local->mc_list, &local->mc_count,
|
||||||
&dev->mc_list, &dev->mc_count);
|
&dev->mc_list, &dev->mc_count);
|
||||||
ieee80211_configure_filter(local);
|
|
||||||
spin_unlock_bh(&local->filter_lock);
|
spin_unlock_bh(&local->filter_lock);
|
||||||
netif_addr_unlock_bh(dev);
|
netif_addr_unlock_bh(dev);
|
||||||
|
|
||||||
|
ieee80211_configure_filter(local);
|
||||||
|
|
||||||
del_timer_sync(&local->dynamic_ps_timer);
|
del_timer_sync(&local->dynamic_ps_timer);
|
||||||
cancel_work_sync(&local->dynamic_ps_enable_work);
|
cancel_work_sync(&local->dynamic_ps_enable_work);
|
||||||
|
|
||||||
@ -458,9 +453,7 @@ static int ieee80211_stop(struct net_device *dev)
|
|||||||
if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
|
if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
|
||||||
local->fif_other_bss--;
|
local->fif_other_bss--;
|
||||||
|
|
||||||
spin_lock_bh(&local->filter_lock);
|
|
||||||
ieee80211_configure_filter(local);
|
ieee80211_configure_filter(local);
|
||||||
spin_unlock_bh(&local->filter_lock);
|
|
||||||
break;
|
break;
|
||||||
case NL80211_IFTYPE_STATION:
|
case NL80211_IFTYPE_STATION:
|
||||||
del_timer_sync(&sdata->u.mgd.chswitch_timer);
|
del_timer_sync(&sdata->u.mgd.chswitch_timer);
|
||||||
@ -503,9 +496,7 @@ static int ieee80211_stop(struct net_device *dev)
|
|||||||
local->fif_other_bss--;
|
local->fif_other_bss--;
|
||||||
atomic_dec(&local->iff_allmultis);
|
atomic_dec(&local->iff_allmultis);
|
||||||
|
|
||||||
spin_lock_bh(&local->filter_lock);
|
|
||||||
ieee80211_configure_filter(local);
|
ieee80211_configure_filter(local);
|
||||||
spin_unlock_bh(&local->filter_lock);
|
|
||||||
|
|
||||||
ieee80211_stop_mesh(sdata);
|
ieee80211_stop_mesh(sdata);
|
||||||
}
|
}
|
||||||
@ -622,8 +613,8 @@ static void ieee80211_set_multicast_list(struct net_device *dev)
|
|||||||
spin_lock_bh(&local->filter_lock);
|
spin_lock_bh(&local->filter_lock);
|
||||||
__dev_addr_sync(&local->mc_list, &local->mc_count,
|
__dev_addr_sync(&local->mc_list, &local->mc_count,
|
||||||
&dev->mc_list, &dev->mc_count);
|
&dev->mc_list, &dev->mc_count);
|
||||||
ieee80211_configure_filter(local);
|
|
||||||
spin_unlock_bh(&local->filter_lock);
|
spin_unlock_bh(&local->filter_lock);
|
||||||
|
ieee80211_queue_work(&local->hw, &local->reconfig_filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -50,9 +50,9 @@ struct ieee80211_tx_status_rtap_hdr {
|
|||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
|
||||||
/* must be called under mdev tx lock */
|
|
||||||
void ieee80211_configure_filter(struct ieee80211_local *local)
|
void ieee80211_configure_filter(struct ieee80211_local *local)
|
||||||
{
|
{
|
||||||
|
u64 mc;
|
||||||
unsigned int changed_flags;
|
unsigned int changed_flags;
|
||||||
unsigned int new_flags = 0;
|
unsigned int new_flags = 0;
|
||||||
|
|
||||||
@ -62,7 +62,7 @@ void ieee80211_configure_filter(struct ieee80211_local *local)
|
|||||||
if (atomic_read(&local->iff_allmultis))
|
if (atomic_read(&local->iff_allmultis))
|
||||||
new_flags |= FIF_ALLMULTI;
|
new_flags |= FIF_ALLMULTI;
|
||||||
|
|
||||||
if (local->monitors)
|
if (local->monitors || local->scanning)
|
||||||
new_flags |= FIF_BCN_PRBRESP_PROMISC;
|
new_flags |= FIF_BCN_PRBRESP_PROMISC;
|
||||||
|
|
||||||
if (local->fif_fcsfail)
|
if (local->fif_fcsfail)
|
||||||
@ -80,20 +80,30 @@ void ieee80211_configure_filter(struct ieee80211_local *local)
|
|||||||
if (local->fif_pspoll)
|
if (local->fif_pspoll)
|
||||||
new_flags |= FIF_PSPOLL;
|
new_flags |= FIF_PSPOLL;
|
||||||
|
|
||||||
|
spin_lock_bh(&local->filter_lock);
|
||||||
changed_flags = local->filter_flags ^ new_flags;
|
changed_flags = local->filter_flags ^ new_flags;
|
||||||
|
|
||||||
|
mc = drv_prepare_multicast(local, local->mc_count, local->mc_list);
|
||||||
|
spin_unlock_bh(&local->filter_lock);
|
||||||
|
|
||||||
/* be a bit nasty */
|
/* be a bit nasty */
|
||||||
new_flags |= (1<<31);
|
new_flags |= (1<<31);
|
||||||
|
|
||||||
drv_configure_filter(local, changed_flags, &new_flags,
|
drv_configure_filter(local, changed_flags, &new_flags, mc);
|
||||||
local->mc_count,
|
|
||||||
local->mc_list);
|
|
||||||
|
|
||||||
WARN_ON(new_flags & (1<<31));
|
WARN_ON(new_flags & (1<<31));
|
||||||
|
|
||||||
local->filter_flags = new_flags & ~(1<<31);
|
local->filter_flags = new_flags & ~(1<<31);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ieee80211_reconfig_filter(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct ieee80211_local *local =
|
||||||
|
container_of(work, struct ieee80211_local, reconfig_filter);
|
||||||
|
|
||||||
|
ieee80211_configure_filter(local);
|
||||||
|
}
|
||||||
|
|
||||||
int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
|
int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
|
||||||
{
|
{
|
||||||
struct ieee80211_channel *chan, *scan_chan;
|
struct ieee80211_channel *chan, *scan_chan;
|
||||||
@ -692,6 +702,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
|
|||||||
|
|
||||||
INIT_WORK(&local->restart_work, ieee80211_restart_work);
|
INIT_WORK(&local->restart_work, ieee80211_restart_work);
|
||||||
|
|
||||||
|
INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter);
|
||||||
|
|
||||||
INIT_WORK(&local->dynamic_ps_enable_work,
|
INIT_WORK(&local->dynamic_ps_enable_work,
|
||||||
ieee80211_dynamic_ps_enable_work);
|
ieee80211_dynamic_ps_enable_work);
|
||||||
INIT_WORK(&local->dynamic_ps_disable_work,
|
INIT_WORK(&local->dynamic_ps_disable_work,
|
||||||
@ -946,6 +958,8 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
|
|||||||
|
|
||||||
rtnl_unlock();
|
rtnl_unlock();
|
||||||
|
|
||||||
|
cancel_work_sync(&local->reconfig_filter);
|
||||||
|
|
||||||
ieee80211_clear_tx_pending(local);
|
ieee80211_clear_tx_pending(local);
|
||||||
sta_info_stop(local);
|
sta_info_stop(local);
|
||||||
rate_control_deinitialize(local);
|
rate_control_deinitialize(local);
|
||||||
|
@ -292,13 +292,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
|
|||||||
if (was_hw_scan)
|
if (was_hw_scan)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
spin_lock_bh(&local->filter_lock);
|
ieee80211_configure_filter(local);
|
||||||
local->filter_flags &= ~FIF_BCN_PRBRESP_PROMISC;
|
|
||||||
drv_configure_filter(local, FIF_BCN_PRBRESP_PROMISC,
|
|
||||||
&local->filter_flags,
|
|
||||||
local->mc_count,
|
|
||||||
local->mc_list);
|
|
||||||
spin_unlock_bh(&local->filter_lock);
|
|
||||||
|
|
||||||
drv_sw_scan_complete(local);
|
drv_sw_scan_complete(local);
|
||||||
|
|
||||||
@ -376,13 +370,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
|
|||||||
local->next_scan_state = SCAN_DECISION;
|
local->next_scan_state = SCAN_DECISION;
|
||||||
local->scan_channel_idx = 0;
|
local->scan_channel_idx = 0;
|
||||||
|
|
||||||
spin_lock_bh(&local->filter_lock);
|
ieee80211_configure_filter(local);
|
||||||
local->filter_flags |= FIF_BCN_PRBRESP_PROMISC;
|
|
||||||
drv_configure_filter(local, FIF_BCN_PRBRESP_PROMISC,
|
|
||||||
&local->filter_flags,
|
|
||||||
local->mc_count,
|
|
||||||
local->mc_list);
|
|
||||||
spin_unlock_bh(&local->filter_lock);
|
|
||||||
|
|
||||||
/* TODO: start scan as soon as all nullfunc frames are ACKed */
|
/* TODO: start scan as soon as all nullfunc frames are ACKed */
|
||||||
ieee80211_queue_delayed_work(&local->hw,
|
ieee80211_queue_delayed_work(&local->hw,
|
||||||
|
@ -1076,9 +1076,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
|
|||||||
/* reconfigure hardware */
|
/* reconfigure hardware */
|
||||||
ieee80211_hw_config(local, ~0);
|
ieee80211_hw_config(local, ~0);
|
||||||
|
|
||||||
spin_lock_bh(&local->filter_lock);
|
|
||||||
ieee80211_configure_filter(local);
|
ieee80211_configure_filter(local);
|
||||||
spin_unlock_bh(&local->filter_lock);
|
|
||||||
|
|
||||||
/* Finally also reconfigure all the BSS information */
|
/* Finally also reconfigure all the BSS information */
|
||||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||||
|
Loading…
Reference in New Issue
Block a user