2009-03-22 19:57:32

by Kalle Valo

[permalink] [raw]
Subject: [PATCH v4 0/5] mac80211: beacon filtering

Here's my proposal how to implement beacon filtering in mac80211. The
basic idea is simple, the driver enables filtering whenever mac80211
enables power save and the driver calls ieee80211_beacon_loss()
whenever hardware informs about beacon loss.

I have tested this with stlc45xx (with beacon filtering) and iwl3945
(without beacon filtering) and based on simple tests this seems to
work. For reference I'll send the stlc45xx patch as a followup.

v4:

o remove hw parameter from ieee80211_beacon_loss()
o don't call the patchset RFC anymore

v3:
o rebase to 2.6.29-rc8-wl
o add cfg80211_hold_bss() and cfg80211_unhold_bss() to avoid loosing
the bss struct when beacon filter is enabled
o fix bug to use !IEEE80211_HW_PS_NULLFUNC_STACK both in
ieee80211_scan_ps_enable() and ieee80211_scan_ps_disable(), also
improve comments
o fix the indentation in ieee80211_associated(), not visible in patch
anymore:

mod_timer(&ifmgd->timer, jiffies +
- IEEE80211_MONITORING_INTERVAL);
+ IEEE80211_MONITORING_INTERVAL);

o add vif parameter to void ieee80211_beacon_loss()
o more documentation about filtering, and especially about
checksumming
o document why multicast check is needed in ieee80211_sta_rx_notify()
o beacon filter is only enabled when power save is enabled, take this
into account in ieee80211_associated()

v2:
o rebase to 2.6.29-rc7-wl
o rename ieee80211_rx_trigger() to ieee80211_sta_rx_notify()
o move check for sta mode in ieee80211_sta_rx_notify() to rx.c
o move unicast check from rx.c to ieee80211_sta_rx_notify()
o add comment for setting last_beacon in ieee80211_rx_mgmt_assoc_resp()
o rename IEEE80211_HW_BEACON_FILTERING to IEEE80211_HW_BEACON_FILTER
o send probe request from ieee80211_beacon_loss_work()
o API documentation
o enable beacon filtering only when power save is enabled
o disable power save (and hence beacon filtering) while scanning to make
it possible to have reliable scan results even when beacon filtering
is enabled

TODO:

(none)

For the future:

o configuration for beacon filter (beacon misses * beacon interval
should be constant?)
o don't run ieee80211_associated() in data idle period

---

Kalle Valo (5):
mac80211: add beacon filtering support
cfg80211: add feature to hold bss
mac80211: disable power save when scanning
mac80211: track beacons separately from the rx path activity
mac80211: decrease execution of the associated timer


Documentation/DocBook/mac80211.tmpl | 6 ++
include/net/cfg80211.h | 18 +++++
include/net/mac80211.h | 45 ++++++++++-
net/mac80211/ieee80211_i.h | 5 +
net/mac80211/iface.c | 3 +
net/mac80211/mlme.c | 139 +++++++++++++++++++++++++++--------
net/mac80211/rx.c | 9 ++
net/mac80211/scan.c | 64 ++++++++++++++++
net/wireless/core.h | 2 +
net/wireless/scan.c | 27 +++++++
10 files changed, 278 insertions(+), 40 deletions(-)



2009-03-25 20:08:35

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH v4 0/5] mac80211: beacon filtering

Johannes Berg <[email protected]> writes:

> On Wed, 2009-03-25 at 21:34 +0200, Kalle Valo wrote:
>
>> > It has to be dynamic, no? Much of the information in there would be
>> > things wpa_supplicant is only interested in. If it was just the kernel
>> > code -- yes, we could just have a static list somewhere -- but much of
>> > the 11k things for instance are only useful for wpa_supplicant.
>>
>> But if we already know what wpa_supplicant needs, can't we do the
>> first implementation with a static list? Sure, the dynamic list is
>> something we should aim for.
>
> True. The userspace part is easy to add though, just make it part of the
> assoc() nl80211 command. So we just need the static list for the
> mac80211 part.

Sounds easy enough.

>> Do we have any knowledge how different hardware support beacon
>> checksumming? I only know how stlc45xx does it.
>
> Not really... how about wl12xx?

Heh, I'm so focused on my thesis right now that forgot wl12xx
altogether :)

I haven't investigate wl12xx beacon filtering in detail yet, but below
is what I quickly found from the firmware interface header files.
Looks like just what we would have expected.


Name: ACX_BEACON_FILTER_TABLE

Desc: This information element configures beacon filtering handling
for the set of information elements. An information element in a
beacon can be set to be: ignored (never compared, and changes
will not cause beacon transfer), checked (compared, and
transferred in case of a change), or transferred (transferred to
the host for each appearance or disappearance).

The table contains all information elements that are subject to
monitoring for host transfer.

All information elements that are not in the table should be
ignored for monitoring.

This functionality is only enabled when beacon filtering is enabled by
ACX_BEACON_FILTER_OPT.

Type: Filtering Configuration

Access: Write Only

Length: 101

Notes: the field measuring the value of received beacons for
which the device wakes up the host in
ACX_BEACON_FILTER_OPT does not affect this
information element.

http://android.git.kernel.org/?p=platform/system/wlan/ti.git;a=blob;f=sta_dk_4_0_4_32/common/src/hal/FirmwareApi/public_infoele.h;h=9a7d1c1203de4db83f700d8cc961cee04e7e5de9;hb=HEAD#l720

--
Kalle Valo

2009-03-22 19:57:43

by Kalle Valo

[permalink] [raw]
Subject: [PATCH v4 3/5] mac80211: disable power save when scanning

From: Kalle Valo <[email protected]>

When software scanning we need to disable power save so that all possible
probe responses and beacons are received. For hardware scanning assume that
hardware will take care of that and document that assumption.

Signed-off-by: Kalle Valo <[email protected]>
---

include/net/mac80211.h | 12 +++++----
net/mac80211/scan.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 69 insertions(+), 7 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index daa539a..174dc1d 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1307,11 +1307,13 @@ enum ieee80211_ampdu_mlme_action {
*
* @hw_scan: Ask the hardware to service the scan request, no need to start
* the scan state machine in stack. The scan must honour the channel
- * configuration done by the regulatory agent in the wiphy's registered
- * bands. When the scan finishes, ieee80211_scan_completed() must be
- * called; note that it also must be called when the scan cannot finish
- * because the hardware is turned off! Anything else is a bug!
- * Returns a negative error code which will be seen in userspace.
+ * configuration done by the regulatory agent in the wiphy's
+ * registered bands. The hardware (or the driver) needs to make sure
+ * that power save is disabled. When the scan finishes,
+ * ieee80211_scan_completed() must be called; note that it also must
+ * be called when the scan cannot finish because the hardware is
+ * turned off! Anything else is a bug! Returns a negative error code
+ * which will be seen in userspace.
*
* @sw_scan_start: Notifier function that is called just before a software scan
* is started. Can be NULL, if the driver doesn't need this notification.
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 46f35dc..3bf9839 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -214,6 +214,66 @@ void ieee80211_scan_failed(struct ieee80211_local *local)
local->scan_req = NULL;
}

+/*
+ * inform AP that we will go to sleep so that it will buffer the frames
+ * while we scan
+ */
+static void ieee80211_scan_ps_enable(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_local *local = sdata->local;
+ bool ps = false;
+
+ /* FIXME: what to do when local->pspolling is true? */
+
+ del_timer_sync(&local->dynamic_ps_timer);
+ cancel_work_sync(&local->dynamic_ps_enable_work);
+
+ if (local->hw.conf.flags & IEEE80211_CONF_PS) {
+ ps = true;
+ local->hw.conf.flags &= ~IEEE80211_CONF_PS;
+ ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
+ }
+
+ if (!ps || !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK))
+ /*
+ * If power save was enabled, no need to send a nullfunc
+ * frame because AP knows that we are sleeping. But if the
+ * hardware is creating the nullfunc frame for power save
+ * status (ie. IEEE80211_HW_PS_NULLFUNC_STACK is not
+ * enabled) and power save was enabled, the firmware just
+ * sent a null frame with power save disabled. So we need
+ * to send a new nullfunc frame to inform the AP that we
+ * are again sleeping.
+ */
+ ieee80211_send_nullfunc(local, sdata, 1);
+}
+
+/* inform AP that we are awake again, unless power save is enabled */
+static void ieee80211_scan_ps_disable(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_local *local = sdata->local;
+
+ if (!local->powersave)
+ ieee80211_send_nullfunc(local, sdata, 0);
+ else {
+ /*
+ * In !IEEE80211_HW_PS_NULLFUNC_STACK case the hardware
+ * will send a nullfunc frame with the powersave bit set
+ * even though the AP already knows that we are sleeping.
+ * This could be avoided by sending a null frame with power
+ * save bit disabled before enabling the power save, but
+ * this doesn't gain anything.
+ *
+ * When IEEE80211_HW_PS_NULLFUNC_STACK is enabled, no need
+ * to send a nullfunc frame because AP already knows that
+ * we are sleeping, let's just enable power save mode in
+ * hardware.
+ */
+ local->hw.conf.flags |= IEEE80211_CONF_PS;
+ ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
+ }
+}
+
void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
{
struct ieee80211_local *local = hw_to_local(hw);
@@ -268,7 +328,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
/* Tell AP we're back */
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) {
- ieee80211_send_nullfunc(local, sdata, 0);
+ ieee80211_scan_ps_disable(sdata);
netif_tx_wake_all_queues(sdata->dev);
}
} else
@@ -441,7 +501,7 @@ int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata,
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) {
netif_tx_stop_all_queues(sdata->dev);
- ieee80211_send_nullfunc(local, sdata, 1);
+ ieee80211_scan_ps_enable(sdata);
}
} else
netif_tx_stop_all_queues(sdata->dev);


2009-03-25 19:34:13

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH v4 0/5] mac80211: beacon filtering

Johannes Berg <[email protected]> writes:

> On Wed, 2009-03-25 at 11:01 +0200, Kalle Valo wrote:
>
>> > This actually affects the entire stack, take for example the BSS load
>> > element, which could potentially change frequently. Unless
>> > wpa_supplicant would want to use it for roaming, we could ignore it.
>> >
>> > However, how do we know which elements the various pieces of the stack
>> > need?
>>
>> I think we can just start with a fixed list and start improving that.
>> Or did you think of creating the list dynamically?
>
> It has to be dynamic, no? Much of the information in there would be
> things wpa_supplicant is only interested in. If it was just the kernel
> code -- yes, we could just have a static list somewhere -- but much of
> the 11k things for instance are only useful for wpa_supplicant.

But if we already know what wpa_supplicant needs, can't we do the
first implementation with a static list? Sure, the dynamic list is
something we should aim for.

Do we have any knowledge how different hardware support beacon
checksumming? I only know how stlc45xx does it.

--
Kalle Valo

2009-03-22 19:58:18

by Kalle Valo

[permalink] [raw]
Subject: [PATCH v4 5/5] mac80211: add beacon filtering support

From: Kalle Valo <[email protected]>

Add IEEE80211_HW_BEACON_FILTERING flag so that driver inform that it supports
beacon filtering. Drivers need to call the new function
ieee80211_beacon_loss() to notify about beacon loss.

Signed-off-by: Kalle Valo <[email protected]>
---

Documentation/DocBook/mac80211.tmpl | 6 ++++
include/net/mac80211.h | 33 ++++++++++++++++++++++++
net/mac80211/ieee80211_i.h | 2 +
net/mac80211/iface.c | 3 ++
net/mac80211/mlme.c | 49 ++++++++++++++++++++++++++++++++++-
5 files changed, 92 insertions(+), 1 deletions(-)

diff --git a/Documentation/DocBook/mac80211.tmpl b/Documentation/DocBook/mac80211.tmpl
index 8af6d96..fbeaffc 100644
--- a/Documentation/DocBook/mac80211.tmpl
+++ b/Documentation/DocBook/mac80211.tmpl
@@ -227,6 +227,12 @@ usage should require reading the full document.
!Pinclude/net/mac80211.h Powersave support
</chapter>

+ <chapter id="beacon-filter">
+ <title>Beacon filter support</title>
+!Pinclude/net/mac80211.h Beacon filter support
+!Finclude/net/mac80211.h ieee80211_beacon_loss
+ </chapter>
+
<chapter id="qos">
<title>Multiple queues and QoS support</title>
<para>TBD</para>
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 174dc1d..d881ed8 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -882,6 +882,10 @@ enum ieee80211_tkip_key_type {
*
* @IEEE80211_HW_MFP_CAPABLE:
* Hardware supports management frame protection (MFP, IEEE 802.11w).
+ *
+ * @IEEE80211_HW_BEACON_FILTER:
+ * Hardware supports dropping of irrelevant beacon frames to
+ * avoid waking up cpu.
*/
enum ieee80211_hw_flags {
IEEE80211_HW_RX_INCLUDES_FCS = 1<<1,
@@ -897,6 +901,7 @@ enum ieee80211_hw_flags {
IEEE80211_HW_PS_NULLFUNC_STACK = 1<<11,
IEEE80211_HW_SUPPORTS_DYNAMIC_PS = 1<<12,
IEEE80211_HW_MFP_CAPABLE = 1<<13,
+ IEEE80211_HW_BEACON_FILTER = 1<<14,
};

/**
@@ -1121,6 +1126,24 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw,
*/

/**
+ * DOC: Beacon filter support
+ *
+ * Some hardware have beacon filter support to reduce host cpu wakeups
+ * which will reduce system power consumption. It usuallly works so that
+ * the firmware creates a checksum of the beacon but omits all constantly
+ * changing elements (TSF, TIM etc). Whenever the checksum changes the
+ * beacon is forwarded to the host, otherwise it will be just dropped. That
+ * way the host will only receive beacons where some relevant information
+ * (for example ERP protection or WMM settings) have changed.
+ *
+ * Beacon filter support is informed with %IEEE80211_HW_BEACON_FILTER flag.
+ * The driver needs to enable beacon filter support whenever power save is
+ * enabled, that is %IEEE80211_CONF_PS is set. When power save is enabled,
+ * the stack will not check for beacon miss at all and the driver needs to
+ * notify about complete loss of beacons with ieee80211_beacon_loss().
+ */
+
+/**
* DOC: Frame filtering
*
* mac80211 requires to see many management frames for proper
@@ -1970,6 +1993,16 @@ void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra,
struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw,
const u8 *addr);

+/**
+ * ieee80211_beacon_loss - inform hardware does not receive beacons
+ *
+ * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
+ *
+ * When beacon filtering is enabled with IEEE80211_HW_BEACON_FILTERING and
+ * IEEE80211_CONF_PS is set, the driver needs to inform whenever the
+ * hardware is not receiving beacons with this function.
+ */
+void ieee80211_beacon_loss(struct ieee80211_vif *vif);

/* Rate control API */

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 73226a9..3a01f35 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -274,6 +274,7 @@ struct ieee80211_if_managed {
struct timer_list chswitch_timer;
struct work_struct work;
struct work_struct chswitch_work;
+ struct work_struct beacon_loss_work;

u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN];

@@ -1087,6 +1088,7 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local,
int powersave);
void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
struct ieee80211_hdr *hdr);
+void ieee80211_beacon_loss_work(struct work_struct *work);

void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
enum queue_stop_reason reason);
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 34f4798..2de6398 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -478,6 +478,9 @@ static int ieee80211_stop(struct net_device *dev)
*/
cancel_work_sync(&sdata->u.mgd.work);
cancel_work_sync(&sdata->u.mgd.chswitch_work);
+
+ cancel_work_sync(&sdata->u.mgd.beacon_loss_work);
+
/*
* When we get here, the interface is marked down.
* Call synchronize_rcu() to wait for the RX path
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index b3f784f..8865692 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -610,6 +610,8 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
bss_info_changed |= ieee80211_handle_bss_capability(sdata,
bss->cbss.capability, bss->has_erp_value, bss->erp_value);

+ cfg80211_hold_bss(&bss->cbss);
+
ieee80211_rx_bss_put(local, bss);
}

@@ -751,6 +753,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
{
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct ieee80211_local *local = sdata->local;
+ struct ieee80211_conf *conf = &local_to_hw(local)->conf;
+ struct ieee80211_bss *bss;
struct sta_info *sta;
u32 changed = 0, config_changed = 0;

@@ -774,6 +778,15 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,

ieee80211_sta_tear_down_BA_sessions(sta);

+ bss = ieee80211_rx_bss_get(local, ifmgd->bssid,
+ conf->channel->center_freq,
+ ifmgd->ssid, ifmgd->ssid_len);
+
+ if (bss) {
+ cfg80211_unhold_bss(&bss->cbss);
+ ieee80211_rx_bss_put(local, bss);
+ }
+
if (self_disconnected) {
if (deauth)
ieee80211_send_deauth_disassoc(sdata,
@@ -926,6 +939,33 @@ void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
jiffies + IEEE80211_MONITORING_INTERVAL);
}

+void ieee80211_beacon_loss_work(struct work_struct *work)
+{
+ struct ieee80211_sub_if_data *sdata =
+ container_of(work, struct ieee80211_sub_if_data,
+ u.mgd.beacon_loss_work);
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+
+ printk(KERN_DEBUG "%s: driver reports beacon loss from AP %pM "
+ "- sending probe request\n", sdata->dev->name,
+ sdata->u.mgd.bssid);
+
+ ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL;
+ ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid,
+ ifmgd->ssid_len, NULL, 0);
+
+ mod_timer(&ifmgd->timer, jiffies + IEEE80211_MONITORING_INTERVAL);
+}
+
+void ieee80211_beacon_loss(struct ieee80211_vif *vif)
+{
+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+
+ queue_work(sdata->local->hw.workqueue,
+ &sdata->u.mgd.beacon_loss_work);
+}
+EXPORT_SYMBOL(ieee80211_beacon_loss);
+
static void ieee80211_associated(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@@ -960,7 +1000,13 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata)
goto unlock;
}

- if (time_after(jiffies,
+ /*
+ * Beacon filtering is only enabled with power save and then the
+ * stack should not check for beacon loss.
+ */
+ if (!((local->hw.flags & IEEE80211_HW_BEACON_FILTER) &&
+ (local->hw.conf.flags & IEEE80211_CONF_PS)) &&
+ time_after(jiffies,
ifmgd->last_beacon + IEEE80211_MONITORING_INTERVAL)) {
printk(KERN_DEBUG "%s: beacon loss from AP %pM "
"- sending probe request\n",
@@ -1870,6 +1916,7 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
ifmgd = &sdata->u.mgd;
INIT_WORK(&ifmgd->work, ieee80211_sta_work);
INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work);
+ INIT_WORK(&ifmgd->beacon_loss_work, ieee80211_beacon_loss_work);
setup_timer(&ifmgd->timer, ieee80211_sta_timer,
(unsigned long) sdata);
setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer,


2009-03-22 20:29:23

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH v4 0/5] mac80211: beacon filtering

Johannes Berg <[email protected]> writes:

> On Sun, 2009-03-22 at 21:56 +0200, Kalle Valo wrote:
>> Here's my proposal how to implement beacon filtering in mac80211. The
>> basic idea is simple, the driver enables filtering whenever mac80211
>> enables power save and the driver calls ieee80211_beacon_loss()
>> whenever hardware informs about beacon loss.
>>
>> I have tested this with stlc45xx (with beacon filtering) and iwl3945
>> (without beacon filtering) and based on simple tests this seems to
>> work. For reference I'll send the stlc45xx patch as a followup.
>
> I'm getting bored saying this again and again ;) Looks good to me.

Sorry, I _had_ to fix the ieee80211_beacon_loss() interface ;)

Oh yeah, forgot to mention that I did some quick measurements and with
these patches I was able get 25% system power consumption decrease
with stlc45xx on Nokia N800 in the wlan idle case (associated to the
AP, no data traffic, display off). I'll do more measurements later.

--
Kalle Valo

2009-03-22 20:02:32

by Kalle Valo

[permalink] [raw]
Subject: [PATCH] stlc45xx: add beacon filtering support

Experimental patch.

Signed-off-by: Kalle Valo <[email protected]>
---

stlc45xx.c | 40 ++++++++++++++++++++++++++++++++++------
1 files changed, 34 insertions(+), 6 deletions(-)

diff --git a/stlc45xx.c b/stlc45xx.c
index ca7bfa2..6d5d4e5 100644
--- a/stlc45xx.c
+++ b/stlc45xx.c
@@ -1263,6 +1263,28 @@ static int stlc45xx_rx_txack(struct stlc45xx *stlc, struct sk_buff *skb)
return 0;
}

+static int stlc45xx_rx_trap(struct stlc45xx *stlc, struct sk_buff *skb)
+{
+ struct s_lm_control *control;
+ struct s_lmo_trap *trap;
+
+ stlc45xx_debug(DEBUG_FUNC, "%s", __func__);
+
+ control = (struct s_lm_control *) skb->data;
+ trap = (struct s_lmo_trap *) (control + 1);
+
+ switch (trap->event) {
+ case LM_TRAP_NO_BEACON:
+ ieee80211_beacon_loss(stlc->vif);
+ break;
+ default:
+ stlc45xx_warning("unhandled trap: %d\n", trap->event);
+ break;
+ }
+
+ return 0;
+}
+
static int stlc45xx_rx_control(struct stlc45xx *stlc, struct sk_buff *skb)
{
struct s_lm_control *control;
@@ -1276,9 +1298,11 @@ static int stlc45xx_rx_control(struct stlc45xx *stlc, struct sk_buff *skb)
case LM_OID_TX:
ret = stlc45xx_rx_txack(stlc, skb);
break;
+ case LM_OID_TRAP:
+ ret = stlc45xx_rx_trap(stlc, skb);
+ break;
case LM_OID_SETUP:
case LM_OID_SCAN:
- case LM_OID_TRAP:
case LM_OID_EDCF:
case LM_OID_KEYCACHE:
case LM_OID_PSM:
@@ -1643,7 +1667,7 @@ static void stlc45xx_setup_mac(struct stlc45xx *stlc,u16 mode,const u8 *bssid)
setup->rx_buffer = FIRMWARE_RXBUFFER_START;
setup->rx_mtu = FIRMWARE_MTU;
setup->frontend = 5;
- setup->timeout = 0;
+ setup->timeout = 2;
setup->truncate = 48896;
setup->bratemask = 0xffffffff;
setup->ref_clock = 644245094;
@@ -1827,11 +1851,13 @@ static void stlc45xx_tx_psm(struct stlc45xx *stlc, bool enable)
control->oid = LM_OID_PSM;

if (enable)
- psm->flags |= LM_PSM;
+ psm->flags |= LM_PSM | LM_PSM_MCBC |
+ LM_PSM_CHECKSUM | LM_PSM_BEACON_TIMEOUT;

psm->aid = stlc->aid;

- psm->beacon_rcpi_skip_max = 60;
+ psm->beacon_rcpi_skip_max = 200;
+ psm->rcpi_delta_threshold = 0;

psm->intervals[0].interval = 1;
psm->intervals[0].periods = 1;
@@ -1842,7 +1868,7 @@ static void stlc45xx_tx_psm(struct stlc45xx *stlc, bool enable)
psm->intervals[3].interval = 1;
psm->intervals[3].periods = 1;

- psm->nr = 0;
+ psm->nr = 10;
psm->exclude[0] = 0;

stlc45xx_debug(DEBUG_PSM, "sending LM_OID_PSM (aid %d, interval %d)",
@@ -2428,7 +2454,9 @@ static int __devinit stlc45xx_probe(struct spi_device *spi)
IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_NOISE_DBM |
IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_PS_NULLFUNC_STACK;
+ IEEE80211_HW_PS_NULLFUNC_STACK |
+ IEEE80211_HW_BEACON_FILTER;
+
/* four bytes for padding */
hw->extra_tx_headroom = sizeof(struct s_lm_data_out) + 4;



2009-03-24 13:11:27

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH v4 0/5] mac80211: beacon filtering

On Sun, 2009-03-22 at 21:56 +0200, Kalle Valo wrote:
> Here's my proposal how to implement beacon filtering in mac80211. The
> basic idea is simple, the driver enables filtering whenever mac80211
> enables power save and the driver calls ieee80211_beacon_loss()
> whenever hardware informs about beacon loss.
>
> I have tested this with stlc45xx (with beacon filtering) and iwl3945
> (without beacon filtering) and based on simple tests this seems to
> work. For reference I'll send the stlc45xx patch as a followup.

Something I've been wondering about now is how to populate the exclude
list (which would probably be smarter as an include list, but anyway).
This actually affects the entire stack, take for example the BSS load
element, which could potentially change frequently. Unless
wpa_supplicant would want to use it for roaming, we could ignore it.

However, how do we know which elements the various pieces of the stack
need?

johannes


Attachments:
signature.asc (836.00 B)
This is a digitally signed message part

2009-03-22 19:57:38

by Kalle Valo

[permalink] [raw]
Subject: [PATCH v4 1/5] mac80211: decrease execution of the associated timer

From: Kalle Valo <[email protected]>

Currently the timer is triggering every two seconds
(IEEE80211_MONITORING_INTERVAL). Decrease the timer to only trigger during
data idle periods to avoid waking up CPU unnecessary. The timer will
still trigger during idle periods, that needs to be fixed later.

There's also a functional change that probe requests are sent only when the
data path is idle, earlier they were sent also while there was activity
on the data path.

This is also preparation for the beacon filtering support. Thanks to
Johannes Berg for the idea.

Signed-off-by: Kalle Valo <[email protected]>
---

net/mac80211/ieee80211_i.h | 2 ++
net/mac80211/mlme.c | 15 +++++++++++++++
net/mac80211/rx.c | 3 +++
3 files changed, 20 insertions(+), 0 deletions(-)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index f69e84a..a7b13ea 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1084,6 +1084,8 @@ void ieee80211_dynamic_ps_timer(unsigned long data);
void ieee80211_send_nullfunc(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
int powersave);
+void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_hdr *hdr);

void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
enum queue_stop_reason reason);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index b0808ef..ce1ad7c 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -910,6 +910,21 @@ static void ieee80211_associate(struct ieee80211_sub_if_data *sdata)
mod_timer(&ifmgd->timer, jiffies + IEEE80211_ASSOC_TIMEOUT);
}

+void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_hdr *hdr)
+{
+ /*
+ * We can postpone the mgd.timer whenever receiving unicast frames
+ * from AP because we know that the connection is working both ways
+ * at that time. But multicast frames (and hence also beacons) must
+ * be ignored here, because we need to trigger the timer during
+ * data idle periods for sending the periodical probe request to
+ * the AP.
+ */
+ if (!is_multicast_ether_addr(hdr->addr1))
+ mod_timer(&sdata->u.mgd.timer,
+ jiffies + IEEE80211_MONITORING_INTERVAL);
+}

static void ieee80211_associated(struct ieee80211_sub_if_data *sdata)
{
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index fcc0a59..4298e86 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -856,6 +856,9 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
if (!(rx->flags & IEEE80211_RX_RA_MATCH))
return RX_CONTINUE;

+ if (rx->sdata->vif.type == NL80211_IFTYPE_STATION)
+ ieee80211_sta_rx_notify(rx->sdata, hdr);
+
sta->rx_fragments++;
sta->rx_bytes += rx->skb->len;
sta->last_signal = rx->status->signal;


2009-03-25 20:18:08

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH v4 0/5] mac80211: beacon filtering

On Wed, 2009-03-25 at 22:08 +0200, Kalle Valo wrote:

> >> Do we have any knowledge how different hardware support beacon
> >> checksumming? I only know how stlc45xx does it.
> >
> > Not really... how about wl12xx?

> Name: ACX_BEACON_FILTER_TABLE
>
> Desc: This information element configures beacon filtering handling
> for the set of information elements. An information element in a
> beacon can be set to be: ignored (never compared, and changes
> will not cause beacon transfer), checked (compared, and
> transferred in case of a change), or transferred (transferred to
> the host for each appearance or disappearance).
>
> The table contains all information elements that are subject to
> monitoring for host transfer.
>
> All information elements that are not in the table should be
> ignored for monitoring.

Seems easy enough... Only concern is vendor IEs since we cannot ignore
them (WMM) but others might change frequently... oh well.

johannes


Attachments:
signature.asc (836.00 B)
This is a digitally signed message part

2009-03-22 19:58:09

by Kalle Valo

[permalink] [raw]
Subject: [PATCH v4 4/5] cfg80211: add feature to hold bss

From: Kalle Valo <[email protected]>

In beacon filtering there needs to be a way to not expire the BSS even
when no beacons are received. Add an interface to cfg80211 to hold
BSS and make sure that it's not expired.

Signed-off-by: Kalle Valo <[email protected]>
---

include/net/cfg80211.h | 18 ++++++++++++++++++
net/wireless/core.h | 2 ++
net/wireless/scan.c | 27 ++++++++++++++++++++++++++-
3 files changed, 46 insertions(+), 1 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index dca4a6b..5389afd 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -539,6 +539,7 @@ enum cfg80211_signal_type {
* is no guarantee that these are well-formed!)
* @len_information_elements: total length of the information elements
* @signal: signal strength value (type depends on the wiphy's signal_type)
+ * @hold: BSS should not expire
* @free_priv: function pointer to free private data
* @priv: private area for driver use, has at least wiphy->bss_priv_size bytes
*/
@@ -940,4 +941,21 @@ void cfg80211_send_rx_deauth(struct net_device *dev, const u8 *buf,
void cfg80211_send_rx_disassoc(struct net_device *dev, const u8 *buf,
size_t len);

+/**
+ * cfg80211_hold_bss - exclude bss from expiration
+ * @bss: bss which should not expire
+ *
+ * In a case when the BSS is not updated but it shouldn't expire this
+ * function can be used to mark the BSS to be excluded from expiration.
+ */
+void cfg80211_hold_bss(struct cfg80211_bss *bss);
+
+/**
+ * cfg80211_unhold_bss - remove expiration exception from the BSS
+ * @bss: bss which can expire again
+ *
+ * This function marks the BSS to be expirable again.
+ */
+void cfg80211_unhold_bss(struct cfg80211_bss *bss);
+
#endif /* __NET_CFG80211_H */
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 6acd483..97a6fd8 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -90,6 +90,8 @@ struct cfg80211_internal_bss {
struct rb_node rbn;
unsigned long ts;
struct kref ref;
+ bool hold;
+
/* must be last because of priv member */
struct cfg80211_bss pub;
};
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 280dbcd..2a00e36 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -80,7 +80,8 @@ void cfg80211_bss_expire(struct cfg80211_registered_device *dev)
bool expired = false;

list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) {
- if (!time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE))
+ if (bss->hold ||
+ !time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE))
continue;
list_del(&bss->list);
rb_erase(&bss->rbn, &dev->bss_tree);
@@ -471,6 +472,30 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
}
EXPORT_SYMBOL(cfg80211_unlink_bss);

+void cfg80211_hold_bss(struct cfg80211_bss *pub)
+{
+ struct cfg80211_internal_bss *bss;
+
+ if (!pub)
+ return;
+
+ bss = container_of(pub, struct cfg80211_internal_bss, pub);
+ bss->hold = true;
+}
+EXPORT_SYMBOL(cfg80211_hold_bss);
+
+void cfg80211_unhold_bss(struct cfg80211_bss *pub)
+{
+ struct cfg80211_internal_bss *bss;
+
+ if (!pub)
+ return;
+
+ bss = container_of(pub, struct cfg80211_internal_bss, pub);
+ bss->hold = false;
+}
+EXPORT_SYMBOL(cfg80211_unhold_bss);
+
#ifdef CONFIG_WIRELESS_EXT
int cfg80211_wext_siwscan(struct net_device *dev,
struct iw_request_info *info,


2009-03-22 19:57:37

by Kalle Valo

[permalink] [raw]
Subject: [PATCH v4 2/5] mac80211: track beacons separately from the rx path activity

From: Kalle Valo <[email protected]>

Separate beacon and rx path tracking in preparation for the beacon filtering
support. At the same time change ieee80211_associated() to look a bit simpler.

Probe requests are now sent only after IEEE80211_PROBE_IDLE_TIME, which
is now set to 60 seconds.

Signed-off-by: Kalle Valo <[email protected]>
---

net/mac80211/ieee80211_i.h | 1 +
net/mac80211/mlme.c | 77 ++++++++++++++++++++++++++------------------
net/mac80211/rx.c | 6 +++
3 files changed, 52 insertions(+), 32 deletions(-)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index a7b13ea..73226a9 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -307,6 +307,7 @@ struct ieee80211_if_managed {
unsigned long request;

unsigned long last_probe;
+ unsigned long last_beacon;

unsigned int flags;

diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index ce1ad7c..b3f784f 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -30,7 +30,7 @@
#define IEEE80211_ASSOC_TIMEOUT (HZ / 5)
#define IEEE80211_ASSOC_MAX_TRIES 3
#define IEEE80211_MONITORING_INTERVAL (2 * HZ)
-#define IEEE80211_PROBE_INTERVAL (60 * HZ)
+#define IEEE80211_PROBE_IDLE_TIME (60 * HZ)
#define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ)

/* utils */
@@ -931,7 +931,7 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata)
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
- int disassoc;
+ bool disassoc = false;

/* TODO: start monitoring current AP signal quality and number of
* missed beacons. Scan other channels every now and then and search
@@ -946,36 +946,39 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata)
if (!sta) {
printk(KERN_DEBUG "%s: No STA entry for own AP %pM\n",
sdata->dev->name, ifmgd->bssid);
- disassoc = 1;
- } else {
- disassoc = 0;
- if (time_after(jiffies,
- sta->last_rx + IEEE80211_MONITORING_INTERVAL)) {
- if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) {
- printk(KERN_DEBUG "%s: No ProbeResp from "
- "current AP %pM - assume out of "
- "range\n",
- sdata->dev->name, ifmgd->bssid);
- disassoc = 1;
- } else
- ieee80211_send_probe_req(sdata, ifmgd->bssid,
- ifmgd->ssid,
- ifmgd->ssid_len,
- NULL, 0);
- ifmgd->flags ^= IEEE80211_STA_PROBEREQ_POLL;
- } else {
- ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL;
- if (time_after(jiffies, ifmgd->last_probe +
- IEEE80211_PROBE_INTERVAL)) {
- ifmgd->last_probe = jiffies;
- ieee80211_send_probe_req(sdata, ifmgd->bssid,
- ifmgd->ssid,
- ifmgd->ssid_len,
- NULL, 0);
- }
- }
+ disassoc = true;
+ goto unlock;
+ }
+
+ if ((ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) &&
+ time_after(jiffies, sta->last_rx + IEEE80211_MONITORING_INTERVAL)) {
+ printk(KERN_DEBUG "%s: no probe response from AP %pM "
+ "- disassociating\n",
+ sdata->dev->name, ifmgd->bssid);
+ disassoc = true;
+ ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL;
+ goto unlock;
+ }
+
+ if (time_after(jiffies,
+ ifmgd->last_beacon + IEEE80211_MONITORING_INTERVAL)) {
+ printk(KERN_DEBUG "%s: beacon loss from AP %pM "
+ "- sending probe request\n",
+ sdata->dev->name, ifmgd->bssid);
+ ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL;
+ ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid,
+ ifmgd->ssid_len, NULL, 0);
+ goto unlock;
+
+ }
+
+ if (time_after(jiffies, sta->last_rx + IEEE80211_PROBE_IDLE_TIME)) {
+ ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL;
+ ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid,
+ ifmgd->ssid_len, NULL, 0);
}

+ unlock:
rcu_read_unlock();

if (disassoc)
@@ -1375,6 +1378,12 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
bss_conf->assoc_capability = capab_info;
ieee80211_set_associated(sdata, changed);

+ /*
+ * initialise the time of last beacon to be the association time,
+ * otherwise beacon loss check will trigger immediately
+ */
+ ifmgd->last_beacon = jiffies;
+
ieee80211_associated(sdata);
cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, len);
}
@@ -1423,9 +1432,12 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
size_t len,
struct ieee80211_rx_status *rx_status)
{
+ struct ieee80211_if_managed *ifmgd;
size_t baselen;
struct ieee802_11_elems elems;

+ ifmgd = &sdata->u.mgd;
+
if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN))
return; /* ignore ProbeResp to foreign address */

@@ -1440,11 +1452,14 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,

/* direct probe may be part of the association flow */
if (test_and_clear_bit(IEEE80211_STA_REQ_DIRECT_PROBE,
- &sdata->u.mgd.request)) {
+ &ifmgd->request)) {
printk(KERN_DEBUG "%s direct probe responded\n",
sdata->dev->name);
ieee80211_authenticate(sdata);
}
+
+ if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL)
+ ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL;
}

static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 4298e86..fd264d9 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -850,7 +850,11 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
* Mesh beacons will update last_rx when if they are found to
* match the current local configuration when processed.
*/
- sta->last_rx = jiffies;
+ if (rx->sdata->vif.type == NL80211_IFTYPE_STATION &&
+ ieee80211_is_beacon(hdr->frame_control)) {
+ rx->sdata->u.mgd.last_beacon = jiffies;
+ } else
+ sta->last_rx = jiffies;
}

if (!(rx->flags & IEEE80211_RX_RA_MATCH))


2009-03-25 09:01:46

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH v4 0/5] mac80211: beacon filtering

Johannes Berg <[email protected]> writes:

> On Sun, 2009-03-22 at 21:56 +0200, Kalle Valo wrote:
>> Here's my proposal how to implement beacon filtering in mac80211. The
>> basic idea is simple, the driver enables filtering whenever mac80211
>> enables power save and the driver calls ieee80211_beacon_loss()
>> whenever hardware informs about beacon loss.
>>
>> I have tested this with stlc45xx (with beacon filtering) and iwl3945
>> (without beacon filtering) and based on simple tests this seems to
>> work. For reference I'll send the stlc45xx patch as a followup.
>
> Something I've been wondering about now is how to populate the exclude
> list (which would probably be smarter as an include list, but anyway).

Yeah, an include list would be a lot better.

> This actually affects the entire stack, take for example the BSS load
> element, which could potentially change frequently. Unless
> wpa_supplicant would want to use it for roaming, we could ignore it.
>
> However, how do we know which elements the various pieces of the stack
> need?

I think we can just start with a fixed list and start improving that.
Or did you think of creating the list dynamically?

--
Kalle Valo

2009-03-25 19:41:11

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH v4 0/5] mac80211: beacon filtering

On Wed, 2009-03-25 at 21:34 +0200, Kalle Valo wrote:

> > It has to be dynamic, no? Much of the information in there would be
> > things wpa_supplicant is only interested in. If it was just the kernel
> > code -- yes, we could just have a static list somewhere -- but much of
> > the 11k things for instance are only useful for wpa_supplicant.
>
> But if we already know what wpa_supplicant needs, can't we do the
> first implementation with a static list? Sure, the dynamic list is
> something we should aim for.

True. The userspace part is easy to add though, just make it part of the
assoc() nl80211 command. So we just need the static list for the
mac80211 part.

> Do we have any knowledge how different hardware support beacon
> checksumming? I only know how stlc45xx does it.

Not really... how about wl12xx?

johannes


Attachments:
signature.asc (836.00 B)
This is a digitally signed message part

2009-03-22 20:15:40

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH v4 0/5] mac80211: beacon filtering

On Sun, 2009-03-22 at 21:56 +0200, Kalle Valo wrote:
> Here's my proposal how to implement beacon filtering in mac80211. The
> basic idea is simple, the driver enables filtering whenever mac80211
> enables power save and the driver calls ieee80211_beacon_loss()
> whenever hardware informs about beacon loss.
>
> I have tested this with stlc45xx (with beacon filtering) and iwl3945
> (without beacon filtering) and based on simple tests this seems to
> work. For reference I'll send the stlc45xx patch as a followup.

I'm getting bored saying this again and again ;) Looks good to me.

johannes


Attachments:
signature.asc (836.00 B)
This is a digitally signed message part

2009-03-25 09:31:22

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH v4 0/5] mac80211: beacon filtering

On Wed, 2009-03-25 at 11:01 +0200, Kalle Valo wrote:

> > This actually affects the entire stack, take for example the BSS load
> > element, which could potentially change frequently. Unless
> > wpa_supplicant would want to use it for roaming, we could ignore it.
> >
> > However, how do we know which elements the various pieces of the stack
> > need?
>
> I think we can just start with a fixed list and start improving that.
> Or did you think of creating the list dynamically?

It has to be dynamic, no? Much of the information in there would be
things wpa_supplicant is only interested in. If it was just the kernel
code -- yes, we could just have a static list somewhere -- but much of
the 11k things for instance are only useful for wpa_supplicant.

johannes


Attachments:
signature.asc (836.00 B)
This is a digitally signed message part