Skip to content

Commit

Permalink
[PATCH] mac80211: revamp interface and filter configuration
Browse files Browse the repository at this point in the history
Drivers are currently supposed to keep track of monitor
interfaces if they allow so-called "hard" monitor, and
they are also supposed to keep track of multicast etc.

This patch changes that, replaces the set_multicast_list()
callback with a new configure_filter() callback that takes
filter flags (FIF_*) instead of interface flags (IFF_*).
For a driver, this means it should open the filter as much
as necessary to get all frames requested by the filter flags.
Accordingly, the filter flags are named "positively", e.g.
FIF_ALLMULTI.

Multicast filtering is a bit special in that drivers that
have no multicast address filters need to allow multicast
frames through when either the FIF_ALLMULTI flag is set or
when the mc_count value is positive.

At the same time, drivers are no longer notified about
monitor interfaces at all, this means they now need to
implement the start() and stop() callbacks and the new
change_filter_flags() callback. Also, the start()/stop()
ordering changed, start() is now called *before* any
add_interface() as it really should be, and stop() after
any remove_interface().

The patch also changes the behaviour of setting the bssid
to multicast for scanning when IEEE80211_HW_NO_PROBE_FILTERING
is set; the IEEE80211_HW_NO_PROBE_FILTERING flag is removed
and the filter flag FIF_BCN_PRBRESP_PROMISC introduced.
This is a lot more efficient for hardware like b43 that
supports it and other hardware can still set the BSSID
to all-ones.

Driver modifications by Johannes Berg (b43 & iwlwifi), Michael Wu
(rtl8187, adm8211, and p54), Larry Finger (b43legacy), and
Ivo van Doorn (rt2x00).

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Michael Wu <flamingice@sourmilk.net>
Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Johannes Berg authored and David S. Miller committed Oct 10, 2007
1 parent 070ac3a commit 4150c57
Show file tree
Hide file tree
Showing 34 changed files with 1,383 additions and 1,267 deletions.
144 changes: 78 additions & 66 deletions drivers/net/wireless/adm8211.c
Original file line number Diff line number Diff line change
Expand Up @@ -281,49 +281,6 @@ static int adm8211_get_stats(struct ieee80211_hw *dev,
return 0;
}

static void adm8211_set_rx_mode(struct ieee80211_hw *dev,
unsigned short flags, int mc_count)
{
struct adm8211_priv *priv = dev->priv;
unsigned int bit_nr;
u32 mc_filter[2];
struct dev_mc_list *mclist;
void *tmp;

if (flags & IFF_PROMISC) {
priv->nar |= ADM8211_NAR_PR;
priv->nar &= ~ADM8211_NAR_MM;
mc_filter[1] = mc_filter[0] = ~0;
} else if ((flags & IFF_ALLMULTI) || (mc_count > -1)) {
priv->nar &= ~ADM8211_NAR_PR;
priv->nar |= ADM8211_NAR_MM;
mc_filter[1] = mc_filter[0] = ~0;
} else {
priv->nar &= ~(ADM8211_NAR_MM | ADM8211_NAR_PR);
mc_filter[1] = mc_filter[0] = 0;
mclist = NULL;
while ((mclist = ieee80211_get_mc_list_item(dev, mclist, &tmp))) {
bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;

bit_nr &= 0x3F;
mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
}
}

ADM8211_IDLE_RX();

ADM8211_CSR_WRITE(MAR0, mc_filter[0]);
ADM8211_CSR_WRITE(MAR1, mc_filter[1]);
ADM8211_CSR_READ(NAR);

if (flags & IFF_PROMISC)
dev->flags |= IEEE80211_HW_RX_INCLUDES_FCS;
else
dev->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS;

ADM8211_RESTORE();
}

static int adm8211_get_tx_stats(struct ieee80211_hw *dev,
struct ieee80211_tx_queue_stats *stats)
{
Expand Down Expand Up @@ -1254,13 +1211,6 @@ static void adm8211_hw_init(struct ieee80211_hw *dev)

/* Clear the missed-packet counter. */
ADM8211_CSR_READ(LPC);

if (!priv->mac_addr)
return;

/* set mac address */
ADM8211_CSR_WRITE(PAR0, *(u32 *)priv->mac_addr);
ADM8211_CSR_WRITE(PAR1, *(u16 *)&priv->mac_addr[4]);
}

static int adm8211_hw_reset(struct ieee80211_hw *dev)
Expand Down Expand Up @@ -1334,7 +1284,7 @@ static void adm8211_set_interval(struct ieee80211_hw *dev,
ADM8211_CSR_WRITE(BPLI, reg);
}

static void adm8211_set_bssid(struct ieee80211_hw *dev, u8 *bssid)
static void adm8211_set_bssid(struct ieee80211_hw *dev, const u8 *bssid)
{
struct adm8211_priv *priv = dev->priv;
u32 reg;
Expand Down Expand Up @@ -1395,24 +1345,87 @@ static int adm8211_config_interface(struct ieee80211_hw *dev, int if_id,
return 0;
}

static void adm8211_configure_filter(struct ieee80211_hw *dev,
unsigned int changed_flags,
unsigned int *total_flags,
int mc_count, struct dev_mc_list *mclist)
{
static const u8 bcast[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
struct adm8211_priv *priv = dev->priv;
unsigned int bit_nr, new_flags;
u32 mc_filter[2];
int i;

new_flags = 0;

if (*total_flags & FIF_PROMISC_IN_BSS) {
new_flags |= FIF_PROMISC_IN_BSS;
priv->nar |= ADM8211_NAR_PR;
priv->nar &= ~ADM8211_NAR_MM;
mc_filter[1] = mc_filter[0] = ~0;
} else if ((*total_flags & FIF_ALLMULTI) || (mc_count > 32)) {
new_flags |= FIF_ALLMULTI;
priv->nar &= ~ADM8211_NAR_PR;
priv->nar |= ADM8211_NAR_MM;
mc_filter[1] = mc_filter[0] = ~0;
} else {
priv->nar &= ~(ADM8211_NAR_MM | ADM8211_NAR_PR);
mc_filter[1] = mc_filter[0] = 0;
for (i = 0; i < mc_count; i++) {
if (!mclist)
break;
bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;

bit_nr &= 0x3F;
mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
mclist = mclist->next;
}
}

ADM8211_IDLE_RX();

ADM8211_CSR_WRITE(MAR0, mc_filter[0]);
ADM8211_CSR_WRITE(MAR1, mc_filter[1]);
ADM8211_CSR_READ(NAR);

if (priv->nar & ADM8211_NAR_PR)
dev->flags |= IEEE80211_HW_RX_INCLUDES_FCS;
else
dev->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS;

if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
adm8211_set_bssid(dev, bcast);
else
adm8211_set_bssid(dev, priv->bssid);

ADM8211_RESTORE();

*total_flags = new_flags;
}

static int adm8211_add_interface(struct ieee80211_hw *dev,
struct ieee80211_if_init_conf *conf)
{
struct adm8211_priv *priv = dev->priv;
/* NOTE: using IEEE80211_IF_TYPE_MGMT to indicate no mode selected */
if (priv->mode != IEEE80211_IF_TYPE_MGMT)
return -1;
if (priv->mode != IEEE80211_IF_TYPE_MNTR)
return -EOPNOTSUPP;

switch (conf->type) {
case IEEE80211_IF_TYPE_STA:
case IEEE80211_IF_TYPE_MNTR:
priv->mode = conf->type;
break;
default:
return -EOPNOTSUPP;
}

priv->mac_addr = conf->mac_addr;
ADM8211_IDLE();

ADM8211_CSR_WRITE(PAR0, *(u32 *)conf->mac_addr);
ADM8211_CSR_WRITE(PAR1, *(u16 *)(conf->mac_addr + 4));

adm8211_update_mode(dev);

ADM8211_RESTORE();

return 0;
}
Expand All @@ -1421,7 +1434,7 @@ static void adm8211_remove_interface(struct ieee80211_hw *dev,
struct ieee80211_if_init_conf *conf)
{
struct adm8211_priv *priv = dev->priv;
priv->mode = IEEE80211_IF_TYPE_MGMT;
priv->mode = IEEE80211_IF_TYPE_MNTR;
}

static int adm8211_init_rings(struct ieee80211_hw *dev)
Expand Down Expand Up @@ -1505,7 +1518,7 @@ static void adm8211_free_rings(struct ieee80211_hw *dev)
}
}

static int adm8211_open(struct ieee80211_hw *dev)
static int adm8211_start(struct ieee80211_hw *dev)
{
struct adm8211_priv *priv = dev->priv;
int retval;
Expand Down Expand Up @@ -1550,7 +1563,7 @@ static int adm8211_open(struct ieee80211_hw *dev)
return retval;
}

static int adm8211_stop(struct ieee80211_hw *dev)
static void adm8211_stop(struct ieee80211_hw *dev)
{
struct adm8211_priv *priv = dev->priv;

Expand All @@ -1562,7 +1575,6 @@ static int adm8211_stop(struct ieee80211_hw *dev)
free_irq(priv->pdev->irq, dev);

adm8211_free_rings(dev);
return 0;
}

static void adm8211_calc_durations(int *dur, int *plcp, size_t payload_len, int len,
Expand Down Expand Up @@ -1765,13 +1777,13 @@ static int adm8211_alloc_rings(struct ieee80211_hw *dev)

static const struct ieee80211_ops adm8211_ops = {
.tx = adm8211_tx,
.open = adm8211_open,
.start = adm8211_start,
.stop = adm8211_stop,
.add_interface = adm8211_add_interface,
.remove_interface = adm8211_remove_interface,
.config = adm8211_config,
.config_interface = adm8211_config_interface,
.set_multicast_list = adm8211_set_rx_mode,
.configure_filter = adm8211_configure_filter,
.get_stats = adm8211_get_stats,
.get_tx_stats = adm8211_get_tx_stats,
.get_tsf = adm8211_get_tsft
Expand Down Expand Up @@ -1905,7 +1917,7 @@ static int __devinit adm8211_probe(struct pci_dev *pdev,
priv->tx_power = 0x40;
priv->lpf_cutoff = 0xFF;
priv->lnags_threshold = 0xFF;
priv->mode = IEEE80211_IF_TYPE_MGMT;
priv->mode = IEEE80211_IF_TYPE_MNTR;

/* Power-on issue. EEPROM won't read correctly without */
if (priv->revid >= ADM8211_REV_BA) {
Expand Down Expand Up @@ -2000,7 +2012,7 @@ static int adm8211_suspend(struct pci_dev *pdev, pm_message_t state)
struct ieee80211_hw *dev = pci_get_drvdata(pdev);
struct adm8211_priv *priv = dev->priv;

if (priv->mode != IEEE80211_IF_TYPE_MGMT) {
if (priv->mode != IEEE80211_IF_TYPE_MNTR) {
ieee80211_stop_queues(dev);
adm8211_stop(dev);
}
Expand All @@ -2018,8 +2030,8 @@ static int adm8211_resume(struct pci_dev *pdev)
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);

if (priv->mode != IEEE80211_IF_TYPE_MGMT) {
adm8211_open(dev);
if (priv->mode != IEEE80211_IF_TYPE_MNTR) {
adm8211_start(dev);
ieee80211_start_queues(dev);
}

Expand Down
1 change: 0 additions & 1 deletion drivers/net/wireless/adm8211.h
Original file line number Diff line number Diff line change
Expand Up @@ -612,7 +612,6 @@ struct adm8211_priv {
u8 bssid[ETH_ALEN];
u8 ssid[32];
size_t ssid_len;
u8 *mac_addr;

u8 soft_rx_crc;
u8 retry_limit;
Expand Down
15 changes: 4 additions & 11 deletions drivers/net/wireless/b43/b43.h
Original file line number Diff line number Diff line change
Expand Up @@ -604,9 +604,8 @@ struct b43_wl {
* at a time. General information about this interface follows.
*/

/* Opaque ID of the operating interface (!= monitor
* interface) from the ieee80211 subsystem.
* Do not modify.
/* Opaque ID of the operating interface from the ieee80211
* subsystem. Do not modify.
*/
int if_id;
/* The MAC address of the operating interface. */
Expand All @@ -615,14 +614,10 @@ struct b43_wl {
u8 bssid[ETH_ALEN];
/* Interface type. (IEEE80211_IF_TYPE_XXX) */
int if_type;
/* Counter of active monitor interfaces. */
int monitor;
/* Is the card operating in AP, STA or IBSS mode? */
bool operating;
/* Promisc mode active?
* Note that (monitor != 0) implies promisc.
*/
bool promisc;
/* filter flags */
unsigned int filter_flags;
/* Stats about the wireless interface */
struct ieee80211_low_level_stats ieee_stats;

Expand Down Expand Up @@ -779,8 +774,6 @@ static inline struct b43_wldev *dev_to_b43_wldev(struct device *dev)
/* Is the device operating in a specified mode (IEEE80211_IF_TYPE_XXX). */
static inline int b43_is_mode(struct b43_wl *wl, int type)
{
if (type == IEEE80211_IF_TYPE_MNTR)
return !!(wl->monitor);
return (wl->operating && wl->if_type == type);
}

Expand Down
Loading

0 comments on commit 4150c57

Please sign in to comment.