diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2007-09-17 01:29:23 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-10-10 16:52:57 -0700 |
commit | 4150c57212ad134765dd78c654a4b9906252b66d (patch) | |
tree | c37ab7a3f75532a623ed00339782d769514422d2 | |
parent | 070ac3a2651e3c1c4d277c5f1981517427c386a7 (diff) |
[PATCH] mac80211: revamp interface and filter configuration
Drivers are currently supposed to keep track of monitor
interfaces if they allow so-called "hard" monitor, and
they are also supposed to keep track of multicast etc.
This patch changes that, replaces the set_multicast_list()
callback with a new configure_filter() callback that takes
filter flags (FIF_*) instead of interface flags (IFF_*).
For a driver, this means it should open the filter as much
as necessary to get all frames requested by the filter flags.
Accordingly, the filter flags are named "positively", e.g.
FIF_ALLMULTI.
Multicast filtering is a bit special in that drivers that
have no multicast address filters need to allow multicast
frames through when either the FIF_ALLMULTI flag is set or
when the mc_count value is positive.
At the same time, drivers are no longer notified about
monitor interfaces at all, this means they now need to
implement the start() and stop() callbacks and the new
change_filter_flags() callback. Also, the start()/stop()
ordering changed, start() is now called *before* any
add_interface() as it really should be, and stop() after
any remove_interface().
The patch also changes the behaviour of setting the bssid
to multicast for scanning when IEEE80211_HW_NO_PROBE_FILTERING
is set; the IEEE80211_HW_NO_PROBE_FILTERING flag is removed
and the filter flag FIF_BCN_PRBRESP_PROMISC introduced.
This is a lot more efficient for hardware like b43 that
supports it and other hardware can still set the BSSID
to all-ones.
Driver modifications by Johannes Berg (b43 & iwlwifi), Michael Wu
(rtl8187, adm8211, and p54), Larry Finger (b43legacy), and
Ivo van Doorn (rt2x00).
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Michael Wu <flamingice@sourmilk.net>
Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
34 files changed, 1383 insertions, 1267 deletions
diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index ac2ea237019d..49a6b9eda4ea 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -281,49 +281,6 @@ static int adm8211_get_stats(struct ieee80211_hw *dev, return 0; } -static void adm8211_set_rx_mode(struct ieee80211_hw *dev, - unsigned short flags, int mc_count) -{ - struct adm8211_priv *priv = dev->priv; - unsigned int bit_nr; - u32 mc_filter[2]; - struct dev_mc_list *mclist; - void *tmp; - - if (flags & IFF_PROMISC) { - priv->nar |= ADM8211_NAR_PR; - priv->nar &= ~ADM8211_NAR_MM; - mc_filter[1] = mc_filter[0] = ~0; - } else if ((flags & IFF_ALLMULTI) || (mc_count > -1)) { - priv->nar &= ~ADM8211_NAR_PR; - priv->nar |= ADM8211_NAR_MM; - mc_filter[1] = mc_filter[0] = ~0; - } else { - priv->nar &= ~(ADM8211_NAR_MM | ADM8211_NAR_PR); - mc_filter[1] = mc_filter[0] = 0; - mclist = NULL; - while ((mclist = ieee80211_get_mc_list_item(dev, mclist, &tmp))) { - bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; - - bit_nr &= 0x3F; - mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); - } - } - - ADM8211_IDLE_RX(); - - ADM8211_CSR_WRITE(MAR0, mc_filter[0]); - ADM8211_CSR_WRITE(MAR1, mc_filter[1]); - ADM8211_CSR_READ(NAR); - - if (flags & IFF_PROMISC) - dev->flags |= IEEE80211_HW_RX_INCLUDES_FCS; - else - dev->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS; - - ADM8211_RESTORE(); -} - static int adm8211_get_tx_stats(struct ieee80211_hw *dev, struct ieee80211_tx_queue_stats *stats) { @@ -1254,13 +1211,6 @@ static void adm8211_hw_init(struct ieee80211_hw *dev) /* Clear the missed-packet counter. */ ADM8211_CSR_READ(LPC); - - if (!priv->mac_addr) - return; - - /* set mac address */ - ADM8211_CSR_WRITE(PAR0, *(u32 *)priv->mac_addr); - ADM8211_CSR_WRITE(PAR1, *(u16 *)&priv->mac_addr[4]); } static int adm8211_hw_reset(struct ieee80211_hw *dev) @@ -1334,7 +1284,7 @@ static void adm8211_set_interval(struct ieee80211_hw *dev, ADM8211_CSR_WRITE(BPLI, reg); } -static void adm8211_set_bssid(struct ieee80211_hw *dev, u8 *bssid) +static void adm8211_set_bssid(struct ieee80211_hw *dev, const u8 *bssid) { struct adm8211_priv *priv = dev->priv; u32 reg; @@ -1395,24 +1345,87 @@ static int adm8211_config_interface(struct ieee80211_hw *dev, int if_id, return 0; } +static void adm8211_configure_filter(struct ieee80211_hw *dev, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, struct dev_mc_list *mclist) +{ + static const u8 bcast[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + struct adm8211_priv *priv = dev->priv; + unsigned int bit_nr, new_flags; + u32 mc_filter[2]; + int i; + + new_flags = 0; + + if (*total_flags & FIF_PROMISC_IN_BSS) { + new_flags |= FIF_PROMISC_IN_BSS; + priv->nar |= ADM8211_NAR_PR; + priv->nar &= ~ADM8211_NAR_MM; + mc_filter[1] = mc_filter[0] = ~0; + } else if ((*total_flags & FIF_ALLMULTI) || (mc_count > 32)) { + new_flags |= FIF_ALLMULTI; + priv->nar &= ~ADM8211_NAR_PR; + priv->nar |= ADM8211_NAR_MM; + mc_filter[1] = mc_filter[0] = ~0; + } else { + 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_CSR_WRITE(MAR0, mc_filter[0]); + ADM8211_CSR_WRITE(MAR1, mc_filter[1]); + ADM8211_CSR_READ(NAR); + + if (priv->nar & ADM8211_NAR_PR) + dev->flags |= IEEE80211_HW_RX_INCLUDES_FCS; + else + dev->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS; + + if (*total_flags & FIF_BCN_PRBRESP_PROMISC) + adm8211_set_bssid(dev, bcast); + else + adm8211_set_bssid(dev, priv->bssid); + + ADM8211_RESTORE(); + + *total_flags = new_flags; +} + static int adm8211_add_interface(struct ieee80211_hw *dev, struct ieee80211_if_init_conf *conf) { struct adm8211_priv *priv = dev->priv; - /* NOTE: using IEEE80211_IF_TYPE_MGMT to indicate no mode selected */ - if (priv->mode != IEEE80211_IF_TYPE_MGMT) - return -1; + if (priv->mode != IEEE80211_IF_TYPE_MNTR) + return -EOPNOTSUPP; switch (conf->type) { case IEEE80211_IF_TYPE_STA: - case IEEE80211_IF_TYPE_MNTR: priv->mode = conf->type; break; default: return -EOPNOTSUPP; } - priv->mac_addr = conf->mac_addr; + ADM8211_IDLE(); + + ADM8211_CSR_WRITE(PAR0, *(u32 *)conf->mac_addr); + ADM8211_CSR_WRITE(PAR1, *(u16 *)(conf->mac_addr + 4)); + + adm8211_update_mode(dev); + + ADM8211_RESTORE(); return 0; } @@ -1421,7 +1434,7 @@ static void adm8211_remove_interface(struct ieee80211_hw *dev, struct ieee80211_if_init_conf *conf) { struct adm8211_priv *priv = dev->priv; - priv->mode = IEEE80211_IF_TYPE_MGMT; + priv->mode = IEEE80211_IF_TYPE_MNTR; } static int adm8211_init_rings(struct ieee80211_hw *dev) @@ -1505,7 +1518,7 @@ static void adm8211_free_rings(struct ieee80211_hw *dev) } } -static int adm8211_open(struct ieee80211_hw *dev) +static int adm8211_start(struct ieee80211_hw *dev) { struct adm8211_priv *priv = dev->priv; int retval; @@ -1550,7 +1563,7 @@ fail: return retval; } -static int adm8211_stop(struct ieee80211_hw *dev) +static void adm8211_stop(struct ieee80211_hw *dev) { struct adm8211_priv *priv = dev->priv; @@ -1562,7 +1575,6 @@ static int adm8211_stop(struct ieee80211_hw *dev) free_irq(priv->pdev->irq, dev); adm8211_free_rings(dev); - return 0; } static void adm8211_calc_durations(int *dur, int *plcp, size_t payload_len, int len, @@ -1765,13 +1777,13 @@ static int adm8211_alloc_rings(struct ieee80211_hw *dev) static const struct ieee80211_ops adm8211_ops = { .tx = adm8211_tx, - .open = adm8211_open, + .start = adm8211_start, .stop = adm8211_stop, .add_interface = adm8211_add_interface, .remove_interface = adm8211_remove_interface, .config = adm8211_config, .config_interface = adm8211_config_interface, - .set_multicast_list = adm8211_set_rx_mode, + .configure_filter = adm8211_configure_filter, .get_stats = adm8211_get_stats, .get_tx_stats = adm8211_get_tx_stats, .get_tsf = adm8211_get_tsft @@ -1905,7 +1917,7 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, priv->tx_power = 0x40; priv->lpf_cutoff = 0xFF; priv->lnags_threshold = 0xFF; - priv->mode = IEEE80211_IF_TYPE_MGMT; + priv->mode = IEEE80211_IF_TYPE_MNTR; /* Power-on issue. EEPROM won't read correctly without */ if (priv->revid >= ADM8211_REV_BA) { @@ -2000,7 +2012,7 @@ static int adm8211_suspend(struct pci_dev *pdev, pm_message_t state) struct ieee80211_hw *dev = pci_get_drvdata(pdev); struct adm8211_priv *priv = dev->priv; - if (priv->mode != IEEE80211_IF_TYPE_MGMT) { + if (priv->mode != IEEE80211_IF_TYPE_MNTR) { ieee80211_stop_queues(dev); adm8211_stop(dev); } @@ -2018,8 +2030,8 @@ static int adm8211_resume(struct pci_dev *pdev) pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); - if (priv->mode != IEEE80211_IF_TYPE_MGMT) { - adm8211_open(dev); + if (priv->mode != IEEE80211_IF_TYPE_MNTR) { + adm8211_start(dev); ieee80211_start_queues(dev); } diff --git a/drivers/net/wireless/adm8211.h b/drivers/net/wireless/adm8211.h index 795d895f5c99..5991b17c4a7b 100644 --- a/drivers/net/wireless/adm8211.h +++ b/drivers/net/wireless/adm8211.h @@ -612,7 +612,6 @@ struct adm8211_priv { u8 bssid[ETH_ALEN]; u8 ssid[32]; size_t ssid_len; - u8 *mac_addr; u8 soft_rx_crc; u8 retry_limit; diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index a22435ade8ca..2c8fa1c3465e 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -604,9 +604,8 @@ struct b43_wl { * at a time. General information about this interface follows. */ - /* Opaque ID of the operating interface (!= monitor - * interface) from the ieee80211 subsystem. - * Do not modify. + /* Opaque ID of the operating interface from the ieee80211 + * subsystem. Do not modify. */ int if_id; /* The MAC address of the operating interface. */ @@ -615,14 +614,10 @@ struct b43_wl { u8 bssid[ETH_ALEN]; /* Interface type. (IEEE80211_IF_TYPE_XXX) */ int if_type; - /* Counter of active monitor interfaces. */ - int monitor; /* Is the card operating in AP, STA or IBSS mode? */ bool operating; - /* Promisc mode active? - * Note that (monitor != 0) implies promisc. - */ - bool promisc; + /* filter flags */ + unsigned int filter_flags; /* Stats about the wireless interface */ struct ieee80211_low_level_stats ieee_stats; @@ -779,8 +774,6 @@ static inline struct b43_wldev *dev_to_b43_wldev(struct device *dev) /* Is the device operating in a specified mode (IEEE80211_IF_TYPE_XXX). */ static inline int b43_is_mode(struct b43_wl *wl, int type) { - if (type == IEEE80211_IF_TYPE_MNTR) - return !!(wl->monitor); return (wl->operating && wl->if_type == type); } diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index b44c9f928848..72467c86f8d4 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -92,14 +92,6 @@ static char modparam_fwpostfix[16]; module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444); MODULE_PARM_DESC(fwpostfix, "Postfix for the .fw files to load."); -static int modparam_mon_keep_bad; -module_param_named(mon_keep_bad, modparam_mon_keep_bad, int, 0444); -MODULE_PARM_DESC(mon_keep_bad, "Keep bad frames in monitor mode"); - -static int modparam_mon_keep_badplcp; -module_param_named(mon_keep_badplcp, modparam_mon_keep_bad, int, 0444); -MODULE_PARM_DESC(mon_keep_badplcp, "Keep frames with bad PLCP in monitor mode"); - static int modparam_hwpctl; module_param_named(hwpctl, modparam_hwpctl, int, 0444); MODULE_PARM_DESC(hwpctl, "Enable hardware-side power control (default off)"); @@ -561,15 +553,10 @@ static void b43_write_mac_bssid_templates(struct b43_wldev *dev) } } -static void b43_upload_card_macaddress(struct b43_wldev *dev, - const u8 * mac_addr) +static void b43_upload_card_macaddress(struct b43_wldev *dev) { - if (mac_addr) - memcpy(dev->wl->mac_addr, mac_addr, ETH_ALEN); - else - memset(dev->wl->mac_addr, 0, ETH_ALEN); b43_write_mac_bssid_templates(dev); - b43_macfilter_set(dev, B43_MACFILTER_SELF, mac_addr); + b43_macfilter_set(dev, B43_MACFILTER_SELF, dev->wl->mac_addr); } static void b43_set_slot_time(struct b43_wldev *dev, u16 slot_time) @@ -2052,33 +2039,25 @@ static void b43_adjust_opmode(struct b43_wldev *dev) ctl &= ~B43_MACCTL_KEEP_BADPLCP; ctl &= ~B43_MACCTL_KEEP_BAD; ctl &= ~B43_MACCTL_PROMISC; + ctl &= ~B43_MACCTL_BEACPROMISC; ctl |= B43_MACCTL_INFRA; - if (wl->operating) { - switch (wl->if_type) { - case IEEE80211_IF_TYPE_AP: - ctl |= B43_MACCTL_AP; - break; - case IEEE80211_IF_TYPE_IBSS: - ctl &= ~B43_MACCTL_INFRA; - break; - case IEEE80211_IF_TYPE_STA: - case IEEE80211_IF_TYPE_MNTR: - case IEEE80211_IF_TYPE_WDS: - break; - default: - B43_WARN_ON(1); - } - } - if (wl->monitor) { + if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) + ctl |= B43_MACCTL_AP; + else if (b43_is_mode(wl, IEEE80211_IF_TYPE_IBSS)) + ctl &= ~B43_MACCTL_INFRA; + + if (wl->filter_flags & FIF_CONTROL) ctl |= B43_MACCTL_KEEP_CTL; - if (modparam_mon_keep_bad) - ctl |= B43_MACCTL_KEEP_BAD; - if (modparam_mon_keep_badplcp) - ctl |= B43_MACCTL_KEEP_BADPLCP; - } - if (wl->promisc) + if (wl->filter_flags & FIF_FCSFAIL) + ctl |= B43_MACCTL_KEEP_BAD; + if (wl->filter_flags & FIF_PLCPFAIL) + ctl |= B43_MACCTL_KEEP_BADPLCP; + if (wl->filter_flags & FIF_PROMISC_IN_BSS) ctl |= B43_MACCTL_PROMISC; + if (wl->filter_flags & FIF_BCN_PRBRESP_PROMISC) + ctl |= B43_MACCTL_BEACPROMISC; + /* Workaround: On old hardware the HW-MAC-address-filter * doesn't work properly, so always run promisc in filter * it in software. */ @@ -2254,9 +2233,6 @@ static int b43_chip_init(struct b43_wldev *dev) & ~B43_MACCTL_INFRA); b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL) | B43_MACCTL_INFRA); - /* Let beacons come through */ - b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL) - | B43_MACCTL_BEACPROMISC); if (b43_using_pio(dev)) { b43_write32(dev, 0x0210, 0x00000100); @@ -2899,9 +2875,9 @@ static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) return err; } -static int b43_dev_set_key(struct ieee80211_hw *hw, - set_key_cmd cmd, const u8 *local_addr, - const u8 *addr, struct ieee80211_key_conf *key) +static int b43_dev_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + const u8 *local_addr, const u8 *addr, + struct ieee80211_key_conf *key) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev = wl->current_dev; @@ -3003,21 +2979,40 @@ out: return err; } -static void b43_set_multicast_list(struct ieee80211_hw *hw, - unsigned short netflags, int mc_count) +static void b43_configure_filter(struct ieee80211_hw *hw, + unsigned int changed, unsigned int *fflags, + int mc_count, struct dev_addr_list *mc_list) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev = wl->current_dev; unsigned long flags; - if (!dev) + if (!dev) { + *fflags = 0; return; - spin_lock_irqsave(&wl->irq_lock, flags); - if (wl->promisc != !!(netflags & IFF_PROMISC)) { - wl->promisc = !!(netflags & IFF_PROMISC); - if (b43_status(dev) >= B43_STAT_INITIALIZED) - b43_adjust_opmode(dev); } + + spin_lock_irqsave(&wl->irq_lock, flags); + *fflags &= FIF_PROMISC_IN_BSS | + FIF_ALLMULTI | + FIF_FCSFAIL | + FIF_PLCPFAIL | + FIF_CONTROL | + FIF_OTHER_BSS | + FIF_BCN_PRBRESP_PROMISC; + + changed &= FIF_PROMISC_IN_BSS | + FIF_ALLMULTI | + FIF_FCSFAIL | + FIF_PLCPFAIL | + FIF_CONTROL | + FIF_OTHER_BSS | + FIF_BCN_PRBRESP_PROMISC; + + wl->filter_flags = *fflags; + + if (changed && b43_status(dev) >= B43_STAT_INITIALIZED) + b43_adjust_opmode(dev); spin_unlock_irqrestore(&wl->irq_lock, flags); } @@ -3032,21 +3027,19 @@ static int b43_config_interface(struct ieee80211_hw *hw, return -ENODEV; mutex_lock(&wl->mutex); spin_lock_irqsave(&wl->irq_lock, flags); - if (conf->type != IEEE80211_IF_TYPE_MNTR) { - B43_WARN_ON(wl->if_id != if_id); - if (conf->bssid) - memcpy(wl->bssid, conf->bssid, ETH_ALEN); - else - memset(wl->bssid, 0, ETH_ALEN); - if (b43_status(dev) >= B43_STAT_INITIALIZED) { - if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) { - B43_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP); - b43_set_ssid(dev, conf->ssid, conf->ssid_len); - if (conf->beacon) - b43_refresh_templates(dev, conf->beacon); - } - b43_write_mac_bssid_templates(dev); + B43_WARN_ON(wl->if_id != if_id); + if (conf->bssid) + memcpy(wl->bssid, conf->bssid, ETH_ALEN); + else + memset(wl->bssid, 0, ETH_ALEN); + if (b43_status(dev) >= B43_STAT_INITIALIZED) { + if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) { + B43_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP); + b43_set_ssid(dev, conf->ssid, conf->ssid_len); + if (conf->beacon) + b43_refresh_templates(dev, conf->beacon); } + b43_write_mac_bssid_templates(dev); } spin_unlock_irqrestore(&wl->irq_lock, flags); mutex_unlock(&wl->mutex); @@ -3472,7 +3465,8 @@ static int b43_wireless_core_init(struct b43_wldev *dev) ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */ memset(wl->bssid, 0, ETH_ALEN); - b43_upload_card_macaddress(dev, NULL); + memset(wl->mac_addr, 0, ETH_ALEN); + b43_upload_card_macaddress(dev); b43_security_init(dev); b43_rng_init(wl); @@ -3502,21 +3496,80 @@ static int b43_add_interface(struct ieee80211_hw *hw, struct b43_wldev *dev; unsigned long flags; int err = -EOPNOTSUPP; - int did_init = 0; + + /* TODO: allow WDS/AP devices to coexist */ + + if (conf->type != IEEE80211_IF_TYPE_AP && + conf->type != IEEE80211_IF_TYPE_STA && + conf->type != IEEE80211_IF_TYPE_WDS && + conf->type != IEEE80211_IF_TYPE_IBSS) + return -EOPNOTSUPP; mutex_lock(&wl->mutex); - if ((conf->type != IEEE80211_IF_TYPE_MNTR) && wl->operating) + if (wl->operating) goto out_mutex_unlock; b43dbg(wl, "Adding Interface type %d\n", conf->type); dev = wl->current_dev; + wl->operating = 1; + wl->if_id = conf->if_id; + wl->if_type = conf->type; + memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN); + + spin_lock_irqsave(&wl->irq_lock, flags); + b43_adjust_opmode(dev); + b43_upload_card_macaddress(dev); + spin_unlock_irqrestore(&wl->irq_lock, flags); + + err = 0; + out_mutex_unlock: + mutex_unlock(&wl->mutex); + + return err; +} + +static void b43_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct b43_wl *wl = hw_to_b43_wl(hw); + struct b43_wldev *dev = wl->current_dev; + unsigned long flags; + + b43dbg(wl, "Removing Interface type %d\n", conf->type); + + mutex_lock(&wl->mutex); + + B43_WARN_ON(!wl->operating); + B43_WARN_ON(wl->if_id != conf->if_id); + + wl->operating = 0; + + spin_lock_irqsave(&wl->irq_lock, flags); + b43_adjust_opmode(dev); + memset(wl->mac_addr, 0, ETH_ALEN); + b43_upload_card_macaddress(dev); + spin_unlock_irqrestore(&wl->irq_lock, flags); + + mutex_unlock(&wl->mutex); +} + +static int b43_start(struct ieee80211_hw *hw) +{ + struct b43_wl *wl = hw_to_b43_wl(hw); + struct b43_wldev *dev = wl->current_dev; + int did_init = 0; + int err; + + mutex_lock(&wl->mutex); + if (b43_status(dev) < B43_STAT_INITIALIZED) { err = b43_wireless_core_init(dev); if (err) goto out_mutex_unlock; did_init = 1; } + if (b43_status(dev) < B43_STAT_STARTED) { err = b43_wireless_core_start(dev); if (err) { @@ -3526,59 +3579,21 @@ static int b43_add_interface(struct ieee80211_hw *hw, } } - spin_lock_irqsave(&wl->irq_lock, flags); - switch (conf->type) { - case IEEE80211_IF_TYPE_MNTR: - wl->monitor++; - break; - default: - wl->operating = 1; - wl->if_id = conf->if_id; - wl->if_type = conf->type; - b43_upload_card_macaddress(dev, conf->mac_addr); - } - b43_adjust_opmode(dev); - spin_unlock_irqrestore(&wl->irq_lock, flags); - - err = 0; - out_mutex_unlock: + out_mutex_unlock: mutex_unlock(&wl->mutex); return err; } -static void b43_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) +void b43_stop(struct ieee80211_hw *hw) { struct b43_wl *wl = hw_to_b43_wl(hw); - struct b43_wldev *dev; - unsigned long flags; - - b43dbg(wl, "Removing Interface type %d\n", conf->type); + struct b43_wldev *dev = wl->current_dev; mutex_lock(&wl->mutex); - if (conf->type == IEEE80211_IF_TYPE_MNTR) { - wl->monitor--; - B43_WARN_ON(wl->monitor < 0); - } else { - B43_WARN_ON(!wl->operating); - wl->operating = 0; - } - - dev = wl->current_dev; - if (!wl->operating && wl->monitor == 0) { - /* No interface left. */ - if (b43_status(dev) >= B43_STAT_STARTED) - b43_wireless_core_stop(dev); - b43_wireless_core_exit(dev); - } else { - /* Just monitor interfaces left. */ - spin_lock_irqsave(&wl->irq_lock, flags); - b43_adjust_opmode(dev); - if (!wl->operating) - b43_upload_card_macaddress(dev, NULL); - spin_unlock_irqrestore(&wl->irq_lock, flags); - } + if (b43_status(dev) >= B43_STAT_STARTED) + b43_wireless_core_stop(dev); + b43_wireless_core_exit(dev); mutex_unlock(&wl->mutex); } @@ -3589,10 +3604,12 @@ static const struct ieee80211_ops b43_hw_ops = { .remove_interface = b43_remove_interface, .config = b43_dev_config, .config_interface = b43_config_interface, - .set_multicast_list = b43_set_multicast_list, + .configure_filter = b43_configure_filter, .set_key = b43_dev_set_key, .get_stats = b43_get_stats, .get_tx_stats = b43_get_tx_stats, + .start = b43_start, + .stop = b43_stop, }; /* Hard-reset the chip. Do not call this directly. @@ -3930,8 +3947,7 @@ static int b43_wireless_init(struct ssb_device *dev) } /* fill hw info */ - hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | - IEEE80211_HW_MONITOR_DURING_OPER; + hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE; hw->max_signal = 100; hw->max_rssi = -110; hw->max_noise = -110; diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h index 746de2ff498c..afe145cec067 100644 --- a/drivers/net/wireless/b43legacy/b43legacy.h +++ b/drivers/net/wireless/b43legacy/b43legacy.h @@ -179,6 +179,7 @@ #define B43legacy_MACCTL_IHR_ENABLED 0x00000400 /* IHR Region Enabled */ #define B43legacy_MACCTL_INFRA 0x00020000 /* Infrastructure mode */ #define B43legacy_MACCTL_AP 0x00040000 /* AccessPoint mode */ +#define B43legacy_MACCTL_BEACPROMISC 0x00100000 /* Beacon Promiscuous */ #define B43legacy_MACCTL_KEEP_BADPLCP 0x00200000 /* Keep bad PLCP frames */ #define B43legacy_MACCTL_KEEP_CTL 0x00400000 /* Keep control frames */ #define B43legacy_MACCTL_KEEP_BAD 0x00800000 /* Keep bad frames (FCS) */ @@ -570,25 +571,20 @@ struct b43legacy_wl { * at a time. General information about this interface follows. */ - /* Opaque ID of the operating interface (!= monitor - * interface) from the ieee80211 subsystem. - * Do not modify. + /* Opaque ID of the operating interface from the ieee80211 + * subsystem. Do not modify. */ int if_id; /* MAC address (can be NULL). */ - const u8 *mac_addr; + u8 mac_addr[ETH_ALEN]; /* Current BSSID (can be NULL). */ - const u8 *bssid; + u8 bssid[ETH_ALEN]; /* Interface type. (IEEE80211_IF_TYPE_XXX) */ int if_type; - /* Counter of active monitor interfaces. */ - int monitor; /* Is the card operating in AP, STA or IBSS mode? */ bool operating; - /* Promisc mode active? - * Note that (monitor != 0) implies promisc. - */ - bool promisc; + /* filter flags */ + unsigned int filter_flags; /* Stats about the wireless interface */ struct ieee80211_low_level_stats ieee_stats; @@ -753,8 +749,6 @@ struct b43legacy_wldev *dev_to_b43legacy_wldev(struct device *dev) static inline int b43legacy_is_mode(struct b43legacy_wl *wl, int type) { - if (type == IEEE80211_IF_TYPE_MNTR) - return !!(wl->monitor); return (wl->operating && wl->if_type == type); } diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index a793f183a2c0..f0749510bcd7 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -91,14 +91,6 @@ static char modparam_fwpostfix[16]; module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444); MODULE_PARM_DESC(fwpostfix, "Postfix for the firmware files to load."); -static int modparam_mon_keep_bad; -module_param_named(mon_keep_bad, modparam_mon_keep_bad, int, 0444); -MODULE_PARM_DESC(mon_keep_bad, "Keep bad frames in monitor mode"); - -static int modparam_mon_keep_badplcp; -module_param_named(mon_keep_badplcp, modparam_mon_keep_bad, int, 0444); -MODULE_PARM_DESC(mon_keep_badplcp, "Keep frames with bad PLCP in monitor mode"); - /* The following table supports BCM4301, BCM4303 and BCM4306/2 devices. */ static const struct ssb_device_id b43legacy_ssb_tbl[] = { SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 2), @@ -566,12 +558,11 @@ static void b43legacy_write_mac_bssid_templates(struct b43legacy_wldev *dev) } } -static void b43legacy_upload_card_macaddress(struct b43legacy_wldev *dev, - const u8 *mac_addr) +static void b43legacy_upload_card_macaddress(struct b43legacy_wldev *dev) { - dev->wl->mac_addr = mac_addr; b43legacy_write_mac_bssid_templates(dev); - b43legacy_macfilter_set(dev, B43legacy_MACFILTER_SELF, mac_addr); + b43legacy_macfilter_set(dev, B43legacy_MACFILTER_SELF, + dev->wl->mac_addr); } static void b43legacy_set_slot_time(struct b43legacy_wldev *dev, @@ -1874,34 +1865,25 @@ static void b43legacy_adjust_opmode(struct b43legacy_wldev *dev) ctl &= ~B43legacy_MACCTL_KEEP_BADPLCP; ctl &= ~B43legacy_MACCTL_KEEP_BAD; ctl &= ~B43legacy_MACCTL_PROMISC; + ctl &= ~B43legacy_MACCTL_BEACPROMISC; ctl |= B43legacy_MACCTL_INFRA; - if (wl->operating) { - switch (wl->if_type) { - case IEEE80211_IF_TYPE_AP: - ctl |= B43legacy_MACCTL_AP; - break; - case IEEE80211_IF_TYPE_IBSS: - ctl &= ~B43legacy_MACCTL_INFRA; - break; - case IEEE80211_IF_TYPE_STA: - case IEEE80211_IF_TYPE_MNTR: - case IEEE80211_IF_TYPE_WDS: - break; - default: - b43legacyerr(wl, "Improper value of %d for" - " wl->if_type\n", wl->if_type); - } - } - if (wl->monitor) { + if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP)) + ctl |= B43legacy_MACCTL_AP; + else if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_IBSS)) + ctl &= ~B43legacy_MACCTL_INFRA; + + if (wl->filter_flags & FIF_CONTROL) ctl |= B43legacy_MACCTL_KEEP_CTL; - if (modparam_mon_keep_bad) - ctl |= B43legacy_MACCTL_KEEP_BAD; - if (modparam_mon_keep_badplcp) - ctl |= B43legacy_MACCTL_KEEP_BADPLCP; - } - if (wl->promisc) + if (wl->filter_flags & FIF_FCSFAIL) + ctl |= B43legacy_MACCTL_KEEP_BAD; + if (wl->filter_flags & FIF_PLCPFAIL) + ctl |= B43legacy_MACCTL_KEEP_BADPLCP; + if (wl->filter_flags & FIF_PROMISC_IN_BSS) ctl |= B43legacy_MACCTL_PROMISC; + if (wl->filter_flags & FIF_BCN_PRBRESP_PROMISC) + ctl |= B43legacy_MACCTL_BEACPROMISC; + /* Workaround: On old hardware the HW-MAC-address-filter * doesn't work properly, so always run promisc in filter * it in software. */ @@ -2091,10 +2073,6 @@ static int b43legacy_chip_init(struct b43legacy_wldev *dev) value32 |= B43legacy_SBF_MODE_NOTADHOC; b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value32); - value32 = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); - value32 |= 0x100000; - b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value32); - if (b43legacy_using_pio(dev)) { b43legacy_write32(dev, 0x0210, 0x00000100); b43legacy_write32(dev, 0x0230, 0x00000100); @@ -2699,7 +2677,7 @@ out_unlock_mutex: } static int b43legacy_dev_set_key(struct ieee80211_hw *hw, - set_key_cmd cmd, + enum set_key_cmd cmd, const u8 *local_addr, const u8 *addr, struct ieee80211_key_conf *key) { @@ -2724,22 +2702,42 @@ static int b43legacy_dev_set_key(struct ieee80211_hw *hw, return err; } -static void b43legacy_set_multicast_list(struct ieee80211_hw *hw, - unsigned short netflags, - int mc_count) +static void b43legacy_configure_filter(struct ieee80211_hw *hw, + unsigned int changed, + unsigned int *fflags, + int mc_count, + struct dev_addr_list *mc_list) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev = wl->current_dev; unsigned long flags; - if (!dev) + if (!dev) { + *fflags = 0; return; - spin_lock_irqsave(&wl->irq_lock, flags); - if (wl->promisc != !!(netflags & IFF_PROMISC)) { - wl->promisc = !!(netflags & IFF_PROMISC); - if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) - b43legacy_adjust_opmode(dev); } + + spin_lock_irqsave(&wl->irq_lock, flags); + *fflags &= FIF_PROMISC_IN_BSS | + FIF_ALLMULTI | + FIF_FCSFAIL | + FIF_PLCPFAIL | + FIF_CONTROL | + FIF_OTHER_BSS | + FIF_BCN_PRBRESP_PROMISC; + + changed &= FIF_PROMISC_IN_BSS | + FIF_ALLMULTI | + FIF_FCSFAIL | + FIF_PLCPFAIL | + FIF_CONTROL | + FIF_OTHER_BSS | + FIF_BCN_PRBRESP_PROMISC; + + wl->filter_flags = *fflags; + + if (changed && b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) + b43legacy_adjust_opmode(dev); spin_unlock_irqrestore(&wl->irq_lock, flags); } @@ -2755,21 +2753,19 @@ static int b43legacy_config_interface(struct ieee80211_hw *hw, return -ENODEV; mutex_lock(&wl->mutex); spin_lock_irqsave(&wl->irq_lock, flags); - if (conf->type != IEEE80211_IF_TYPE_MNTR) { - B43legacy_WARN_ON(wl->if_id != if_id); - wl->bssid = conf->bssid; - if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) { - if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP)) { - B43legacy_WARN_ON(conf->type != - IEEE80211_IF_TYPE_AP); - b43legacy_set_ssid(dev, conf->ssid, - conf->ssid_len); - if (conf->beacon) - b43legacy_refresh_templates(dev, - conf->beacon); - } - b43legacy_write_mac_bssid_templates(dev); + B43legacy_WARN_ON(wl->if_id != if_id); + if (conf->bssid) + memcpy(wl->bssid, conf->bssid, ETH_ALEN); + else + memset(wl->bssid, 0, ETH_ALEN); + if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) { + if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP)) { + B43legacy_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP); + b43legacy_set_ssid(dev, conf->ssid, conf->ssid_len); + if (conf->beacon) + b43legacy_refresh_templates(dev, conf->beacon); } + b43legacy_write_mac_bssid_templates(dev); } spin_unlock_irqrestore(&wl->irq_lock, flags); mutex_unlock(&wl->mutex); @@ -3216,8 +3212,9 @@ static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev) b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0414, 0x01F4); ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */ - wl->bssid = NULL; - b43legacy_upload_card_macaddress(dev, NULL); + memset(wl->bssid, 0, ETH_ALEN); + memset(wl->mac_addr, 0, ETH_ALEN); + b43legacy_upload_card_macaddress(dev); b43legacy_security_init(dev); b43legacy_rng_init(wl); @@ -3246,22 +3243,80 @@ static int b43legacy_add_interface(struct ieee80211_hw *hw, struct b43legacy_wldev *dev; unsigned long flags; int err = -EOPNOTSUPP; - int did_init = 0; + + /* TODO: allow WDS/AP devices to coexist */ + + if (conf->type != IEEE80211_IF_TYPE_AP && + conf->type != IEEE80211_IF_TYPE_STA && + conf->type != IEEE80211_IF_TYPE_WDS && + conf->type != IEEE80211_IF_TYPE_IBSS) + return -EOPNOTSUPP; mutex_lock(&wl->mutex); - if ((conf->type != IEEE80211_IF_TYPE_MNTR) && - wl->operating) + if (wl->operating) goto out_mutex_unlock; b43legacydbg(wl, "Adding Interface type %d\n", conf->type); dev = wl->current_dev; + wl->operating = 1; + wl->if_id = conf->if_id; + wl->if_type = conf->type; + memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN); + + spin_lock_irqsave(&wl->irq_lock, flags); + b43legacy_adjust_opmode(dev); + b43legacy_upload_card_macaddress(dev); + spin_unlock_irqrestore(&wl->irq_lock, flags); + + err = 0; + out_mutex_unlock: + mutex_unlock(&wl->mutex); + + return err; +} + +static void b43legacy_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); + struct b43legacy_wldev *dev = wl->current_dev; + unsigned long flags; + + b43legacydbg(wl, "Removing Interface type %d\n", conf->type); + + mutex_lock(&wl->mutex); + + B43legacy_WARN_ON(!wl->operating); + B43legacy_WARN_ON(wl->if_id != conf->if_id); + + wl->operating = 0; + + spin_lock_irqsave(&wl->irq_lock, flags); + b43legacy_adjust_opmode(dev); + memset(wl->mac_addr, 0, ETH_ALEN); + b43legacy_upload_card_macaddress(dev); + spin_unlock_irqrestore(&wl->irq_lock, flags); + + mutex_unlock(&wl->mutex); +} + +static int b43legacy_start(struct ieee80211_hw *hw) +{ + struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); + struct b43legacy_wldev *dev = wl->current_dev; + int did_init = 0; + int err; + + mutex_lock(&wl->mutex); + if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) { err = b43legacy_wireless_core_init(dev); if (err) goto out_mutex_unlock; did_init = 1; } + if (b43legacy_status(dev) < B43legacy_STAT_STARTED) { err = b43legacy_wireless_core_start(dev); if (err) { @@ -3271,59 +3326,21 @@ static int b43legacy_add_interface(struct ieee80211_hw *hw, } } - spin_lock_irqsave(&wl->irq_lock, flags); - switch (conf->type) { - case IEEE80211_IF_TYPE_MNTR: - wl->monitor++; - break; - default: - wl->operating = 1; - wl->if_id = conf->if_id; - wl->if_type = conf->type; - b43legacy_upload_card_macaddress(dev, conf->mac_addr); - } - b43legacy_adjust_opmode(dev); - spin_unlock_irqrestore(&wl->irq_lock, flags); - - err = 0; out_mutex_unlock: mutex_unlock(&wl->mutex); return err; } -static void b43legacy_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) +void b43legacy_stop(struct ieee80211_hw *hw) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); - struct b43legacy_wldev *dev; - unsigned long flags; - - b43legacydbg(wl, "Removing Interface type %d\n", conf->type); + struct b43legacy_wldev *dev = wl->current_dev; mutex_lock(&wl->mutex); - if (conf->type == IEEE80211_IF_TYPE_MNTR) { - wl->monitor--; - B43legacy_WARN_ON(wl->monitor < 0); - } else { - B43legacy_WARN_ON(!wl->operating); - wl->operating = 0; - } - - dev = wl->current_dev; - if (!wl->operating && wl->monitor == 0) { - /* No interface left. */ - if (b43legacy_status(dev) >= B43legacy_STAT_STARTED) - b43legacy_wireless_core_stop(dev); - b43legacy_wireless_core_exit(dev); - } else { - /* Just monitor interfaces left. */ - spin_lock_irqsave(&wl->irq_lock, flags); - b43legacy_adjust_opmode(dev); - if (!wl->operating) - b43legacy_upload_card_macaddress(dev, NULL); - spin_unlock_irqrestore(&wl->irq_lock, flags); - } + if (b43legacy_status(dev) >= B43legacy_STAT_STARTED) + b43legacy_wireless_core_stop(dev); + b43legacy_wireless_core_exit(dev); mutex_unlock(&wl->mutex); } @@ -3336,9 +3353,11 @@ static const struct ieee80211_ops b43legacy_hw_ops = { .config = b43legacy_dev_config, .config_interface = b43legacy_config_interface, .set_key = b43legacy_dev_set_key, - .set_multicast_list = b43legacy_set_multicast_list, + .configure_filter = b43legacy_configure_filter, .get_stats = b43legacy_get_stats, .get_tx_stats = b43legacy_get_tx_stats, + .start = b43legacy_start, + .stop = b43legacy_stop, }; /* Hard-reset the chip. Do not call this directly. diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 44f983b6d39b..8acda640df25 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -6870,7 +6870,7 @@ static void iwl_bg_scan_completed(struct work_struct *work) * *****************************************************************************/ -static int iwl_mac_open(struct ieee80211_hw *hw) +static int iwl_mac_start(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; @@ -6889,7 +6889,7 @@ static int iwl_mac_open(struct ieee80211_hw *hw) return 0; } -static int iwl_mac_stop(struct ieee80211_hw *hw) +static void iwl_mac_stop(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; @@ -6898,8 +6898,6 @@ static int iwl_mac_stop(struct ieee80211_hw *hw) /*netif_stop_queue(dev); */ flush_workqueue(priv->workqueue); IWL_DEBUG_MAC80211("leave\n"); - - return 0; } static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, @@ -7115,6 +7113,8 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, if (conf == NULL) return -EIO; + /* XXX: this MUST use conf->mac_addr */ + if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) && (!conf->beacon || !conf->ssid_len)) { IWL_DEBUG_MAC80211 @@ -7129,8 +7129,13 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, IWL_DEBUG_MAC80211("bssid: %s\n", print_mac(mac, conf->bssid)); +/* + * very dubious code was here; the probe filtering flag is never set: + * if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) && !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) { + */ + if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) { IWL_DEBUG_MAC80211("leave - scanning\n"); mutex_unlock(&priv->mutex); return 0; @@ -7205,6 +7210,18 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, return 0; } +static void iwl_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, struct dev_addr_list *mc_list) +{ + /* + * XXX: dummy + * see also iwl_connection_init_rx_config + */ + *total_flags = 0; +} + static void iwl_mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { @@ -8265,12 +8282,13 @@ static struct attribute_group iwl_attribute_group = { static struct ieee80211_ops iwl_hw_ops = { .tx = iwl_mac_tx, - .open = iwl_mac_open, + .start = iwl_mac_start, .stop = iwl_mac_stop, .add_interface = iwl_mac_add_interface, .remove_interface = iwl_mac_remove_interface, .config = iwl_mac_config, .config_interface = iwl_mac_config_interface, + .configure_filter = iwl_configure_filter, .set_key = iwl_mac_set_key, .get_stats = iwl_mac_get_stats, .get_tx_stats = iwl_mac_get_tx_stats, diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 61500a209297..7b9227c562b7 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -7252,7 +7252,7 @@ static void iwl_bg_scan_completed(struct work_struct *work) * *****************************************************************************/ -static int iwl_mac_open(struct ieee80211_hw *hw) +static int iwl_mac_start(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; @@ -7271,7 +7271,7 @@ static int iwl_mac_open(struct ieee80211_hw *hw) return 0; } -static int iwl_mac_stop(struct ieee80211_hw *hw) +static void iwl_mac_stop(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; @@ -7280,8 +7280,6 @@ static int iwl_mac_stop(struct ieee80211_hw *hw) /*netif_stop_queue(dev); */ flush_workqueue(priv->workqueue); IWL_DEBUG_MAC80211("leave\n"); - - return 0; } static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, @@ -7528,8 +7526,13 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, IWL_DEBUG_MAC80211("bssid: %s\n", print_mac(mac, conf->bssid)); +/* + * very dubious code was here; the probe filtering flag is never set: + * if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) && !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) { + */ + if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) { IWL_DEBUG_MAC80211("leave - scanning\n"); mutex_unlock(&priv->mutex); return 0; @@ -7604,6 +7607,18 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, return 0; } +static void iwl_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, struct dev_addr_list *mc_list) +{ + /* + * XXX: dummy + * see also iwl_connection_init_rx_config + */ + *total_flags = 0; +} + static void iwl_mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { @@ -8852,12 +8867,13 @@ static struct attribute_group iwl_attribute_group = { static struct ieee80211_ops iwl_hw_ops = { .tx = iwl_mac_tx, - .open = iwl_mac_open, + .start = iwl_mac_start, .stop = iwl_mac_stop, .add_interface = iwl_mac_add_interface, .remove_interface = iwl_mac_remove_interface, .config = iwl_mac_config, .config_interface = iwl_mac_config_interface, + .configure_filter = iwl_configure_filter, .set_key = iwl_mac_set_key, .get_stats = iwl_mac_get_stats, .get_tx_stats = iwl_mac_get_tx_stats, diff --git a/drivers/net/wireless/p54.h b/drivers/net/wireless/p54.h index e558d697d9e5..744c866066c5 100644 --- a/drivers/net/wireless/p54.h +++ b/drivers/net/wireless/p54.h @@ -52,7 +52,8 @@ struct p54_common { int (*open)(struct ieee80211_hw *dev); void (*stop)(struct ieee80211_hw *dev); int mode; - u8 *mac_addr; + u8 mac_addr[ETH_ALEN]; + u8 bssid[ETH_ALEN]; struct pda_iq_autocal_entry *iq_autocal; unsigned int iq_autocal_len; struct pda_channel_output_limit *output_limit; diff --git a/drivers/net/wireless/p54common.c b/drivers/net/wireless/p54common.c index b05b5c5b4c04..9befd6cc7911 100644 --- a/drivers/net/wireless/p54common.c +++ b/drivers/net/wireless/p54common.c @@ -774,15 +774,39 @@ static void p54_set_vdcf(struct ieee80211_hw *dev) priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*vdcf), 0); } +static int p54_start(struct ieee80211_hw *dev) +{ + struct p54_common *priv = dev->priv; + int err; + + err = priv->open(dev); + if (!err) + priv->mode = IEEE80211_IF_TYPE_MNTR; + + return err; +} + +static void p54_stop(struct ieee80211_hw *dev) +{ + struct p54_common *priv = dev->priv; + struct sk_buff *skb; + while ((skb = skb_dequeue(&priv->tx_queue))) { + struct memrecord *range = (struct memrecord *)&skb->cb; + if (range->control) + kfree(range->control); + kfree_skb(skb); + } + priv->stop(dev); + priv->mode = IEEE80211_IF_TYPE_MGMT; +} + static int p54_add_interface(struct ieee80211_hw *dev, struct ieee80211_if_init_conf *conf) { struct p54_common *priv = dev->priv; - int err; - /* NOTE: using IEEE80211_IF_TYPE_MGMT to indicate no mode selected */ - if (priv->mode != IEEE80211_IF_TYPE_MGMT) - return -1; + if (priv->mode != IEEE80211_IF_TYPE_MNTR) + return -EOPNOTSUPP; switch (conf->type) { case IEEE80211_IF_TYPE_STA: @@ -792,23 +816,18 @@ static int p54_add_interface(struct ieee80211_hw *dev, return -EOPNOTSUPP; } - priv->mac_addr = conf->mac_addr; - - err = priv->open(dev); - if (err) { - priv->mode = IEEE80211_IF_TYPE_MGMT; - skb_queue_purge(&priv->tx_queue); - return err; - } + memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); p54_set_filter(dev, 0, priv->mac_addr, NULL, 0, 1, 0, 0xF642); p54_set_filter(dev, 0, priv->mac_addr, NULL, 1, 0, 0, 0xF642); - p54_set_vdcf(dev); switch (conf->type) { case IEEE80211_IF_TYPE_STA: p54_set_filter(dev, 1, priv->mac_addr, NULL, 0, 0x15F, 0x1F4, 0); break; + default: + BUG(); /* impossible */ + break; } p54_set_leds(dev, 1, 0, 0); @@ -820,15 +839,9 @@ static void p54_remove_interface(struct ieee80211_hw *dev, struct ieee80211_if_init_conf *conf) { struct p54_common *priv = dev->priv; - struct sk_buff *skb; - while ((skb = skb_dequeue(&priv->tx_queue))) { - struct memrecord *range = (struct memrecord *)&skb->cb; - if (range->control) - kfree(range->control); - kfree_skb(skb); - } - priv->mode = IEEE80211_IF_TYPE_MGMT; - priv->stop(dev); + priv->mode = IEEE80211_IF_TYPE_MNTR; + memset(priv->mac_addr, 0, ETH_ALEN); + p54_set_filter(dev, 0, priv->mac_addr, NULL, 2, 0, 0, 0); } static int p54_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) @@ -848,9 +861,29 @@ static int p54_config_interface(struct ieee80211_hw *dev, int if_id, p54_set_filter(dev, 0, priv->mac_addr, conf->bssid, 0, 1, 0, 0xF642); p54_set_filter(dev, 0, priv->mac_addr, conf->bssid, 2, 0, 0, 0); p54_set_leds(dev, 1, !is_multicast_ether_addr(conf->bssid), 0); + memcpy(priv->bssid, conf->bssid, ETH_ALEN); return 0; } +static void p54_configure_filter(struct ieee80211_hw *dev, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, struct dev_mc_list *mclist) +{ + struct p54_common *priv = dev->priv; + + *total_flags &= FIF_BCN_PRBRESP_PROMISC; + + if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { + if (*total_flags & FIF_BCN_PRBRESP_PROMISC) + p54_set_filter(dev, 0, priv->mac_addr, + NULL, 2, 0, 0, 0); + else + p54_set_filter(dev, 0, priv->mac_addr, + priv->bssid, 2, 0, 0, 0); + } +} + static int p54_conf_tx(struct ieee80211_hw *dev, int queue, const struct ieee80211_tx_queue_params *params) { @@ -893,10 +926,13 @@ static int p54_get_tx_stats(struct ieee80211_hw *dev, static const struct ieee80211_ops p54_ops = { .tx = p54_tx, + .start = p54_start, + .stop = p54_stop, .add_interface = p54_add_interface, .remove_interface = p54_remove_interface, .config = p54_config, .config_interface = p54_config_interface, + .configure_filter = p54_configure_filter, .conf_tx = p54_conf_tx, .get_stats = p54_get_stats, .get_tx_stats = p54_get_tx_stats diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 398c20105c81..03a94a33e6bd 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -277,55 +277,14 @@ static void rt2400pci_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) rt2x00pci_register_multiwrite(rt2x00dev, CSR5, ®, sizeof(reg)); } -static void rt2400pci_config_packet_filter(struct rt2x00_dev *rt2x00dev, - const unsigned int filter) -{ - int promisc = !!(filter & IFF_PROMISC); - u32 reg; - - rt2x00pci_register_read(rt2x00dev, RXCSR0, ®); - rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME, !promisc); - rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); -} - static void rt2400pci_config_type(struct rt2x00_dev *rt2x00dev, int type) { + struct interface *intf = &rt2x00dev->interface; u32 reg; rt2x00pci_register_write(rt2x00dev, CSR14, 0); /* - * Apply hardware packet filter. - */ - rt2x00pci_register_read(rt2x00dev, RXCSR0, ®); - - if (!is_monitor_present(&rt2x00dev->interface) && - (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_STA)) - rt2x00_set_field32(®, RXCSR0_DROP_TODS, 1); - else - rt2x00_set_field32(®, RXCSR0_DROP_TODS, 0); - - /* - * If there is a non-monitor interface present - * the packet should be strict (even if a monitor interface is present!). - * When there is only 1 interface present which is in monitor mode - * we should start accepting _all_ frames. - */ - if (is_interface_present(&rt2x00dev->interface)) { - rt2x00_set_field32(®, RXCSR0_DROP_CRC, 1); - rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, 1); - rt2x00_set_field32(®, RXCSR0_DROP_CONTROL, 1); - rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 1); - } else if (is_monitor_present(&rt2x00dev->interface)) { - rt2x00_set_field32(®, RXCSR0_DROP_CRC, 0); - rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, 0); - rt2x00_set_field32(®, RXCSR0_DROP_CONTROL, 0); - rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 0); - } - - rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); - - /* * Enable beacon config */ rt2x00pci_register_read(rt2x00dev, BCNCSR1, ®); @@ -337,20 +296,16 @@ static void rt2400pci_config_type(struct rt2x00_dev *rt2x00dev, int type) * Enable synchronisation. */ rt2x00pci_register_read(rt2x00dev, CSR14, ®); - if (is_interface_present(&rt2x00dev->interface)) { - rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); - rt2x00_set_field32(®, CSR14_TBCN, 1); - } - + rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); + rt2x00_set_field32(®, CSR14_TBCN, 1); rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); - if (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_AP) + if (is_interface_type(intf, IEEE80211_IF_TYPE_IBSS) || + is_interface_type(intf, IEEE80211_IF_TYPE_AP)) rt2x00_set_field32(®, CSR14_TSF_SYNC, 2); - else if (type == IEEE80211_IF_TYPE_STA) + else if (is_interface_type(intf, IEEE80211_IF_TYPE_STA)) rt2x00_set_field32(®, CSR14_TSF_SYNC, 1); - else if (is_monitor_present(&rt2x00dev->interface) && - !is_interface_present(&rt2x00dev->interface)) + else rt2x00_set_field32(®, CSR14_TSF_SYNC, 0); - rt2x00pci_register_write(rt2x00dev, CSR14, reg); } @@ -1104,7 +1059,7 @@ static int rt2400pci_set_device_state(struct rt2x00_dev *rt2x00dev, */ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct data_desc *txd, - struct data_entry_desc *desc, + struct txdata_entry_desc *desc, struct ieee80211_hdr *ieee80211hdr, unsigned int length, struct ieee80211_tx_control *control) @@ -1200,8 +1155,8 @@ static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, /* * RX control handlers */ -static int rt2400pci_fill_rxdone(struct data_entry *entry, - int *signal, int *rssi, int *ofdm, int *size) +static void rt2400pci_fill_rxdone(struct data_entry *entry, + struct rxdata_entry_desc *desc) { struct data_desc *rxd = entry->priv; u32 word0; @@ -1210,20 +1165,20 @@ static int rt2400pci_fill_rxdone(struct data_entry *entry, rt2x00_desc_read(rxd, 0, &word0); rt2x00_desc_read(rxd, 2, &word2); - if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR) || - rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR)) - return -EINVAL; + desc->flags = 0; + if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) + desc->flags |= RX_FLAG_FAILED_FCS_CRC; + if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR)) + desc->flags |= RX_FLAG_FAILED_PLCP_CRC; /* * Obtain the status about this packet. */ - *signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL); - *rssi = rt2x00_get_field32(word2, RXD_W2_RSSI) - + desc->signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL); + desc->rssi = rt2x00_get_field32(word2, RXD_W2_RSSI) - entry->ring->rt2x00dev->rssi_offset; - *ofdm = 0; - *size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); - - return 0; + desc->ofdm = 0; + desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); } /* @@ -1460,10 +1415,7 @@ static void rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) /* * Initialize all hw fields. */ - rt2x00dev->hw->flags = - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_MONITOR_DURING_OPER | - IEEE80211_HW_NO_PROBE_FILTERING; + rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; rt2x00dev->hw->extra_tx_headroom = 0; rt2x00dev->hw->max_signal = MAX_SIGNAL; rt2x00dev->hw->max_rssi = MAX_RX_SSI; @@ -1530,6 +1482,68 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ +static void rt2400pci_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, + struct dev_addr_list *mc_list) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct interface *intf = &rt2x00dev->interface; + u32 reg; + + /* + * Mask off any flags we are going to ignore from + * the total_flags field. + */ + *total_flags &= + FIF_ALLMULTI | + FIF_FCSFAIL | + FIF_PLCPFAIL | + FIF_CONTROL | + FIF_OTHER_BSS | + FIF_PROMISC_IN_BSS; + + /* + * Apply some rules to the filters: + * - Some filters imply different filters to be set. + * - Some things we can't filter out at all. + * - Some filters are set based on interface type. + */ + *total_flags |= FIF_ALLMULTI; + if (changed_flags & FIF_OTHER_BSS || + changed_flags & FIF_PROMISC_IN_BSS) + *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; + if (is_interface_type(intf, IEEE80211_IF_TYPE_AP)) + *total_flags |= FIF_PROMISC_IN_BSS; + + /* + * Check if there is any work left for us. + */ + if (intf->filter == *total_flags) + return; + intf->filter = *total_flags; + + /* + * Start configuration steps. + * Note that the version error will always be dropped + * since there is no filter for it at this time. + */ + rt2x00pci_register_read(rt2x00dev, RXCSR0, ®); + rt2x00_set_field32(®, RXCSR0_DROP_CRC, + !(*total_flags & FIF_FCSFAIL)); + rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, + !(*total_flags & FIF_PLCPFAIL)); + rt2x00_set_field32(®, RXCSR0_DROP_CONTROL, + !(*total_flags & FIF_CONTROL)); + rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME, + !(*total_flags & FIF_PROMISC_IN_BSS)); + rt2x00_set_field32(®, RXCSR0_DROP_TODS, + !(*total_flags & FIF_PROMISC_IN_BSS)); + rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 1); + rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); +} + static int rt2400pci_set_retry_limit(struct ieee80211_hw *hw, u32 short_retry, u32 long_retry) { @@ -1602,11 +1616,13 @@ static int rt2400pci_tx_last_beacon(struct ieee80211_hw *hw) static const struct ieee80211_ops rt2400pci_mac80211_ops = { .tx = rt2x00mac_tx, + .start = rt2x00mac_start, + .stop = rt2x00mac_stop, .add_interface = rt2x00mac_add_interface, .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, .config_interface = rt2x00mac_config_interface, - .set_multicast_list = rt2x00mac_set_multicast_list, + .configure_filter = rt2400pci_configure_filter, .get_stats = rt2x00mac_get_stats, .set_retry_limit = rt2400pci_set_retry_limit, .conf_tx = rt2400pci_conf_tx, @@ -1635,7 +1651,6 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { .fill_rxdone = rt2400pci_fill_rxdone, .config_mac_addr = rt2400pci_config_mac_addr, .config_bssid = rt2400pci_config_bssid, - .config_packet_filter = rt2400pci_config_packet_filter, .config_type = rt2400pci_config_type, .config = rt2400pci_config, }; diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index e8d63aaab7bc..892baa907a6b 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -277,59 +277,14 @@ static void rt2500pci_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) rt2x00pci_register_multiwrite(rt2x00dev, CSR5, ®, sizeof(reg)); } -static void rt2500pci_config_packet_filter(struct rt2x00_dev *rt2x00dev, - const unsigned int filter) -{ - int promisc = !!(filter & IFF_PROMISC); - int multicast = !!(filter & IFF_MULTICAST); - int broadcast = !!(filter & IFF_BROADCAST); - u32 reg; - - rt2x00pci_register_read(rt2x00dev, RXCSR0, ®); - rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME, !promisc); - rt2x00_set_field32(®, RXCSR0_DROP_MCAST, !multicast); - rt2x00_set_field32(®, RXCSR0_DROP_BCAST, !broadcast); - rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); -} - static void rt2500pci_config_type(struct rt2x00_dev *rt2x00dev, const int type) { + struct interface *intf = &rt2x00dev->interface; u32 reg; rt2x00pci_register_write(rt2x00dev, CSR14, 0); /* - * Apply hardware packet filter. - */ - rt2x00pci_register_read(rt2x00dev, RXCSR0, ®); - - if (!is_monitor_present(&rt2x00dev->interface) && - (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_STA)) - rt2x00_set_field32(®, RXCSR0_DROP_TODS, 1); - else - rt2x00_set_field32(®, RXCSR0_DROP_TODS, 0); - - /* - * If there is a non-monitor interface present - * the packet should be strict (even if a monitor interface is present!). - * When there is only 1 interface present which is in monitor mode - * we should start accepting _all_ frames. - */ - if (is_interface_present(&rt2x00dev->interface)) { - rt2x00_set_field32(®, RXCSR0_DROP_CRC, 1); - rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, 1); - rt2x00_set_field32(®, RXCSR0_DROP_CONTROL, 1); - rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 1); - } else if (is_monitor_present(&rt2x00dev->interface)) { - rt2x00_set_field32(®, RXCSR0_DROP_CRC, 0); - rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, 0); - rt2x00_set_field32(®, RXCSR0_DROP_CONTROL, 0); - rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 0); - } - - rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); - - /* * Enable beacon config */ rt2x00pci_register_read(rt2x00dev, BCNCSR1, ®); @@ -345,20 +300,16 @@ static void rt2500pci_config_type(struct rt2x00_dev *rt2x00dev, const int type) * Enable synchronisation. */ rt2x00pci_register_read(rt2x00dev, CSR14, ®); - if (is_interface_present(&rt2x00dev->interface)) { - rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); - rt2x00_set_field32(®, CSR14_TBCN, 1); - } - + rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); + rt2x00_set_field32(®, CSR14_TBCN, 1); rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); - if (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_AP) + if (is_interface_type(intf, IEEE80211_IF_TYPE_IBSS) || + is_interface_type(intf, IEEE80211_IF_TYPE_AP)) rt2x00_set_field32(®, CSR14_TSF_SYNC, 2); - else if (type == IEEE80211_IF_TYPE_STA) + else if (is_interface_type(intf, IEEE80211_IF_TYPE_STA)) rt2x00_set_field32(®, CSR14_TSF_SYNC, 1); - else if (is_monitor_present(&rt2x00dev->interface) && - !is_interface_present(&rt2x00dev->interface)) + else rt2x00_set_field32(®, CSR14_TSF_SYNC, 0); - rt2x00pci_register_write(rt2x00dev, CSR14, reg); } @@ -1269,7 +1220,7 @@ static int rt2500pci_set_device_state(struct rt2x00_dev *rt2x00dev, */ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct data_desc *txd, - struct data_entry_desc *desc, + struct txdata_entry_desc *desc, struct ieee80211_hdr *ieee80211hdr, unsigned int length, struct ieee80211_tx_control *control) @@ -1349,8 +1300,8 @@ static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, /* * RX control handlers */ -static int rt2500pci_fill_rxdone(struct data_entry *entry, - int *signal, int *rssi, int *ofdm, int *size) +static void rt2500pci_fill_rxdone(struct data_entry *entry, + struct rxdata_entry_desc *desc) { struct data_desc *rxd = entry->priv; u32 word0; @@ -1359,18 +1310,17 @@ static int rt2500pci_fill_rxdone(struct data_entry *entry, rt2x00_desc_read(rxd, 0, &word0); rt2x00_desc_read(rxd, 2, &word2); - if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR) || - rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR) || - rt2x00_get_field32(word0, RXD_W0_ICV_ERROR)) - return -EINVAL; + desc->flags = 0; + if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) + desc->flags |= RX_FLAG_FAILED_FCS_CRC; + if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR)) + desc->flags |= RX_FLAG_FAILED_PLCP_CRC; - *signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL); - *rssi = rt2x00_get_field32(word2, RXD_W2_RSSI) - + desc->signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL); + desc->rssi = rt2x00_get_field32(word2, RXD_W2_RSSI) - entry->ring->rt2x00dev->rssi_offset; - *ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); - *size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); - - return 0; + desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); + desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); } /* @@ -1779,10 +1729,7 @@ static void rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) /* * Initialize all hw fields. */ - rt2x00dev->hw->flags = - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_MONITOR_DURING_OPER | - IEEE80211_HW_NO_PROBE_FILTERING; + rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; rt2x00dev->hw->extra_tx_headroom = 0; rt2x00dev->hw->max_signal = MAX_SIGNAL; rt2x00dev->hw->max_rssi = MAX_RX_SSI; @@ -1867,6 +1814,73 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ +static void rt2500pci_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, + struct dev_addr_list *mc_list) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct interface *intf = &rt2x00dev->interface; + u32 reg; + + /* + * Mask off any flags we are going to ignore from + * the total_flags field. + */ + *total_flags &= + FIF_ALLMULTI | + FIF_FCSFAIL | + FIF_PLCPFAIL | + FIF_CONTROL | + FIF_OTHER_BSS | + FIF_PROMISC_IN_BSS; + + /* + * Apply some rules to the filters: + * - Some filters imply different filters to be set. + * - Some things we can't filter out at all. + * - Some filters are set based on interface type. + */ + if (mc_count) + *total_flags |= FIF_ALLMULTI; + if (changed_flags & FIF_OTHER_BSS || + changed_flags & FIF_PROMISC_IN_BSS) + *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; + if (is_interface_type(intf, IEEE80211_IF_TYPE_AP)) + *total_flags |= FIF_PROMISC_IN_BSS; + + /* + * Check if there is any work left for us. + */ + if (intf->filter == *total_flags) + return; + intf->filter = *total_flags; + + /* + * Start configuration steps. + * Note that the version error will always be dropped + * and broadcast frames will always be accepted since + * there is no filter for it at this time. + */ + rt2x00pci_register_read(rt2x00dev, RXCSR0, ®); + rt2x00_set_field32(®, RXCSR0_DROP_CRC, + !(*total_flags & FIF_FCSFAIL)); + rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, + !(*total_flags & FIF_PLCPFAIL)); + rt2x00_set_field32(®, RXCSR0_DROP_CONTROL, + !(*total_flags & FIF_CONTROL)); + rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME, + !(*total_flags & FIF_PROMISC_IN_BSS)); + rt2x00_set_field32(®, RXCSR0_DROP_TODS, + !(*total_flags & FIF_PROMISC_IN_BSS)); + rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 1); + rt2x00_set_field32(®, RXCSR0_DROP_MCAST, + !(*total_flags & FIF_ALLMULTI)); + rt2x00_set_field32(®, RXCSR0_DROP_BCAST, 0); + rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); +} + static int rt2500pci_set_retry_limit(struct ieee80211_hw *hw, u32 short_retry, u32 long_retry) { @@ -1914,11 +1928,13 @@ static int rt2500pci_tx_last_beacon(struct ieee80211_hw *hw) static const struct ieee80211_ops rt2500pci_mac80211_ops = { .tx = rt2x00mac_tx, + .start = rt2x00mac_start, + .stop = rt2x00mac_stop, .add_interface = rt2x00mac_add_interface, .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, .config_interface = rt2x00mac_config_interface, - .set_multicast_list = rt2x00mac_set_multicast_list, + .configure_filter = rt2500pci_configure_filter, .get_stats = rt2x00mac_get_stats, .set_retry_limit = rt2500pci_set_retry_limit, .conf_tx = rt2x00mac_conf_tx, @@ -1947,7 +1963,6 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = { .fill_rxdone = rt2500pci_fill_rxdone, .config_mac_addr = rt2500pci_config_mac_addr, .config_bssid = rt2500pci_config_bssid, - .config_packet_filter = rt2500pci_config_packet_filter, .config_type = rt2500pci_config_type, .config = rt2500pci_config, }; diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 614600c5510d..f4e6f6eb7fb5 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -282,65 +282,20 @@ static void rt2500usb_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) rt2500usb_register_multiwrite(rt2x00dev, MAC_CSR5, ®, sizeof(reg)); } -static void rt2500usb_config_packet_filter(struct rt2x00_dev *rt2x00dev, - const unsigned int filter) -{ - int promisc = !!(filter & IFF_PROMISC); - int multicast = !!(filter & IFF_MULTICAST); - int broadcast = !!(filter & IFF_BROADCAST); - u16 reg; - - rt2500usb_register_read(rt2x00dev, TXRX_CSR2, ®); - rt2x00_set_field16(®, TXRX_CSR2_DROP_NOT_TO_ME, !promisc); - rt2x00_set_field16(®, TXRX_CSR2_DROP_MULTICAST, !multicast); - rt2x00_set_field16(®, TXRX_CSR2_DROP_BROADCAST, !broadcast); - rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg); -} - static void rt2500usb_config_type(struct rt2x00_dev *rt2x00dev, const int type) { + struct interface *intf = &rt2x00dev->interface; u16 reg; rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0); /* - * Apply hardware packet filter. - */ - rt2500usb_register_read(rt2x00dev, TXRX_CSR2, ®); - - if (!is_monitor_present(&rt2x00dev->interface) && - (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_STA)) - rt2x00_set_field16(®, TXRX_CSR2_DROP_TODS, 1); - else - rt2x00_set_field16(®, TXRX_CSR2_DROP_TODS, 0); - - /* - * If there is a non-monitor interface present - * the packet should be strict (even if a monitor interface is present!). - * When there is only 1 interface present which is in monitor mode - * we should start accepting _all_ frames. - */ - if (is_interface_present(&rt2x00dev->interface)) { - rt2x00_set_field16(®, TXRX_CSR2_DROP_CRC, 1); - rt2x00_set_field16(®, TXRX_CSR2_DROP_PHYSICAL, 1); - rt2x00_set_field16(®, TXRX_CSR2_DROP_CONTROL, 1); - rt2x00_set_field16(®, TXRX_CSR2_DROP_VERSION_ERROR, 1); - } else if (is_monitor_present(&rt2x00dev->interface)) { - rt2x00_set_field16(®, TXRX_CSR2_DROP_CRC, 0); - rt2x00_set_field16(®, TXRX_CSR2_DROP_PHYSICAL, 0); - rt2x00_set_field16(®, TXRX_CSR2_DROP_CONTROL, 0); - rt2x00_set_field16(®, TXRX_CSR2_DROP_VERSION_ERROR, 0); - } - - rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg); - - /* * Enable beacon config */ rt2500usb_register_read(rt2x00dev, TXRX_CSR20, ®); rt2x00_set_field16(®, TXRX_CSR20_OFFSET, (PREAMBLE + get_duration(IEEE80211_HEADER, 2)) >> 6); - if (type == IEEE80211_IF_TYPE_STA) + if (is_interface_type(intf, IEEE80211_IF_TYPE_STA)) rt2x00_set_field16(®, TXRX_CSR20_BCN_EXPECT_WINDOW, 0); else rt2x00_set_field16(®, TXRX_CSR20_BCN_EXPECT_WINDOW, 2); @@ -354,20 +309,16 @@ static void rt2500usb_config_type(struct rt2x00_dev *rt2x00dev, const int type) rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg); rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®); - if (is_interface_present(&rt2x00dev->interface)) { - rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 1); - rt2x00_set_field16(®, TXRX_CSR19_TBCN, 1); - } - + rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 1); + rt2x00_set_field16(®, TXRX_CSR19_TBCN, 1); rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 0); - if (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_AP) + if (is_interface_type(intf, IEEE80211_IF_TYPE_IBSS) || + is_interface_type(intf, IEEE80211_IF_TYPE_AP)) rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, 2); - else if (type == IEEE80211_IF_TYPE_STA) + else if (is_interface_type(intf, IEEE80211_IF_TYPE_STA)) rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, 1); - else if (is_monitor_present(&rt2x00dev->interface) && - !is_interface_present(&rt2x00dev->interface)) + else rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, 0); - rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); } @@ -1084,7 +1035,7 @@ static int rt2500usb_set_device_state(struct rt2x00_dev *rt2x00dev, */ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct data_desc *txd, - struct data_entry_desc *desc, + struct txdata_entry_desc *desc, struct ieee80211_hdr *ieee80211hdr, unsigned int length, struct ieee80211_tx_control *control) @@ -1156,8 +1107,8 @@ static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, /* * RX control handlers */ -static int rt2500usb_fill_rxdone(struct data_entry *entry, - int *signal, int *rssi, int *ofdm, int *size) +static void rt2500usb_fill_rxdone(struct data_entry *entry, + struct rxdata_entry_desc *desc) { struct urb *urb = entry->priv; struct data_desc *rxd = (struct data_desc *)(entry->skb->data + @@ -1169,21 +1120,22 @@ static int rt2500usb_fill_rxdone(struct data_entry *entry, rt2x00_desc_read(rxd, 0, &word0); rt2x00_desc_read(rxd, 1, &word1); - if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR) || - rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR) || - rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR)) - return -EINVAL; + desc->flags = 0; + if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) + desc->flags |= RX_FLAG_FAILED_FCS_CRC; + if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR)) + desc->flags |= RX_FLAG_FAILED_PLCP_CRC; /* * Obtain the status about this packet. */ - *signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); - *rssi = rt2x00_get_field32(word1, RXD_W1_RSSI) - + desc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); + desc->rssi = rt2x00_get_field32(word1, RXD_W1_RSSI) - entry->ring->rt2x00dev->rssi_offset; - *ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); - *size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); + desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); + desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); - return 0; + return; } /* @@ -1549,9 +1501,7 @@ static void rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) rt2x00dev->hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_MONITOR_DURING_OPER | - IEEE80211_HW_NO_PROBE_FILTERING; + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE; rt2x00dev->hw->max_signal = MAX_SIGNAL; rt2x00dev->hw->max_rssi = MAX_RX_SSI; @@ -1621,10 +1571,8 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) rt2500usb_probe_hw_mode(rt2x00dev); /* - * USB devices require scheduled packet filter toggling - *This device requires the beacon ring + * This device requires the beacon ring */ - __set_bit(PACKET_FILTER_SCHEDULED, &rt2x00dev->flags); __set_bit(REQUIRE_BEACON_RING, &rt2x00dev->flags); /* @@ -1638,6 +1586,82 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ +static void rt2500usb_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, + struct dev_addr_list *mc_list) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct interface *intf = &rt2x00dev->interface; + u16 reg; + + /* + * Mask off any flags we are going to ignore from + * the total_flags field. + */ + *total_flags &= + FIF_ALLMULTI | + FIF_FCSFAIL | + FIF_PLCPFAIL | + FIF_CONTROL | + FIF_OTHER_BSS | + FIF_PROMISC_IN_BSS; + + /* + * Apply some rules to the filters: + * - Some filters imply different filters to be set. + * - Some things we can't filter out at all. + * - Some filters are set based on interface type. + */ + if (mc_count) + *total_flags |= FIF_ALLMULTI; + if (changed_flags & FIF_OTHER_BSS || + changed_flags & FIF_PROMISC_IN_BSS) + *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; + if (is_interface_type(intf, IEEE80211_IF_TYPE_AP)) + *total_flags |= FIF_PROMISC_IN_BSS; + + /* + * Check if there is any work left for us. + */ + if (intf->filter == *total_flags) + return; + intf->filter = *total_flags; + + /* + * When in atomic context, reschedule and let rt2x00lib + * call this function again. + */ + if (in_atomic()) { + queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->filter_work); + return; + } + + /* + * Start configuration steps. + * Note that the version error will always be dropped + * and broadcast frames will always be accepted since + * there is no filter for it at this time. + */ + rt2500usb_register_read(rt2x00dev, TXRX_CSR2, ®); + rt2x00_set_field16(®, TXRX_CSR2_DROP_CRC, + !(*total_flags & FIF_FCSFAIL)); + rt2x00_set_field16(®, TXRX_CSR2_DROP_PHYSICAL, + !(*total_flags & FIF_PLCPFAIL)); + rt2x00_set_field16(®, TXRX_CSR2_DROP_CONTROL, + !(*total_flags & FIF_CONTROL)); + rt2x00_set_field16(®, TXRX_CSR2_DROP_NOT_TO_ME, + !(*total_flags & FIF_PROMISC_IN_BSS)); + rt2x00_set_field16(®, TXRX_CSR2_DROP_TODS, + !(*total_flags & FIF_PROMISC_IN_BSS)); + rt2x00_set_field16(®, TXRX_CSR2_DROP_VERSION_ERROR, 1); + rt2x00_set_field16(®, TXRX_CSR2_DROP_MULTICAST, + !(*total_flags & FIF_ALLMULTI)); + rt2x00_set_field16(®, TXRX_CSR2_DROP_BROADCAST, 0); + rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg); +} + static int rt2500usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_tx_control *control) @@ -1714,11 +1738,13 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw, static const struct ieee80211_ops rt2500usb_mac80211_ops = { .tx = rt2x00mac_tx, + .start = rt2x00mac_start, + .stop = rt2x00mac_stop, .add_interface = rt2x00mac_add_interface, .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, .config_interface = rt2x00mac_config_interface, - .set_multicast_list = rt2x00mac_set_multicast_list, + .configure_filter = rt2500usb_configure_filter, .get_stats = rt2x00mac_get_stats, .conf_tx = rt2x00mac_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, @@ -1739,7 +1765,6 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = { .fill_rxdone = rt2500usb_fill_rxdone, .config_mac_addr = rt2500usb_config_mac_addr, .config_bssid = rt2500usb_config_bssid, - .config_packet_filter = rt2500usb_config_packet_filter, .config_type = rt2500usb_config_type, .config = rt2500usb_config, }; diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 80b079d723d6..046eecfb16c0 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -294,9 +294,6 @@ struct interface { /* * Current working type (IEEE80211_IF_TYPE_*). - * This excludes the type IEEE80211_IF_TYPE_MNTR - * since that is counted seperately in the monitor_count - * field. * When set to INVALID_INTERFACE, no interface is configured. */ int type; @@ -314,18 +311,8 @@ struct interface { /* * Store the packet filter mode for the current interface. - * monitor mode always disabled filtering. But in such - * cases we still need to store the value here in case - * the monitor mode interfaces are removed, while a - * non-monitor mode interface remains. */ - unsigned short filter; - - /* - * Monitor mode count, the number of interfaces - * in monitor mode that that have been added. - */ - unsigned short monitor_count; + unsigned int filter; }; static inline int is_interface_present(struct interface *intf) @@ -333,9 +320,9 @@ static inline int is_interface_present(struct interface *intf) return !!intf->id; } -static inline int is_monitor_present(struct interface *intf) +static inline int is_interface_type(struct interface *intf, int type) { - return !!intf->monitor_count; + return intf->type == type; } /* @@ -402,7 +389,7 @@ struct rt2x00lib_ops { */ void (*write_tx_desc) (struct rt2x00_dev *rt2x00dev, struct data_desc *txd, - struct data_entry_desc *desc, + struct txdata_entry_desc *desc, struct ieee80211_hdr *ieee80211hdr, unsigned int length, struct ieee80211_tx_control *control); @@ -415,8 +402,8 @@ struct rt2x00lib_ops { /* * RX control handlers */ - int (*fill_rxdone) (struct data_entry *entry, - int *signal, int *rssi, int *ofdm, int *size); + void (*fill_rxdone) (struct data_entry *entry, + struct rxdata_entry_desc *desc); /* * Configuration handlers. @@ -511,11 +498,10 @@ struct rt2x00_dev { #define DEVICE_INITIALIZED 3 #define DEVICE_INITIALIZED_HW 4 #define REQUIRE_FIRMWARE 5 -#define PACKET_FILTER_SCHEDULED 6 -#define PACKET_FILTER_PENDING 7 +/* Hole: Add new Flag here */ #define INTERFACE_RESUME 8 #define INTERFACE_ENABLED 9 -#define INTERFACE_ENABLED_MONITOR 10 +/* Hole: Add new Flag here */ #define REQUIRE_BEACON_RING 11 #define DEVICE_SUPPORT_HW_BUTTON 12 #define CONFIG_FRAME_TYPE 13 @@ -606,9 +592,10 @@ struct rt2x00_dev { struct ieee80211_rx_status rx_status; /* - * Beacon scheduled work. + * Scheduled work. */ struct work_struct beacon_work; + struct work_struct filter_work; /* * Data ring arrays for RX, TX and Beacon. @@ -760,7 +747,7 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev); void rt2x00lib_txdone(struct data_entry *entry, const int status, const int retry); void rt2x00lib_rxdone(struct data_entry *entry, struct sk_buff *skb, - const int signal, const int rssi, const int ofdm); + struct rxdata_entry_desc *desc); /* * TX descriptor initializer @@ -785,8 +772,6 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw, int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf); int rt2x00mac_config_interface(struct ieee80211_hw *hw, int if_id, struct ieee80211_if_conf *conf); -void rt2x00mac_set_multicast_list(struct ieee80211_hw *hw, - unsigned short flags, int mc_count); int rt2x00mac_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats); int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index de890a17d8fd..f962ce497086 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -46,72 +46,24 @@ void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) rt2x00dev->ops->lib->config_bssid(rt2x00dev, bssid); } -void rt2x00lib_config_packet_filter(struct rt2x00_dev *rt2x00dev, int filter) -{ - /* - * Only configure the device when something has changed, - * or if we are in RESUME state in which case all configuration - * will be forced upon the device. - */ - if (!test_bit(INTERFACE_RESUME, &rt2x00dev->flags) && - !test_bit(PACKET_FILTER_PENDING, &rt2x00dev->flags)) - return; - - /* - * Write configuration to device and clear the update flag. - */ - rt2x00dev->ops->lib->config_packet_filter(rt2x00dev, filter); - __clear_bit(PACKET_FILTER_PENDING, &rt2x00dev->flags); -} - void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, int type) { struct interface *intf = &rt2x00dev->interface; - /* - * Fallback when a invalid interface is attempted to - * be configured. If a monitor interface is present, - * we are going configure that, otherwise exit. - */ - if (type == INVALID_INTERFACE) { - if (is_monitor_present(intf)) - type = IEEE80211_IF_TYPE_MNTR; - else - return; - } - - /* - * Only configure the device when something has changed, - * or if we are in RESUME state in which case all configuration - * will be forced upon the device. - */ if (!test_bit(INTERFACE_RESUME, &rt2x00dev->flags) && - (!(is_interface_present(intf) ^ - test_bit(INTERFACE_ENABLED, &rt2x00dev->flags)) && - !(is_monitor_present(intf) ^ - test_bit(INTERFACE_ENABLED_MONITOR, &rt2x00dev->flags)))) + (!!test_bit(INTERFACE_ENABLED, &rt2x00dev->flags) == + !!is_interface_present(intf))) return; - /* - * Configure device. - */ rt2x00dev->ops->lib->config_type(rt2x00dev, type); /* * Update the configuration flags. */ - if (type != IEEE80211_IF_TYPE_MNTR) { - if (is_interface_present(intf)) - __set_bit(INTERFACE_ENABLED, &rt2x00dev->flags); - else - __clear_bit(INTERFACE_ENABLED, &rt2x00dev->flags); - } else { - if (is_monitor_present(intf)) - __set_bit(INTERFACE_ENABLED_MONITOR, &rt2x00dev->flags); - else - __clear_bit(INTERFACE_ENABLED_MONITOR, - &rt2x00dev->flags); - } + if (is_interface_present(intf)) + __set_bit(INTERFACE_ENABLED, &rt2x00dev->flags); + else + __clear_bit(INTERFACE_ENABLED, &rt2x00dev->flags); } void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, struct ieee80211_conf *conf) diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index cd82eeface8f..bbccb8933876 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -135,10 +135,12 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev) return; /* - * Stop beacon generation. + * Stop all scheduled work. */ if (work_pending(&rt2x00dev->beacon_work)) cancel_work_sync(&rt2x00dev->beacon_work); + if (work_pending(&rt2x00dev->filter_work)) + cancel_work_sync(&rt2x00dev->filter_work); /* * Stop the TX queues. @@ -257,6 +259,17 @@ static void rt2x00lib_link_tuner(struct work_struct *work) LINK_TUNE_INTERVAL); } +static void rt2x00lib_packetfilter_scheduled(struct work_struct *work) +{ + struct rt2x00_dev *rt2x00dev = + container_of(work, struct rt2x00_dev, filter_work); + + rt2x00dev->ops->hw->configure_filter(rt2x00dev->hw, + rt2x00dev->interface.filter, + &rt2x00dev->interface.filter, + 0, NULL); +} + /* * Interrupt context handlers. */ @@ -337,7 +350,7 @@ void rt2x00lib_txdone(struct data_entry *entry, EXPORT_SYMBOL_GPL(rt2x00lib_txdone); void rt2x00lib_rxdone(struct data_entry *entry, struct sk_buff *skb, - const int signal, const int rssi, const int ofdm) + struct rxdata_entry_desc *desc) { struct rt2x00_dev *rt2x00dev = entry->ring->rt2x00dev; struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status; @@ -358,22 +371,24 @@ void rt2x00lib_rxdone(struct data_entry *entry, struct sk_buff *skb, * the signal is the PLCP value. If it was received with * a CCK bitrate the signal is the rate in 0.5kbit/s. */ - if (!ofdm) + if (!desc->ofdm) val = DEVICE_GET_RATE_FIELD(rate->val, RATE); else val = DEVICE_GET_RATE_FIELD(rate->val, PLCP); - if (val == signal) { + if (val == desc->signal) { val = rate->val; break; } } - rt2x00_update_link_rssi(&rt2x00dev->link, rssi); + rt2x00_update_link_rssi(&rt2x00dev->link, desc->rssi); rt2x00dev->link.rx_success++; rx_status->rate = val; - rx_status->signal = rt2x00lib_calculate_link_signal(rt2x00dev, rssi); - rx_status->ssi = rssi; + rx_status->signal = + rt2x00lib_calculate_link_signal(rt2x00dev, desc->rssi); + rx_status->ssi = desc->rssi; + rx_status->flag = desc->flags; /* * Send frame to mac80211 @@ -391,7 +406,7 @@ void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev, unsigned int length, struct ieee80211_tx_control *control) { - struct data_entry_desc desc; + struct txdata_entry_desc desc; struct data_ring *ring; int tx_rate; int bitrate; @@ -956,6 +971,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) * Initialize configuration work. */ INIT_WORK(&rt2x00dev->beacon_work, rt2x00lib_beacondone_scheduled); + INIT_WORK(&rt2x00dev->filter_work, rt2x00lib_packetfilter_scheduled); INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00lib_link_tuner); /* @@ -1098,7 +1114,6 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) rt2x00lib_config_mac_addr(rt2x00dev, intf->mac); rt2x00lib_config_bssid(rt2x00dev, intf->bssid); rt2x00lib_config_type(rt2x00dev, intf->type); - rt2x00lib_config_packet_filter(rt2x00dev, intf->filter); /* * When in Master or Ad-hoc mode, diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 3324090a96a7..fcc2ffdd1a3c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -51,7 +51,6 @@ void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev); */ void rt2x00lib_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *mac); void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid); -void rt2x00lib_config_packet_filter(struct rt2x00_dev *rt2x00dev, int filter); void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, int type); void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, struct ieee80211_conf *conf); diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 778ed41e21ef..17802f6d3d6d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -176,46 +176,26 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, { struct rt2x00_dev *rt2x00dev = hw->priv; struct interface *intf = &rt2x00dev->interface; - int retval; /* * We only support 1 non-monitor interface. */ - if (conf->type != IEEE80211_IF_TYPE_MNTR && is_interface_present(intf)) + if (is_interface_present(intf)) return -ENOBUFS; - /* - * HACK: Placeholder until start/stop handler has been - * added to the mac80211 callback functions structure. - */ - retval = rt2x00mac_start(hw); - if (retval) - return retval; - - /* - * We support muliple monitor mode interfaces. - * All we need to do is increase the monitor_count. - */ - if (conf->type == IEEE80211_IF_TYPE_MNTR) { - intf->monitor_count++; - } else { - intf->id = conf->if_id; - intf->type = conf->type; - if (conf->type == IEEE80211_IF_TYPE_AP) - memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN); - memcpy(&intf->mac, conf->mac_addr, ETH_ALEN); - intf->filter = 0; - } + intf->id = conf->if_id; + intf->type = conf->type; + if (conf->type == IEEE80211_IF_TYPE_AP) + memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN); + memcpy(&intf->mac, conf->mac_addr, ETH_ALEN); /* - * Configure interface. * The MAC adddress must be configured after the device - * has been initialized. Else the device can reset the - * MAC registers. + * has been initialized. Otherwise the device can reset + * the MAC registers. */ rt2x00lib_config_mac_addr(rt2x00dev, intf->mac); rt2x00lib_config_type(rt2x00dev, conf->type); - rt2x00lib_config_packet_filter(rt2x00dev, intf->filter); return 0; } @@ -230,22 +210,13 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw, /* * We only support 1 non-monitor interface. */ - if (conf->type != IEEE80211_IF_TYPE_MNTR && !is_interface_present(intf)) + if (!is_interface_present(intf)) return; - /* - * When removing an monitor interface, decrease monitor_count. - * For non-monitor interfaces, all interface data needs to be reset. - */ - if (conf->type == IEEE80211_IF_TYPE_MNTR) { - intf->monitor_count--; - } else if (intf->type == conf->type) { - intf->id = 0; - intf->type = INVALID_INTERFACE; - memset(&intf->bssid, 0x00, ETH_ALEN); - memset(&intf->mac, 0x00, ETH_ALEN); - intf->filter = 0; - } + intf->id = 0; + intf->type = INVALID_INTERFACE; + memset(&intf->bssid, 0x00, ETH_ALEN); + memset(&intf->mac, 0x00, ETH_ALEN); /* * Make sure the bssid and mac address registers @@ -254,12 +225,6 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw, rt2x00lib_config_mac_addr(rt2x00dev, intf->mac); rt2x00lib_config_bssid(rt2x00dev, intf->bssid); rt2x00lib_config_type(rt2x00dev, intf->type); - - /* - * HACK: Placeholder untill start/stop handler has been - * added to the mac80211 callback functions structure. - */ - rt2x00mac_stop(hw); } EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface); @@ -290,14 +255,6 @@ int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) rt2x00lib_config(rt2x00dev, conf); /* - * If promisc mode cannot be configured in irq context, - * then it is now the time to configure it. - */ - if (test_bit(PACKET_FILTER_SCHEDULED, &rt2x00dev->flags)) - rt2x00lib_config_packet_filter(rt2x00dev, - rt2x00dev->interface.filter); - - /* * Reenable RX only if the radio should be on. */ if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) @@ -326,13 +283,10 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw, int if_id, return 0; /* - * Monitor mode does not need configuring. * If the given type does not match the configured type, * there has been a problem. */ - if (conf->type == IEEE80211_IF_TYPE_MNTR) - return 0; - else if (conf->type != intf->type) + if (conf->type != intf->type) return -EINVAL; /* @@ -360,36 +314,6 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw, int if_id, } EXPORT_SYMBOL_GPL(rt2x00mac_config_interface); -void rt2x00mac_set_multicast_list(struct ieee80211_hw *hw, - unsigned short flags, int mc_count) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - - /* - * Check if the new state is different then the old state. - */ - if (rt2x00dev->interface.filter == flags) - return; - - rt2x00dev->interface.filter = flags; - - /* - * Raise the pending bit to indicate the - * packet filter should be updated. - */ - __set_bit(PACKET_FILTER_PENDING, &rt2x00dev->flags); - - /* - * Check if Packet filter actions are allowed in - * atomic context. If not, raise the pending flag and - * let it be. - */ - if (!test_bit(PACKET_FILTER_SCHEDULED, &rt2x00dev->flags) || - !in_atomic()) - rt2x00lib_config_packet_filter(rt2x00dev, flags); -} -EXPORT_SYMBOL_GPL(rt2x00mac_set_multicast_list); - int rt2x00mac_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats) { diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index 85629f1999ab..2780df00623c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -124,47 +124,40 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) struct data_entry *entry; struct data_desc *rxd; struct sk_buff *skb; - u32 desc; - int retval; - int signal; - int rssi; - int ofdm; - int size; + struct rxdata_entry_desc desc; + u32 word; while (1) { entry = rt2x00_get_data_entry(ring); rxd = entry->priv; - rt2x00_desc_read(rxd, 0, &desc); + rt2x00_desc_read(rxd, 0, &word); - if (rt2x00_get_field32(desc, RXD_ENTRY_OWNER_NIC)) + if (rt2x00_get_field32(word, RXD_ENTRY_OWNER_NIC)) break; - retval = rt2x00dev->ops->lib->fill_rxdone(entry, &signal, - &rssi, &ofdm, &size); - if (retval) - goto skip_entry; + memset(&desc, 0x00, sizeof(desc)); + rt2x00dev->ops->lib->fill_rxdone(entry, &desc); /* * Allocate the sk_buffer, initialize it and copy * all data into it. */ - skb = dev_alloc_skb(size + NET_IP_ALIGN); + skb = dev_alloc_skb(desc.size + NET_IP_ALIGN); if (!skb) return; skb_reserve(skb, NET_IP_ALIGN); - skb_put(skb, size); - memcpy(skb->data, entry->data_addr, size); + skb_put(skb, desc.size); + memcpy(skb->data, entry->data_addr, desc.size); /* * Send the frame to rt2x00lib for further processing. */ - rt2x00lib_rxdone(entry, skb, signal, rssi, ofdm); + rt2x00lib_rxdone(entry, skb, &desc); -skip_entry: if (test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) { - rt2x00_set_field32(&desc, RXD_ENTRY_OWNER_NIC, 1); - rt2x00_desc_write(rxd, 0, desc); + rt2x00_set_field32(&word, RXD_ENTRY_OWNER_NIC, 1); + rt2x00_desc_write(rxd, 0, word); } rt2x00_ring_index_inc(ring); diff --git a/drivers/net/wireless/rt2x00/rt2x00rfkill.c b/drivers/net/wireless/rt2x00/rt2x00rfkill.c index dc5b696f4751..b54457c921c5 100644 --- a/drivers/net/wireless/rt2x00/rt2x00rfkill.c +++ b/drivers/net/wireless/rt2x00/rt2x00rfkill.c @@ -45,11 +45,9 @@ static int rt2x00rfkill_toggle_radio(void *data, enum rfkill_state state) return 0; /* - * Only continue if we have an active interface, - * either monitor or non-monitor should be present. + * Only continue if we have an active interface. */ - if (!is_interface_present(&rt2x00dev->interface) && - !is_monitor_present(&rt2x00dev->interface)) + if (!is_interface_present(&rt2x00dev->interface)) return 0; if (state == RFKILL_STATE_ON) { diff --git a/drivers/net/wireless/rt2x00/rt2x00ring.h b/drivers/net/wireless/rt2x00/rt2x00ring.h index 122c75248e74..1a864d32cfbd 100644 --- a/drivers/net/wireless/rt2x00/rt2x00ring.h +++ b/drivers/net/wireless/rt2x00/rt2x00ring.h @@ -41,11 +41,24 @@ struct data_desc { }; /* - * data_entry_desc + * rxdata_entry_desc + * Summary of information that has been read from the + * RX frame descriptor. + */ +struct rxdata_entry_desc { + int signal; + int rssi; + int ofdm; + int size; + int flags; +}; + +/* + * txdata_entry_desc * Summary of information that should be written into the * descriptor for sending a TX frame. */ -struct data_entry_desc { +struct txdata_entry_desc { unsigned long flags; #define ENTRY_TXDONE 1 #define ENTRY_TXD_RTS_FRAME 2 diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index a0f05ca54bb4..8d2081189025 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -220,11 +220,7 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) struct data_ring *ring = entry->ring; struct rt2x00_dev *rt2x00dev = ring->rt2x00dev; struct sk_buff *skb; - int retval; - int signal; - int rssi; - int ofdm; - int size; + struct rxdata_entry_desc desc; int frame_size; if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || @@ -239,10 +235,8 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) if (urb->actual_length < entry->ring->desc_size || urb->status) goto skip_entry; - retval = rt2x00dev->ops->lib->fill_rxdone(entry, &signal, &rssi, - &ofdm, &size); - if (retval) - goto skip_entry; + memset(&desc, 0x00, sizeof(desc)); + rt2x00dev->ops->lib->fill_rxdone(entry, &desc); /* * Allocate a new sk buffer to replace the current one. @@ -261,12 +255,12 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) * Trim the skb_buffer to only contain the valid * frame data (so ignore the device's descriptor). */ - skb_trim(entry->skb, size); + skb_trim(entry->skb, desc.size); /* * Send the frame to rt2x00lib for further processing. */ - rt2x00lib_rxdone(entry, entry->skb, signal, rssi, ofdm); + rt2x00lib_rxdone(entry, entry->skb, &desc); /* * Replace current entry's skb with the newly allocated one, diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 09c8c96e2f83..dea7a8a4fa00 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -312,23 +312,9 @@ static void rt61pci_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) rt2x00pci_register_multiwrite(rt2x00dev, MAC_CSR4, ®, sizeof(reg)); } -static void rt61pci_config_packet_filter(struct rt2x00_dev *rt2x00dev, - const unsigned int filter) -{ - int promisc = !!(filter & IFF_PROMISC); - int multicast = !!(filter & IFF_MULTICAST); - int broadcast = !!(filter & IFF_BROADCAST); - u32 reg; - - rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); - rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, !promisc); - rt2x00_set_field32(®, TXRX_CSR0_DROP_MULTICAST, !multicast); - rt2x00_set_field32(®, TXRX_CSR0_DROP_BORADCAST, !broadcast); - rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); -} - static void rt61pci_config_type(struct rt2x00_dev *rt2x00dev, const int type) { + struct interface *intf = &rt2x00dev->interface; u32 reg; /* @@ -344,56 +330,19 @@ static void rt61pci_config_type(struct rt2x00_dev *rt2x00dev, const int type) rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE3, 0); /* - * Apply hardware packet filter. - */ - rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); - - if (!is_monitor_present(&rt2x00dev->interface) && - (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_STA)) - rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, 1); - else - rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, 0); - - /* - * If there is a non-monitor interface present - * the packet should be strict (even if a monitor interface is present!). - * When there is only 1 interface present which is in monitor mode - * we should start accepting _all_ frames. - */ - if (is_interface_present(&rt2x00dev->interface)) { - rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, 1); - rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, 1); - rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, 1); - rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 1); - rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 1); - } else if (is_monitor_present(&rt2x00dev->interface)) { - rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, 0); - rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, 0); - rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, 0); - rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 0); - rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 0); - } - - rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); - - /* * Enable synchronisation. */ rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®); - if (is_interface_present(&rt2x00dev->interface)) { - rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); - rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); - } - + rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); + rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); - if (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_AP) + if (is_interface_type(intf, IEEE80211_IF_TYPE_IBSS) || + is_interface_type(intf, IEEE80211_IF_TYPE_AP)) rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 2); - else if (type == IEEE80211_IF_TYPE_STA) + else if (is_interface_type(intf, IEEE80211_IF_TYPE_STA)) rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 1); - else if (is_monitor_present(&rt2x00dev->interface) && - !is_interface_present(&rt2x00dev->interface)) + else rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 0); - rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); } @@ -1686,7 +1635,7 @@ static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev, */ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct data_desc *txd, - struct data_entry_desc *desc, + struct txdata_entry_desc *desc, struct ieee80211_hdr *ieee80211hdr, unsigned int length, struct ieee80211_tx_control *control) @@ -1826,8 +1775,8 @@ static int rt61pci_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) return rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_AGC) * 2 - offset; } -static int rt61pci_fill_rxdone(struct data_entry *entry, - int *signal, int *rssi, int *ofdm, int *size) +static void rt61pci_fill_rxdone(struct data_entry *entry, + struct rxdata_entry_desc *desc) { struct data_desc *rxd = entry->priv; u32 word0; @@ -1836,19 +1785,19 @@ static int rt61pci_fill_rxdone(struct data_entry *entry, rt2x00_desc_read(rxd, 0, &word0); rt2x00_desc_read(rxd, 1, &word1); - if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR) || - rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR)) - return -EINVAL; + desc->flags = 0; + if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) + desc->flags |= RX_FLAG_FAILED_FCS_CRC; /* * Obtain the status about this packet. */ - *signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); - *rssi = rt61pci_agc_to_rssi(entry->ring->rt2x00dev, word1); - *ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); - *size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); + desc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); + desc->rssi = rt61pci_agc_to_rssi(entry->ring->rt2x00dev, word1); + desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); + desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); - return 0; + return; } /* @@ -2340,9 +2289,7 @@ static void rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) */ rt2x00dev->hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_MONITOR_DURING_OPER | - IEEE80211_HW_NO_PROBE_FILTERING; + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; rt2x00dev->hw->extra_tx_headroom = 0; rt2x00dev->hw->max_signal = MAX_SIGNAL; rt2x00dev->hw->max_rssi = MAX_RX_SSI; @@ -2426,6 +2373,74 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ +static void rt61pci_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, + struct dev_addr_list *mc_list) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct interface *intf = &rt2x00dev->interface; + u32 reg; + + /* + * Mask off any flags we are going to ignore from + * the total_flags field. + */ + *total_flags &= + FIF_ALLMULTI | + FIF_FCSFAIL | + FIF_PLCPFAIL | + FIF_CONTROL | + FIF_OTHER_BSS | + FIF_PROMISC_IN_BSS; + + /* + * Apply some rules to the filters: + * - Some filters imply different filters to be set. + * - Some things we can't filter out at all. + * - Some filters are set based on interface type. + */ + if (mc_count) + *total_flags |= FIF_ALLMULTI; + if (changed_flags & FIF_OTHER_BSS || + changed_flags & FIF_PROMISC_IN_BSS) + *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; + if (is_interface_type(intf, IEEE80211_IF_TYPE_AP)) + *total_flags |= FIF_PROMISC_IN_BSS; + + /* + * Check if there is any work left for us. + */ + if (intf->filter == *total_flags) + return; + intf->filter = *total_flags; + + /* + * Start configuration steps. + * Note that the version error will always be dropped + * and broadcast frames will always be accepted since + * there is no filter for it at this time. + */ + rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, + !(*total_flags & FIF_FCSFAIL)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, + !(*total_flags & FIF_PLCPFAIL)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, + !(*total_flags & FIF_CONTROL)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, + !(*total_flags & FIF_PROMISC_IN_BSS)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, + !(*total_flags & FIF_PROMISC_IN_BSS)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 1); + rt2x00_set_field32(®, TXRX_CSR0_DROP_MULTICAST, + !(*total_flags & FIF_ALLMULTI)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_BORADCAST, 0); + rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 1); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); +} + static int rt61pci_set_retry_limit(struct ieee80211_hw *hw, u32 short_retry, u32 long_retry) { @@ -2506,11 +2521,13 @@ int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, static const struct ieee80211_ops rt61pci_mac80211_ops = { .tx = rt2x00mac_tx, + .start = rt2x00mac_start, + .stop = rt2x00mac_stop, .add_interface = rt2x00mac_add_interface, .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, .config_interface = rt2x00mac_config_interface, - .set_multicast_list = rt2x00mac_set_multicast_list, + .configure_filter = rt61pci_configure_filter, .get_stats = rt2x00mac_get_stats, .set_retry_limit = rt61pci_set_retry_limit, .conf_tx = rt2x00mac_conf_tx, @@ -2540,7 +2557,6 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { .fill_rxdone = rt61pci_fill_rxdone, .config_mac_addr = rt61pci_config_mac_addr, .config_bssid = rt61pci_config_bssid, - .config_packet_filter = rt61pci_config_packet_filter, .config_type = rt61pci_config_type, .config = rt61pci_config, }; diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 3397881bd63d..aac13aa4039c 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -293,23 +293,9 @@ static void rt73usb_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) rt73usb_register_multiwrite(rt2x00dev, MAC_CSR4, ®, sizeof(reg)); } -static void rt73usb_config_packet_filter(struct rt2x00_dev *rt2x00dev, - const unsigned int filter) -{ - int promisc = !!(filter & IFF_PROMISC); - int multicast = !!(filter & IFF_MULTICAST); - int broadcast = !!(filter & IFF_BROADCAST); - u32 reg; - - rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); - rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, !promisc); - rt2x00_set_field32(®, TXRX_CSR0_DROP_MULTICAST, !multicast); - rt2x00_set_field32(®, TXRX_CSR0_DROP_BORADCAST, !broadcast); - rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); -} - static void rt73usb_config_type(struct rt2x00_dev *rt2x00dev, const int type) { + struct interface *intf = &rt2x00dev->interface; u32 reg; /* @@ -325,56 +311,19 @@ static void rt73usb_config_type(struct rt2x00_dev *rt2x00dev, const int type) rt73usb_register_write(rt2x00dev, HW_BEACON_BASE3, 0); /* - * Apply hardware packet filter. - */ - rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); - - if (!is_monitor_present(&rt2x00dev->interface) && - (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_STA)) - rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, 1); - else - rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, 0); - - /* - * If there is a non-monitor interface present - * the packet should be strict (even if a monitor interface is present!). - * When there is only 1 interface present which is in monitor mode - * we should start accepting _all_ frames. - */ - if (is_interface_present(&rt2x00dev->interface)) { - rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, 1); - rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, 1); - rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, 1); - rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 1); - rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 1); - } else if (is_monitor_present(&rt2x00dev->interface)) { - rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, 0); - rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, 0); - rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, 0); - rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 0); - rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 0); - } - - rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); - - /* * Enable synchronisation. */ rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®); - if (is_interface_present(&rt2x00dev->interface)) { - rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); - rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); - } - + rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); + rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); - if (type == IEEE80211_IF_TYPE_IBSS || type == IEEE80211_IF_TYPE_AP) + if (is_interface_type(intf, IEEE80211_IF_TYPE_IBSS) || + is_interface_type(intf, IEEE80211_IF_TYPE_AP)) rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 2); - else if (type == IEEE80211_IF_TYPE_STA) + else if (is_interface_type(intf, IEEE80211_IF_TYPE_STA)) rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 1); - else if (is_monitor_present(&rt2x00dev->interface) && - !is_interface_present(&rt2x00dev->interface)) + else rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 0); - rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); } @@ -1301,7 +1250,7 @@ static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev, */ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, struct data_desc *txd, - struct data_entry_desc *desc, + struct txdata_entry_desc *desc, struct ieee80211_hdr *ieee80211hdr, unsigned int length, struct ieee80211_tx_control *control) @@ -1429,8 +1378,8 @@ static int rt73usb_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) return rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_AGC) * 2 - offset; } -static int rt73usb_fill_rxdone(struct data_entry *entry, - int *signal, int *rssi, int *ofdm, int *size) +static void rt73usb_fill_rxdone(struct data_entry *entry, + struct rxdata_entry_desc *desc) { struct data_desc *rxd = (struct data_desc *)entry->skb->data; u32 word0; @@ -1439,24 +1388,24 @@ static int rt73usb_fill_rxdone(struct data_entry *entry, rt2x00_desc_read(rxd, 0, &word0); rt2x00_desc_read(rxd, 1, &word1); - if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR) || - rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR)) - return -EINVAL; + desc->flags = 0; + if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR)) + desc->flags |= RX_FLAG_FAILED_FCS_CRC; /* * Obtain the status about this packet. */ - *signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); - *rssi = rt73usb_agc_to_rssi(entry->ring->rt2x00dev, word1); - *ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); - *size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); + desc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); + desc->rssi = rt73usb_agc_to_rssi(entry->ring->rt2x00dev, word1); + desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); + desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); /* * Pull the skb to clear the descriptor area. */ skb_pull(entry->skb, entry->ring->desc_size); - return 0; + return; } /* @@ -1802,9 +1751,7 @@ static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) */ rt2x00dev->hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_MONITOR_DURING_OPER | - IEEE80211_HW_NO_PROBE_FILTERING; + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE; rt2x00dev->hw->max_signal = MAX_SIGNAL; rt2x00dev->hw->max_rssi = MAX_RX_SSI; @@ -1878,11 +1825,9 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) rt73usb_probe_hw_mode(rt2x00dev); /* - * USB devices require scheduled packet filter toggling * This device requires firmware */ __set_bit(REQUIRE_FIRMWARE, &rt2x00dev->flags); - __set_bit(PACKET_FILTER_SCHEDULED, &rt2x00dev->flags); /* * Set the rssi offset. @@ -1895,6 +1840,83 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ +static void rt73usb_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, + struct dev_addr_list *mc_list) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct interface *intf = &rt2x00dev->interface; + u32 reg; + + /* + * Mask off any flags we are going to ignore from + * the total_flags field. + */ + *total_flags &= + FIF_ALLMULTI | + FIF_FCSFAIL | + FIF_PLCPFAIL | + FIF_CONTROL | + FIF_OTHER_BSS | + FIF_PROMISC_IN_BSS; + + /* + * Apply some rules to the filters: + * - Some filters imply different filters to be set. + * - Some things we can't filter out at all. + * - Some filters are set based on interface type. + */ + if (mc_count) + *total_flags |= FIF_ALLMULTI; + if (changed_flags & FIF_OTHER_BSS || + changed_flags & FIF_PROMISC_IN_BSS) + *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; + if (is_interface_type(intf, IEEE80211_IF_TYPE_AP)) + *total_flags |= FIF_PROMISC_IN_BSS; + + /* + * Check if there is any work left for us. + */ + if (intf->filter == *total_flags) + return; + intf->filter = *total_flags; + + /* + * When in atomic context, reschedule and let rt2x00lib + * call this function again. + */ + if (in_atomic()) { + queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->filter_work); + return; + } + + /* + * Start configuration steps. + * Note that the version error will always be dropped + * and broadcast frames will always be accepted since + * there is no filter for it at this time. + */ + rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, + !(*total_flags & FIF_FCSFAIL)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, + !(*total_flags & FIF_PLCPFAIL)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, + !(*total_flags & FIF_CONTROL)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, + !(*total_flags & FIF_PROMISC_IN_BSS)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, + !(*total_flags & FIF_PROMISC_IN_BSS)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 1); + rt2x00_set_field32(®, TXRX_CSR0_DROP_MULTICAST, + !(*total_flags & FIF_ALLMULTI)); + rt2x00_set_field32(®, TXRX_CSR0_DROP_BROADCAST, 0); + rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, 1); + rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); +} + static int rt73usb_set_retry_limit(struct ieee80211_hw *hw, u32 short_retry, u32 long_retry) { @@ -1977,11 +1999,13 @@ int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, static const struct ieee80211_ops rt73usb_mac80211_ops = { .tx = rt2x00mac_tx, + .start = rt2x00mac_start, + .stop = rt2x00mac_stop, .add_interface = rt2x00mac_add_interface, .remove_interface = rt2x00mac_remove_interface, .config = rt2x00mac_config, .config_interface = rt2x00mac_config_interface, - .set_multicast_list = rt2x00mac_set_multicast_list, + .configure_filter = rt73usb_configure_filter, .get_stats = rt2x00mac_get_stats, .set_retry_limit = rt73usb_set_retry_limit, .conf_tx = rt2x00mac_conf_tx, @@ -2012,7 +2036,6 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { .fill_rxdone = rt73usb_fill_rxdone, .config_mac_addr = rt73usb_config_mac_addr, .config_bssid = rt73usb_config_bssid, - .config_packet_filter = rt73usb_config_packet_filter, .config_type = rt73usb_config_type, .config = rt73usb_config, }; diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h index 5d63a1a714f3..f0951519f74b 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.h +++ b/drivers/net/wireless/rt2x00/rt73usb.h @@ -290,7 +290,7 @@ struct hw_pairwise_ta_entry { #define TXRX_CSR0_DROP_TO_DS FIELD32(0x00200000) #define TXRX_CSR0_DROP_VERSION_ERROR FIELD32(0x00400000) #define TXRX_CSR0_DROP_MULTICAST FIELD32(0x00800000) -#define TXRX_CSR0_DROP_BORADCAST FIELD32(0x01000000) +#define TXRX_CSR0_DROP_BROADCAST FIELD32(0x01000000) #define TXRX_CSR0_DROP_ACK_CTS FIELD32(0x02000000) #define TXRX_CSR0_TX_WITHOUT_WAITING FIELD32(0x04000000) diff --git a/drivers/net/wireless/rtl8187.h b/drivers/net/wireless/rtl8187.h index 7993b3d87203..6ad322ef0da1 100644 --- a/drivers/net/wireless/rtl8187.h +++ b/drivers/net/wireless/rtl8187.h @@ -36,8 +36,7 @@ struct rtl8187_rx_info { }; struct rtl8187_rx_hdr { - __le16 len; - __le16 rate; + __le32 flags; u8 noise; u8 signal; u8 agc; @@ -74,7 +73,7 @@ struct rtl8187_priv { struct ieee80211_rate rates[12]; struct ieee80211_hw_mode modes[2]; struct usb_device *udev; - u8 *hwaddr; + u32 rx_conf; u16 txpwr_base; u8 asic_rev; struct sk_buff_head rx_queue; diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index bf9f0cc5a645..b0a92f543da4 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -41,6 +41,57 @@ static struct usb_device_id rtl8187_table[] __devinitdata = { MODULE_DEVICE_TABLE(usb, rtl8187_table); +static void rtl8187_iowrite_async_cb(struct urb *urb) +{ + kfree(urb->context); + usb_free_urb(urb); +} + +static void rtl8187_iowrite_async(struct rtl8187_priv *priv, __le16 addr, + void *data, u16 len) +{ + struct usb_ctrlrequest *dr; + struct urb *urb; + struct rtl8187_async_write_data { + u8 data[4]; + struct usb_ctrlrequest dr; + } *buf; + + buf = kmalloc(sizeof(*buf), GFP_ATOMIC); + if (!buf) + return; + + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!urb) { + kfree(buf); + return; + } + + dr = &buf->dr; + + dr->bRequestType = RTL8187_REQT_WRITE; + dr->bRequest = RTL8187_REQ_SET_REG; + dr->wValue = addr; + dr->wIndex = 0; + dr->wLength = cpu_to_le16(len); + + memcpy(buf, data, len); + + usb_fill_control_urb(urb, priv->udev, usb_sndctrlpipe(priv->udev, 0), + (unsigned char *)dr, buf, len, + rtl8187_iowrite_async_cb, buf); + usb_submit_urb(urb, GFP_ATOMIC); +} + +static inline void rtl818x_iowrite32_async(struct rtl8187_priv *priv, + __le32 *addr, u32 val) +{ + __le32 buf = cpu_to_le32(val); + + rtl8187_iowrite_async(priv, cpu_to_le16((unsigned long)addr), + &buf, sizeof(buf)); +} + void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data) { struct rtl8187_priv *priv = dev->priv; @@ -125,6 +176,7 @@ static void rtl8187_rx_cb(struct urb *urb) struct rtl8187_rx_hdr *hdr; struct ieee80211_rx_status rx_status = { 0 }; int rate, signal; + u32 flags; spin_lock(&priv->rx_queue.lock); if (skb->next) @@ -143,10 +195,11 @@ static void rtl8187_rx_cb(struct urb *urb) skb_put(skb, urb->actual_length); hdr = (struct rtl8187_rx_hdr *)(skb_tail_pointer(skb) - sizeof(*hdr)); - skb_trim(skb, le16_to_cpu(hdr->len) & 0x0FFF); + flags = le32_to_cpu(hdr->flags); + skb_trim(skb, flags & 0x0FFF); signal = hdr->agc >> 1; - rate = (le16_to_cpu(hdr->rate) >> 4) & 0xF; + rate = (flags >> 20) & 0xF; if (rate > 3) { /* OFDM rate */ if (signal > 90) signal = 90; @@ -169,6 +222,8 @@ static void rtl8187_rx_cb(struct urb *urb) rx_status.channel = dev->conf.channel; rx_status.phymode = dev->conf.phymode; rx_status.mactime = le64_to_cpu(hdr->mac_time); + if (flags & (1 << 13)) + rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; ieee80211_rx_irqsafe(dev, skb, &rx_status); skb = dev_alloc_skb(RTL8187_MAX_RX); @@ -293,8 +348,6 @@ static int rtl8187_init_hw(struct ieee80211_hw *dev) rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - for (i = 0; i < ETH_ALEN; i++) - rtl818x_iowrite8(priv, &priv->map->MAC[i], priv->hwaddr[i]); rtl818x_iowrite16(priv, (__le16 *)0xFFF4, 0xFFFF); reg = rtl818x_ioread8(priv, &priv->map->CONFIG1); @@ -365,7 +418,7 @@ static void rtl8187_set_channel(struct ieee80211_hw *dev, int channel) rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg); } -static int rtl8187_open(struct ieee80211_hw *dev) +static int rtl8187_start(struct ieee80211_hw *dev) { struct rtl8187_priv *priv = dev->priv; u32 reg; @@ -383,16 +436,13 @@ static int rtl8187_open(struct ieee80211_hw *dev) RTL818X_RX_CONF_RX_AUTORESETPHY | RTL818X_RX_CONF_BSSID | RTL818X_RX_CONF_MGMT | - RTL818X_RX_CONF_CTRL | RTL818X_RX_CONF_DATA | (7 << 13 /* RX FIFO threshold NONE */) | (7 << 10 /* MAX RX DMA */) | RTL818X_RX_CONF_BROADCAST | - RTL818X_RX_CONF_MULTICAST | RTL818X_RX_CONF_NICMAC; - if (priv->mode == IEEE80211_IF_TYPE_MNTR) - reg |= RTL818X_RX_CONF_MONITOR; + priv->rx_conf = reg; rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg); reg = rtl818x_ioread8(priv, &priv->map->CW_CONF); @@ -419,7 +469,7 @@ static int rtl8187_open(struct ieee80211_hw *dev) return 0; } -static int rtl8187_stop(struct ieee80211_hw *dev) +static void rtl8187_stop(struct ieee80211_hw *dev) { struct rtl8187_priv *priv = dev->priv; struct rtl8187_rx_info *info; @@ -445,28 +495,31 @@ static int rtl8187_stop(struct ieee80211_hw *dev) usb_kill_urb(info->urb); kfree_skb(skb); } - return 0; + return; } static int rtl8187_add_interface(struct ieee80211_hw *dev, struct ieee80211_if_init_conf *conf) { struct rtl8187_priv *priv = dev->priv; + int i; - /* NOTE: using IEEE80211_IF_TYPE_MGMT to indicate no mode selected */ - if (priv->mode != IEEE80211_IF_TYPE_MGMT) - return -1; + if (priv->mode != IEEE80211_IF_TYPE_MNTR) + return -EOPNOTSUPP; switch (conf->type) { case IEEE80211_IF_TYPE_STA: - case IEEE80211_IF_TYPE_MNTR: priv->mode = conf->type; break; default: return -EOPNOTSUPP; } - priv->hwaddr = conf->mac_addr ? conf->mac_addr : dev->wiphy->perm_addr; + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + for (i = 0; i < ETH_ALEN; i++) + rtl818x_iowrite8(priv, &priv->map->MAC[i], + ((u8 *)conf->mac_addr)[i]); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); return 0; } @@ -475,7 +528,7 @@ static void rtl8187_remove_interface(struct ieee80211_hw *dev, struct ieee80211_if_init_conf *conf) { struct rtl8187_priv *priv = dev->priv; - priv->mode = IEEE80211_IF_TYPE_MGMT; + priv->mode = IEEE80211_IF_TYPE_MNTR; } static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) @@ -523,14 +576,52 @@ static int rtl8187_config_interface(struct ieee80211_hw *dev, int if_id, return 0; } +static void rtl8187_configure_filter(struct ieee80211_hw *dev, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, struct dev_addr_list *mc_list) +{ + struct rtl8187_priv *priv = dev->priv; + + *total_flags = 0; + + if (changed_flags & FIF_PROMISC_IN_BSS) + priv->rx_conf ^= RTL818X_RX_CONF_NICMAC; + if (changed_flags & FIF_ALLMULTI) + priv->rx_conf ^= RTL818X_RX_CONF_MULTICAST; + if (changed_flags & FIF_FCSFAIL) + priv->rx_conf ^= RTL818X_RX_CONF_FCS; + if (changed_flags & FIF_CONTROL) + priv->rx_conf ^= RTL818X_RX_CONF_CTRL; + if (changed_flags & FIF_OTHER_BSS) + priv->rx_conf ^= RTL818X_RX_CONF_MONITOR; + + if (mc_count > 0) + priv->rx_conf |= RTL818X_RX_CONF_MULTICAST; + + if (priv->rx_conf & RTL818X_RX_CONF_NICMAC) + *total_flags |= FIF_PROMISC_IN_BSS; + if (priv->rx_conf & RTL818X_RX_CONF_MULTICAST) + *total_flags |= FIF_ALLMULTI; + if (priv->rx_conf & RTL818X_RX_CONF_FCS) + *total_flags |= FIF_FCSFAIL; + if (priv->rx_conf & RTL818X_RX_CONF_CTRL) + *total_flags |= FIF_CONTROL; + if (priv->rx_conf & RTL818X_RX_CONF_MONITOR) + *total_flags |= FIF_OTHER_BSS; + + rtl818x_iowrite32_async(priv, &priv->map->RX_CONF, priv->rx_conf); +} + static const struct ieee80211_ops rtl8187_ops = { .tx = rtl8187_tx, - .open = rtl8187_open, + .start = rtl8187_start, .stop = rtl8187_stop, .add_interface = rtl8187_add_interface, .remove_interface = rtl8187_remove_interface, .config = rtl8187_config, .config_interface = rtl8187_config_interface, + .configure_filter = rtl8187_configure_filter, }; static void rtl8187_eeprom_register_read(struct eeprom_93cx6 *eeprom) @@ -604,7 +695,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, priv->modes[1].rates = priv->rates; priv->modes[1].num_channels = ARRAY_SIZE(rtl818x_channels); priv->modes[1].channels = priv->channels; - priv->mode = IEEE80211_IF_TYPE_MGMT; + priv->mode = IEEE80211_IF_TYPE_MNTR; dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_RX_INCLUDES_FCS; dev->extra_tx_headroom = sizeof(struct rtl8187_tx_hdr); diff --git a/drivers/net/wireless/rtl818x.h b/drivers/net/wireless/rtl818x.h index 283de30628e1..880d4becae31 100644 --- a/drivers/net/wireless/rtl818x.h +++ b/drivers/net/wireless/rtl818x.h @@ -71,6 +71,7 @@ struct rtl818x_csr { #define RTL818X_RX_CONF_NICMAC (1 << 1) #define RTL818X_RX_CONF_MULTICAST (1 << 2) #define RTL818X_RX_CONF_BROADCAST (1 << 3) +#define RTL818X_RX_CONF_FCS (1 << 5) #define RTL818X_RX_CONF_DATA (1 << 18) #define RTL818X_RX_CONF_CTRL (1 << 19) #define RTL818X_RX_CONF_MGMT (1 << 20) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 5ff45553a985..855754d4c50d 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -467,7 +467,6 @@ enum ieee80211_if_types { * @mac_addr: pointer to MAC address of the interface. This pointer is valid * until the interface is removed (i.e. it cannot be used after * remove_interface() callback was called for this interface). - * This pointer will be %NULL for monitor interfaces, be careful. * * This structure is used in add_interface() and remove_interface() * callbacks of &struct ieee80211_hw. @@ -653,13 +652,9 @@ struct ieee80211_hw { /* hole at 8 */ - /* Device is capable of performing full monitor mode even during - * normal operation. */ -#define IEEE80211_HW_MONITOR_DURING_OPER (1<<9) +/* hole at 9 */ - /* Device does not need BSSID filter set to broadcast in order to - * receive all probe responses while scanning */ -#define IEEE80211_HW_NO_PROBE_FILTERING (1<<10) +/* hole at 10 */ /* Channels are already configured to the default regulatory domain * specified in the device's EEPROM */ @@ -694,6 +689,39 @@ static inline void SET_IEEE80211_PERM_ADDR(struct ieee80211_hw *hw, u8 *addr) memcpy(hw->wiphy->perm_addr, addr, ETH_ALEN); } +/* + * flags for change_filter_flags() + * + * Note that e.g. if PROMISC_IN_BSS is unset then + * you should still do MAC address filtering if + * possible even if OTHER_BSS is set to indicate + * no BSSID filtering should be done. + */ +/* + * promiscuous mode within your BSS, + * think of the BSS as your network segment and then this corresponds + * to the regular ethernet device promiscuous mode + */ +#define FIF_PROMISC_IN_BSS 0x01 +/* show all multicast frames */ +#define FIF_ALLMULTI 0x02 +/* show frames with failed FCS, but set RX_FLAG_FAILED_FCS_CRC for them */ +#define FIF_FCSFAIL 0x04 +/* show frames with failed PLCP CRC, but set RX_FLAG_FAILED_PLCP_CRC for them */ +#define FIF_PLCPFAIL 0x08 +/* + * This flag is set during scanning to indicate to the hardware + * that it should not filter beacons or probe responses by BSSID. + */ +#define FIF_BCN_PRBRESP_PROMISC 0x10 +/* + * show control frames, if PROMISC_IN_BSS is not set then + * only those addressed to this station + */ +#define FIF_CONTROL 0x20 +/* show frames from other BSSes */ +#define FIF_OTHER_BSS 0x40 + /* Configuration block used by the low-level driver to tell the 802.11 code * about supported hardware features and to pass function pointers to callback * functions. */ @@ -706,32 +734,55 @@ struct ieee80211_ops { int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_tx_control *control); - /* Handler that is called when any netdevice attached to the hardware - * device is set UP for the first time. This can be used, e.g., to - * enable interrupts and beacon sending. */ - int (*open)(struct ieee80211_hw *hw); - - /* Handler that is called when the last netdevice attached to the - * hardware device is set DOWN. This can be used, e.g., to disable - * interrupts and beacon sending. */ - int (*stop)(struct ieee80211_hw *hw); - - /* Handler for asking a driver if a new interface can be added (or, - * more exactly, set UP). If the handler returns zero, the interface - * is added. Driver should perform any initialization it needs prior - * to returning zero. By returning non-zero addition of the interface - * is inhibited. Unless monitor_during_oper is set, it is guaranteed - * that monitor interfaces and normal interfaces are mutually - * exclusive. If assigned, the open() handler is called after - * add_interface() if this is the first device added. The - * add_interface() callback has to be assigned because it is the only - * way to obtain the requested MAC address for any interface. + /* + * Called before the first netdevice attached to the hardware + * is enabled. This should turn on the hardware and must turn on + * frame reception (for possibly enabled monitor interfaces.) + * Returns negative error codes, these may be seen in userspace, + * or zero. + * When the device is started it should not have a MAC address + * to avoid acknowledging frames before a non-monitor device + * is added. + * + * Must be implemented. + */ + int (*start)(struct ieee80211_hw *hw); + + /* + * Called after last netdevice attached to the hardware + * is disabled. This should turn off the hardware (at least + * it must turn off frame reception.) + * May be called right after add_interface if that rejects + * an interface. + * + * Must be implemented. + */ + void (*stop)(struct ieee80211_hw *hw); + + /* + * Called when a netdevice attached to the hardware is enabled. + * Because it is not called for monitor mode devices, open() + * and stop() must be implemented. + * The driver should perform any initialization it needs before + * the device can be enabled. The initial configuration for the + * interface is given in the conf parameter. + * + * Must be implemented. */ int (*add_interface)(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); - /* Notify a driver that an interface is going down. The stop() handler - * is called prior to this if this is a last interface. */ + /* + * Notifies a driver that an interface is going down. The stop() handler + * is called after this if it is the last interface and no monitor + * interfaces are present. + * When all interfaces are removed, the MAC address in the hardware + * must be cleared so the device no longer acknowledges packets, + * the mac_addr member of the conf structure is, however, set to the + * MAC address of the device going away. + * + * Hence, this callback must be implemented. + */ void (*remove_interface)(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); @@ -744,15 +795,21 @@ struct ieee80211_ops { int (*config_interface)(struct ieee80211_hw *hw, int if_id, struct ieee80211_if_conf *conf); - /* ieee80211 drivers do not have access to the &struct net_device - * that is (are) connected with their device. Hence (and because - * we need to combine the multicast lists and flags for multiple - * virtual interfaces), they cannot assign set_multicast_list. - * The parameters here replace dev->flags and dev->mc_count, - * dev->mc_list is replaced by calling ieee80211_get_mc_list_item. - * Must be atomic. */ - void (*set_multicast_list)(struct ieee80211_hw *hw, - unsigned short flags, int mc_count); + /* + * Configure the device's RX filter. + * + * The multicast address filter must be changed if the hardware flags + * indicate that one is present. + * + * All unsupported flags in 'total_flags' must be cleared, + * clear all bits except those you honoured. + * + * The callback must be implemented and must be atomic. + */ + void (*configure_filter)(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, struct dev_addr_list *mc_list); /* Set TIM bit handler. If the hardware/firmware takes care of beacon * generation, IEEE 802.11 code uses this function to tell the @@ -1155,24 +1212,6 @@ void ieee80211_stop_queues(struct ieee80211_hw *hw); */ void ieee80211_wake_queues(struct ieee80211_hw *hw); -/** - * ieee80211_get_mc_list_item - iteration over items in multicast list - * @hw: pointer as obtained from ieee80211_alloc_hw(). - * @prev: value returned by previous call to ieee80211_get_mc_list_item() or - * NULL to start a new iteration. - * @ptr: pointer to buffer of void * type for internal usage of - * ieee80211_get_mc_list_item(). - * - * Iterates over items in multicast list of given device. To get the first - * item, pass NULL in @prev and in *@ptr. In subsequent calls, pass the - * value returned by previous call in @prev. Don't alter *@ptr during - * iteration. When there are no more items, NULL is returned. - */ -struct dev_mc_list * -ieee80211_get_mc_list_item(struct ieee80211_hw *hw, - struct dev_mc_list *prev, - void **ptr); - /* called by driver to notify scan status completed */ void ieee80211_scan_completed(struct ieee80211_hw *hw); diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 9efb84c47bb0..c9948fa58e08 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -165,20 +165,6 @@ IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC); /* VLAN attributes */ IEEE80211_IF_FILE(vlan_id, u.vlan.id, DEC); -/* MONITOR attributes */ -static ssize_t ieee80211_if_fmt_mode( - const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) -{ - struct ieee80211_local *local = sdata->local; - - return scnprintf(buf, buflen, "%s\n", - ((local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER) || - local->open_count == local->monitors) ? - "hard" : "soft"); -} -__IEEE80211_IF_FILE(mode); - - #define DEBUGFS_ADD(name, type)\ sdata->debugfs.type.name = debugfs_create_file(#name, 0444,\ sdata->debugfsdir, sdata, &name##_ops); @@ -242,7 +228,6 @@ static void add_vlan_files(struct ieee80211_sub_if_data *sdata) static void add_monitor_files(struct ieee80211_sub_if_data *sdata) { - DEBUGFS_ADD(mode, monitor); } static void add_files(struct ieee80211_sub_if_data *sdata) @@ -337,7 +322,6 @@ static void del_vlan_files(struct ieee80211_sub_if_data *sdata) static void del_monitor_files(struct ieee80211_sub_if_data *sdata) { - DEBUGFS_DEL(mode, monitor); } static void del_files(struct ieee80211_sub_if_data *sdata, int type) diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 57ec8880bb1a..319ec2a1d84f 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -53,6 +53,38 @@ static int header_parse_80211(const struct sk_buff *skb, unsigned char *haddr) return ETH_ALEN; } +/* must be called under mdev tx lock */ +static void ieee80211_configure_filter(struct ieee80211_local *local) +{ + unsigned int changed_flags; + unsigned int new_flags = 0; + + if (local->iff_promiscs) + new_flags |= FIF_PROMISC_IN_BSS; + + if (local->iff_allmultis) + new_flags |= FIF_ALLMULTI; + + if (local->monitors) + new_flags |= FIF_CONTROL | + FIF_OTHER_BSS | + FIF_BCN_PRBRESP_PROMISC; + + changed_flags = local->filter_flags ^ new_flags; + + /* be a bit nasty */ + new_flags |= (1<<31); + + local->ops->configure_filter(local_to_hw(local), + changed_flags, &new_flags, + local->mdev->mc_count, + local->mdev->mc_list); + + WARN_ON(new_flags & (1<<31)); + + local->filter_flags = new_flags & ~(1<<31); +} + /* master interface */ static int ieee80211_master_open(struct net_device *dev) @@ -86,6 +118,13 @@ static int ieee80211_master_stop(struct net_device *dev) return 0; } +static void ieee80211_master_set_multicast_list(struct net_device *dev) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + + ieee80211_configure_filter(local); +} + /* management interface */ static void @@ -267,49 +306,6 @@ static inline int identical_mac_addr_allowed(int type1, int type2) type2 == IEEE80211_IF_TYPE_VLAN))); } -/* Check if running monitor interfaces should go to a "soft monitor" mode - * and switch them if necessary. */ -static inline void ieee80211_start_soft_monitor(struct ieee80211_local *local) -{ - struct ieee80211_if_init_conf conf; - - if (local->open_count && local->open_count == local->monitors && - !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER) && - local->ops->remove_interface) { - conf.if_id = -1; - conf.type = IEEE80211_IF_TYPE_MNTR; - conf.mac_addr = NULL; - local->ops->remove_interface(local_to_hw(local), &conf); - } -} - -/* Check if running monitor interfaces should go to a "hard monitor" mode - * and switch them if necessary. */ -static void ieee80211_start_hard_monitor(struct ieee80211_local *local) -{ - struct ieee80211_if_init_conf conf; - - if (local->open_count && local->open_count == local->monitors && - !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) { - conf.if_id = -1; - conf.type = IEEE80211_IF_TYPE_MNTR; - conf.mac_addr = NULL; - local->ops->add_interface(local_to_hw(local), &conf); - } -} - -static void ieee80211_if_open(struct net_device *dev) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - switch (sdata->type) { - case IEEE80211_IF_TYPE_STA: - case IEEE80211_IF_TYPE_IBSS: - sdata->u.sta.flags &= ~IEEE80211_STA_PREV_BSSID_SET; - break; - } -} - static int ieee80211_open(struct net_device *dev) { struct ieee80211_sub_if_data *sdata, *nsdata; @@ -335,84 +331,96 @@ static int ieee80211_open(struct net_device *dev) is_zero_ether_addr(sdata->u.wds.remote_addr)) return -ENOLINK; - if (sdata->type == IEEE80211_IF_TYPE_MNTR && local->open_count && - !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) { - /* run the interface in a "soft monitor" mode */ - local->monitors++; - local->open_count++; - local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP; - return 0; - } - ieee80211_if_open(dev); - ieee80211_start_soft_monitor(local); - - conf.if_id = dev->ifindex; - conf.type = sdata->type; - if (sdata->type == IEEE80211_IF_TYPE_MNTR) - conf.mac_addr = NULL; - else - conf.mac_addr = dev->dev_addr; - res = local->ops->add_interface(local_to_hw(local), &conf); - if (res) { - if (sdata->type == IEEE80211_IF_TYPE_MNTR) - ieee80211_start_hard_monitor(local); - return res; - } - if (local->open_count == 0) { res = 0; - tasklet_enable(&local->tx_pending_tasklet); - tasklet_enable(&local->tasklet); - if (local->ops->open) - res = local->ops->open(local_to_hw(local)); - if (res == 0) { - res = dev_open(local->mdev); - if (res) { - if (local->ops->stop) - local->ops->stop(local_to_hw(local)); - } else { - res = ieee80211_hw_config(local); - if (res && local->ops->stop) - local->ops->stop(local_to_hw(local)); - else if (!res && local->apdev) - dev_open(local->apdev); - } - } - if (res) { - if (local->ops->remove_interface) - local->ops->remove_interface(local_to_hw(local), - &conf); + if (local->ops->start) + res = local->ops->start(local_to_hw(local)); + if (res) return res; - } } - local->open_count++; - if (sdata->type == IEEE80211_IF_TYPE_MNTR) { + switch (sdata->type) { + case IEEE80211_IF_TYPE_MNTR: + /* must be before the call to ieee80211_configure_filter */ local->monitors++; - local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP; - } else { + if (local->monitors == 1) { + netif_tx_lock_bh(local->mdev); + ieee80211_configure_filter(local); + netif_tx_unlock_bh(local->mdev); + + local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP; + ieee80211_hw_config(local); + } + break; + case IEEE80211_IF_TYPE_STA: + case IEEE80211_IF_TYPE_IBSS: + sdata->u.sta.flags &= ~IEEE80211_STA_PREV_BSSID_SET; + /* fall through */ + default: + conf.if_id = dev->ifindex; + conf.type = sdata->type; + conf.mac_addr = dev->dev_addr; + res = local->ops->add_interface(local_to_hw(local), &conf); + if (res && !local->open_count && local->ops->stop) + local->ops->stop(local_to_hw(local)); + if (res) + return res; + ieee80211_if_config(dev); ieee80211_reset_erp_info(dev); ieee80211_enable_keys(sdata); + + if (sdata->type == IEEE80211_IF_TYPE_STA && + !local->user_space_mlme) + netif_carrier_off(dev); + else + netif_carrier_on(dev); } - if (sdata->type == IEEE80211_IF_TYPE_STA && - !local->user_space_mlme) - netif_carrier_off(dev); - else - netif_carrier_on(dev); + if (local->open_count == 0) { + res = dev_open(local->mdev); + WARN_ON(res); + if (local->apdev) { + res = dev_open(local->apdev); + WARN_ON(res); + } + tasklet_enable(&local->tx_pending_tasklet); + tasklet_enable(&local->tasklet); + } + + local->open_count++; netif_start_queue(dev); + return 0; } -static void ieee80211_if_shutdown(struct net_device *dev) +static int ieee80211_stop(struct net_device *dev) { + struct ieee80211_sub_if_data *sdata; struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_if_init_conf conf; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + netif_stop_queue(dev); + + dev_mc_unsync(local->mdev, dev); + + local->open_count--; - ASSERT_RTNL(); switch (sdata->type) { + case IEEE80211_IF_TYPE_MNTR: + local->monitors--; + if (local->monitors == 0) { + netif_tx_lock_bh(local->mdev); + ieee80211_configure_filter(local); + netif_tx_unlock_bh(local->mdev); + + local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP; + ieee80211_hw_config(local); + } + break; case IEEE80211_IF_TYPE_STA: case IEEE80211_IF_TYPE_IBSS: sdata->u.sta.state = IEEE80211_DISABLED; @@ -433,116 +441,61 @@ static void ieee80211_if_shutdown(struct net_device *dev) cancel_delayed_work(&local->scan_work); } flush_workqueue(local->hw.workqueue); - break; - } -} - -static int ieee80211_stop(struct net_device *dev) -{ - struct ieee80211_sub_if_data *sdata; - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - if (sdata->type == IEEE80211_IF_TYPE_MNTR && - local->open_count > 1 && - !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) { - /* remove "soft monitor" interface */ - local->open_count--; - local->monitors--; - if (!local->monitors) - local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP; - return 0; - } - - netif_stop_queue(dev); - ieee80211_if_shutdown(dev); - - if (sdata->type == IEEE80211_IF_TYPE_MNTR) { - local->monitors--; - if (!local->monitors) - local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP; - } else { + /* fall through */ + default: + conf.if_id = dev->ifindex; + conf.type = sdata->type; + conf.mac_addr = dev->dev_addr; /* disable all keys for as long as this netdev is down */ ieee80211_disable_keys(sdata); + local->ops->remove_interface(local_to_hw(local), &conf); } - local->open_count--; if (local->open_count == 0) { if (netif_running(local->mdev)) dev_close(local->mdev); + if (local->apdev) dev_close(local->apdev); + if (local->ops->stop) local->ops->stop(local_to_hw(local)); + tasklet_disable(&local->tx_pending_tasklet); tasklet_disable(&local->tasklet); } - if (local->ops->remove_interface) { - struct ieee80211_if_init_conf conf; - - conf.if_id = dev->ifindex; - conf.type = sdata->type; - conf.mac_addr = dev->dev_addr; - local->ops->remove_interface(local_to_hw(local), &conf); - } - - ieee80211_start_hard_monitor(local); return 0; } -enum netif_tx_lock_class { - TX_LOCK_NORMAL, - TX_LOCK_MASTER, -}; - -static inline void netif_tx_lock_nested(struct net_device *dev, int subclass) -{ - spin_lock_nested(&dev->_xmit_lock, subclass); - dev->xmit_lock_owner = smp_processor_id(); -} - static void ieee80211_set_multicast_list(struct net_device *dev) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - unsigned short flags; + int allmulti, promisc, sdata_allmulti, sdata_promisc; - netif_tx_lock_nested(local->mdev, TX_LOCK_MASTER); - if (((dev->flags & IFF_ALLMULTI) != 0) ^ - ((sdata->flags & IEEE80211_SDATA_ALLMULTI) != 0)) { - if (sdata->flags & IEEE80211_SDATA_ALLMULTI) - local->iff_allmultis--; - else + allmulti = !!(dev->flags & IFF_ALLMULTI); + promisc = !!(dev->flags & IFF_PROMISC); + sdata_allmulti = sdata->flags & IEEE80211_SDATA_ALLMULTI; + sdata_promisc = sdata->flags & IEEE80211_SDATA_PROMISC; + + if (allmulti != sdata_allmulti) { + if (dev->flags & IFF_ALLMULTI) local->iff_allmultis++; + else + local->iff_allmultis--; sdata->flags ^= IEEE80211_SDATA_ALLMULTI; } - if (((dev->flags & IFF_PROMISC) != 0) ^ - ((sdata->flags & IEEE80211_SDATA_PROMISC) != 0)) { - if (sdata->flags & IEEE80211_SDATA_PROMISC) - local->iff_promiscs--; - else + + if (promisc != sdata_promisc) { + if (dev->flags & IFF_PROMISC) local->iff_promiscs++; + else + local->iff_promiscs--; sdata->flags ^= IEEE80211_SDATA_PROMISC; } - if (dev->mc_count != sdata->mc_count) { - local->mc_count = local->mc_count - sdata->mc_count + - dev->mc_count; - sdata->mc_count = dev->mc_count; - } - if (local->ops->set_multicast_list) { - flags = local->mdev->flags; - if (local->iff_allmultis) - flags |= IFF_ALLMULTI; - if (local->iff_promiscs) - flags |= IFF_PROMISC; - read_lock(&local->sub_if_lock); - local->ops->set_multicast_list(local_to_hw(local), flags, - local->mc_count); - read_unlock(&local->sub_if_lock); - } - netif_tx_unlock(local->mdev); + + dev_mc_sync(local->mdev, dev); } static const struct header_ops ieee80211_header_ops = { @@ -612,7 +565,6 @@ static int __ieee80211_if_config(struct net_device *dev, struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_if_conf conf; - static u8 scan_bssid[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; if (!local->ops->config_interface || !netif_running(dev)) return 0; @@ -621,11 +573,7 @@ static int __ieee80211_if_config(struct net_device *dev, conf.type = sdata->type; if (sdata->type == IEEE80211_IF_TYPE_STA || sdata->type == IEEE80211_IF_TYPE_IBSS) { - if (local->sta_scanning && - local->scan_dev == dev) - conf.bssid = scan_bssid; - else - conf.bssid = sdata->u.sta.bssid; + conf.bssid = sdata->u.sta.bssid; conf.ssid = sdata->u.sta.ssid; conf.ssid_len = sdata->u.sta.ssid_len; conf.generic_elem = sdata->u.sta.extra_ie; @@ -722,37 +670,6 @@ void ieee80211_reset_erp_info(struct net_device *dev) IEEE80211_ERP_CHANGE_PREAMBLE); } -struct dev_mc_list *ieee80211_get_mc_list_item(struct ieee80211_hw *hw, - struct dev_mc_list *prev, - void **ptr) -{ - struct ieee80211_local *local = hw_to_local(hw); - struct ieee80211_sub_if_data *sdata = *ptr; - struct dev_mc_list *mc; - - if (!prev) { - WARN_ON(sdata); - sdata = NULL; - } - if (!prev || !prev->next) { - if (sdata) - sdata = list_entry(sdata->list.next, - struct ieee80211_sub_if_data, list); - else - sdata = list_entry(local->sub_if_list.next, - struct ieee80211_sub_if_data, list); - if (&sdata->list != &local->sub_if_list) - mc = sdata->dev->mc_list; - else - mc = NULL; - } else - mc = prev->next; - - *ptr = sdata; - return mc; -} -EXPORT_SYMBOL(ieee80211_get_mc_list_item); - void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_tx_status *status) @@ -1158,8 +1075,12 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST); BUG_ON(!ops->tx); + BUG_ON(!ops->start); + BUG_ON(!ops->stop); BUG_ON(!ops->config); BUG_ON(!ops->add_interface); + BUG_ON(!ops->remove_interface); + BUG_ON(!ops->configure_filter); local->ops = ops; /* for now, mdev needs sub_if_data :/ */ @@ -1206,6 +1127,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, mdev->stop = ieee80211_master_stop; mdev->type = ARPHRD_IEEE80211; mdev->header_ops = &ieee80211_header_ops; + mdev->set_multicast_list = ieee80211_master_set_multicast_list; sdata->type = IEEE80211_IF_TYPE_AP; sdata->dev = mdev; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index c3f6f89755b1..74deecd09677 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -297,8 +297,6 @@ struct ieee80211_sub_if_data { struct net_device *dev; struct ieee80211_local *local; - int mc_count; - unsigned int flags; int drop_unencrypted; @@ -411,6 +409,7 @@ struct ieee80211_local { struct net_device *apdev; /* wlan#ap - management frames (hostapd) */ int open_count; int monitors; + unsigned int filter_flags; /* FIF_* */ struct iw_statistics wstats; u8 wstats_flags; int tx_headroom; /* required headroom for hardware/radiotap */ diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 3f0a2faf37d4..17455c6a5229 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -2662,10 +2662,16 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw) printk(KERN_DEBUG "%s: failed to restore operational" "channel after scan\n", dev->name); - if (!(local->hw.flags & IEEE80211_HW_NO_PROBE_FILTERING) && - ieee80211_if_config(dev)) - printk(KERN_DEBUG "%s: failed to restore operational" - "BSSID after scan\n", dev->name); + + netif_tx_lock_bh(local->mdev); + local->filter_flags &= ~FIF_BCN_PRBRESP_PROMISC; + local->ops->configure_filter(local_to_hw(local), + FIF_BCN_PRBRESP_PROMISC, + &local->filter_flags, + local->mdev->mc_count, + local->mdev->mc_list); + + netif_tx_unlock_bh(local->mdev); memset(&wrqu, 0, sizeof(wrqu)); wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); @@ -2849,10 +2855,14 @@ static int ieee80211_sta_start_scan(struct net_device *dev, local->scan_channel_idx = 0; local->scan_dev = dev; - if (!(local->hw.flags & IEEE80211_HW_NO_PROBE_FILTERING) && - ieee80211_if_config(dev)) - printk(KERN_DEBUG "%s: failed to set BSSID for scan\n", - dev->name); + netif_tx_lock_bh(local->mdev); + local->filter_flags |= FIF_BCN_PRBRESP_PROMISC; + local->ops->configure_filter(local_to_hw(local), + FIF_BCN_PRBRESP_PROMISC, + &local->filter_flags, + local->mdev->mc_count, + local->mdev->mc_list); + netif_tx_unlock_bh(local->mdev); /* TODO: start scan as soon as all nullfunc frames are ACKed */ queue_delayed_work(local->hw.workqueue, &local->scan_work, diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b5f2e4c25c7e..2535d8d4ce90 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1307,7 +1307,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, } else if (!multicast && compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) { - if (!(sdata->flags & IEEE80211_SDATA_PROMISC)) + if (!(sdata->dev->flags & IFF_PROMISC)) return 0; rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH; } @@ -1322,7 +1322,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, } else if (!multicast && compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) { - if (!(sdata->flags & IEEE80211_SDATA_PROMISC)) + if (!(sdata->dev->flags & IFF_PROMISC)) return 0; rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH; } else if (!rx->sta) |