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)
{
/* 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)
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;
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;
}
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)
}
}
-static int adm8211_open(struct ieee80211_hw *dev)
+static int adm8211_start(struct ieee80211_hw *dev)
{
struct adm8211_priv *priv = dev->priv;
int retval;
return retval;
}
-static int adm8211_stop(struct ieee80211_hw *dev)
+static void adm8211_stop(struct ieee80211_hw *dev)
{
struct adm8211_priv *priv = dev->priv;
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,
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
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) {
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);
}
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);
}
u8 bssid[ETH_ALEN];
u8 ssid[32];
size_t ssid_len;
- u8 *mac_addr;
u8 soft_rx_crc;
u8 retry_limit;
* 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. */
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;
/* 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);
}
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)");
}
}
-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)
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. */
& ~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);
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;
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);
}
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);
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);
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) {
}
}
- 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);
}
.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.
}
/* 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;
#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) */
* 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;
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);
}
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),
}
}
-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,
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. */
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);
}
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)
{
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);
}
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);
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);
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) {
}
}
- 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);
}
.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.
*
*****************************************************************************/
-static int iwl_mac_open(struct ieee80211_hw *hw)
+static int iwl_mac_start(struct ieee80211_hw *hw)
{
struct iwl_priv *priv = hw->priv;
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;
/*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,
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
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;
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)
{
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,
*
*****************************************************************************/
-static int iwl_mac_open(struct ieee80211_hw *hw)
+static int iwl_mac_start(struct ieee80211_hw *hw)
{
struct iwl_priv *priv = hw->priv;
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;
/*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,
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;
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)
{
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,
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;
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:
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);
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)
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)
{
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
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
*/
* 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);
}
*/
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)
/*
* 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;
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);
}
/*
/*
* 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;
/*
* 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)
{
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,
.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,
};
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
*/
* 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);
}
*/
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)
/*
* 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;
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);
}
/*
/*
* 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;
/*
* 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)
{
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,
.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,
};
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);
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);
}
*/
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)
/*
* 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 +
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;
}
/*
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;
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);
/*
/*
* 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)
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,
.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,
};
/*
* 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;
/*
* 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)
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;
}
/*
*/
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);
/*
* 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.
#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
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.
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
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,
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)
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.
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.
*/
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;
* 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
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;
* 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);
/*
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,
*/
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);
{
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;
}
/*
* 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
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);
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.
*/
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;
/*
}
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)
{
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);
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) {
};
/*
- * 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
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) ||
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.
* 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,
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;
/*
rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE2, 0);
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);
}
*/
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)
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;
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;
}
/*
*/
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;
/*
* 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)
{
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,
.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,
};
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;
/*
rt73usb_register_write(rt2x00dev, HW_BEACON_BASE2, 0);
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);
}
*/
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)
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;
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;
}
/*
*/
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;
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.
/*
* 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)
{
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,
.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,
};
#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)
};
struct rtl8187_rx_hdr {
- __le16 len;
- __le16 rate;
+ __le32 flags;
u8 noise;
u8 signal;
u8 agc;
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;
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;
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)
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;
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);
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);
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;
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);
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;
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;
}
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)
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)
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);
#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)
* @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.
/* 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 */
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. */
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);
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
*/
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);
/* 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);
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)
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)
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)
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
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;
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;
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 = {
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;
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;
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)
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 :/ */
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;
struct net_device *dev;
struct ieee80211_local *local;
- int mc_count;
-
unsigned int flags;
int drop_unencrypted;
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 */
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);
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,
} 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 (!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)