2010-03-17 13:04:21

by Juuso Oikarinen

[permalink] [raw]
Subject: [RFC PATCHv3 0/2] mac80211: cfg80211: Roam trigger support

To implement good performance WLAN roaming, it is not sufficient to start
scanning for other available AP's only after the currently serving association
is lost.

The entity controlling the roaming will need to get indication of a
deteriorating WLAN connection in order to start preparing for roaming already
before the serving association is lost. This way, it can roam to a better AP
perhaps even before the serving association becomes too bad in quality.

These patches propose an implementation facilitating this using a simple RSSI
threshold and hysteresis approach.

These patches add a nl80211 interface for simply configuring a rssi threshold
and hysteresis value to facilitate very basic connection quality monitoring.

For the triggering, these patches currently rely on HW support, host based
triggering is not implemented, but could be added later if needed.

These patches have been tested with the wl1271 driver.

Thanks in advance for your comments and suggestions.

Juuso Oikarinen (2):
cfg80211: Add connection quality monitoring support to nl80211
mac80211: Add support for connection quality monitoring

include/linux/nl80211.h | 42 ++++++++++++++++
include/net/cfg80211.h | 18 +++++++
include/net/mac80211.h | 27 +++++++++++
net/mac80211/cfg.c | 26 ++++++++++
net/mac80211/mlme.c | 9 ++++
net/wireless/mlme.c | 12 +++++
net/wireless/nl80211.c | 119 +++++++++++++++++++++++++++++++++++++++++++++++
net/wireless/nl80211.h | 5 ++
8 files changed, 258 insertions(+), 0 deletions(-)



2010-03-20 00:15:37

by Jouni Malinen

[permalink] [raw]
Subject: Re: [RFC PATCHv3 0/2] mac80211: cfg80211: Roam trigger support

On Fri, Mar 19, 2010 at 10:56:37AM -0400, John W. Linville wrote:
> On Fri, Mar 19, 2010 at 08:59:25AM +0200, Kalle Valo wrote:
> > The idea is that wpa_supplicant will listen to these events, and will
> > enable or disable backround scan (ie. scanning for new APs when
> > associated) based on information received from the events. When the
> > connection to the AP is good enough, it can disable background scan
> > which makes it possible to save power and also get rid of latency
> > introduced by the background scan.
> >
> > I haven't seen any implementation for wpa_supplicant yet, but we have
> > talked about that few times during the last two years.
>
> If you can make wpa_supplicant scan less then I am sold! :-)

I would assume it is not really wpa_supplicant that is triggering too
many scans for your liking, but NetworkManager.. The goal here (at least
from my view point) is to actually make wpa_supplicant itself trigger
scans more frequently ;-).

wpa_supplicant already has a notification function just waiting to be
called from somewhere when a beacon is lost of signal strength has
changed.. That somewhere is supposed to be the driver event handler when
it receives one of these new roam trigger events. At that point,
wpa_supplicant can then figure out if it should start scanning more
frequently to find a better BSS. I would hope that this feature will
make NetworkManager eventually stop doing its constant scans (or well,
if it doesn't, I will provide an option in for wpa_supplicant to ignore
D-Bus requests for new scans.. ;-).

--
Jouni Malinen PGP id EFC895FA

2010-03-18 05:22:54

by Juuso Oikarinen

[permalink] [raw]
Subject: Re: [RFC PATCHv3 1/2] cfg80211: Add connection quality monitoring support to nl80211

On Wed, 2010-03-17 at 17:17 +0100, ext Johannes Berg wrote:
> On Wed, 2010-03-17 at 15:01 +0200, Juuso Oikarinen wrote:
>
> > +/**
> > + * enum nl80211_cqm_state - current state in relation to set threshold
> > + * @NL80211_CQM_STATE_ABOVE: the level is above the configured threshold
> > + * @NL80211_CQM_STATE_BELOW: the level is below the configured threshold
> > + */
> > +enum nl80211_cqm_state {
> > + NL80211_CQM_STATE_ABOVE,
> > + NL80211_CQM_STATE_BELOW,
> > +};
>
> Thoughts about removing this and just exporting the actual (smoothed?)
> RSSI instead in the event? Or do you simply not get that from the hw?

On the wl1271 we actually do get the value that triggered the event, but
on the wl1251, for instance, we do not get it. On the wl1271 we get to
decide the above/below on the host based on the reading, but the wl1251
will just tell the host that now the RSSI went below, and now it just
went above.

Our thinking is that the above/below information is sufficient to make a
decisions about roaming. Adding the literal value will give trouble with
HW not supporting it.

If you feel the actual value of the RSSI would be important, we could
add it as an optional field to the notifcation in addition to the
above/below.

-Juuso

> johannes
>



2010-03-17 16:20:22

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC PATCHv3 2/2] mac80211: Add support for connection quality monitoring

On Wed, 2010-03-17 at 15:01 +0200, Juuso Oikarinen wrote:

> +void ieee80211_cqm_notify(struct ieee80211_vif *vif,
> + enum nl80211_cqm_state rssi_state)
> +{
> + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
> +
> + cfg80211_cqm_notify(sdata->dev, rssi_state, GFP_KERNEL);
> +}
> +EXPORT_SYMBOL(ieee80211_cqm_notify);

How do you know GFP_KERNEL is OK? The driver might call this from an
interrupt? Seems better to me to ask the driver for the allocation flags
too.

johannes


2010-03-17 13:04:58

by Juuso Oikarinen

[permalink] [raw]
Subject: [RFC PATCHv3 2/2] mac80211: Add support for connection quality monitoring

Add support for the set_cqm_config op. This op function configures the
requested connection quality monitor rssi threshold and rssi hysteresis
values to the hardware if the hardware supports
IEEE80211_HW_SUPPORTS_CQM.

For unsupporting hardware, currently -EOPNOTSUPP is returned, so the mac80211
is currently not doing connection quality monitoring on the host. This could be
added later, if needed.

Signed-off-by: Juuso Oikarinen <[email protected]>
---
include/net/mac80211.h | 27 +++++++++++++++++++++++++++
net/mac80211/cfg.c | 26 ++++++++++++++++++++++++++
net/mac80211/mlme.c | 9 +++++++++
3 files changed, 62 insertions(+), 0 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 936bc41..90da396 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -599,6 +599,7 @@ enum ieee80211_conf_flags {
* @IEEE80211_CONF_CHANGE_RETRY_LIMITS: retry limits changed
* @IEEE80211_CONF_CHANGE_IDLE: Idle flag changed
* @IEEE80211_CONF_CHANGE_SMPS: Spatial multiplexing powersave mode changed
+ * @IEEE80211_CONF_CHANGE_CQM: Connection quality monitor config changed
*/
enum ieee80211_conf_changed {
IEEE80211_CONF_CHANGE_SMPS = BIT(1),
@@ -609,6 +610,7 @@ enum ieee80211_conf_changed {
IEEE80211_CONF_CHANGE_CHANNEL = BIT(6),
IEEE80211_CONF_CHANGE_RETRY_LIMITS = BIT(7),
IEEE80211_CONF_CHANGE_IDLE = BIT(8),
+ IEEE80211_CONF_CHANGE_CQM = BIT(9),
};

/**
@@ -662,6 +664,9 @@ enum ieee80211_smps_mode {
* frame, called "dot11ShortRetryLimit" in 802.11, but actually means the
* number of transmissions not the number of retries
*
+ * @cqm_rssi_thold: Connection quality monitor RSSI threshold
+ * @cqm_rssi_hyst: Connection quality monitor RSSI hysteresis
+ *
* @smps_mode: spatial multiplexing powersave mode; note that
* %IEEE80211_SMPS_STATIC is used when the device is not
* configured for an HT channel
@@ -676,6 +681,9 @@ struct ieee80211_conf {

u8 long_frame_max_tx_count, short_frame_max_tx_count;

+ s32 cqm_rssi_thold;
+ u8 cqm_rssi_hyst;
+
struct ieee80211_channel *channel;
enum nl80211_channel_type channel_type;
enum ieee80211_smps_mode smps_mode;
@@ -954,6 +962,10 @@ enum ieee80211_tkip_key_type {
* Hardware can provide ack status reports of Tx frames to
* the stack.
*
+ * @IEEE80211_HW_SUPPORTS_CQM:
+ * Hardware can do connection quality monitoring - i.e. it can monitor
+ * RSSI levels and notify on changes based on a threshold and hysteresis.
+ *
*/
enum ieee80211_hw_flags {
IEEE80211_HW_HAS_RATE_CONTROL = 1<<0,
@@ -975,6 +987,7 @@ enum ieee80211_hw_flags {
IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS = 1<<16,
IEEE80211_HW_SUPPORTS_UAPSD = 1<<17,
IEEE80211_HW_REPORTS_TX_ACK_STATUS = 1<<18,
+ IEEE80211_HW_SUPPORTS_CQM = 1<<19,
};

/**
@@ -2370,6 +2383,20 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw,
*/
void ieee80211_beacon_loss(struct ieee80211_vif *vif);

+/**
+ * ieee80211_cqm_notify - inform connection quality monitoring RSSI
+ * threshold triggered
+ *
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+ * @rssi_state: the current state of the RSSI value compared to threshold
+ *
+ * When the IEEE80211_HW_SUPPORTS_CQM is set, and a RSSI threshold has been
+ * configured, the driver will inform whenever RSSI goes above or below
+ * the threshold with this function.
+ */
+void ieee80211_cqm_notify(struct ieee80211_vif *vif,
+ enum nl80211_cqm_state rssi_state);
+
/* Rate control API */

/**
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index b7116ef..319a604 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1402,6 +1402,31 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
return 0;
}

+static int ieee80211_set_cqm_config(struct wiphy *wiphy,
+ struct net_device *dev,
+ s32 rssi_thold, u8 rssi_hyst)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_conf *conf = &local->hw.conf;
+
+ if (sdata->vif.type != NL80211_IFTYPE_STATION)
+ return -EOPNOTSUPP;
+
+ if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_CQM))
+ return -EOPNOTSUPP;
+
+ if (rssi_thold == conf->cqm_rssi_thold &&
+ rssi_hyst == conf->cqm_rssi_hyst)
+ return 0;
+
+ conf->cqm_rssi_thold = rssi_thold;
+ conf->cqm_rssi_hyst = rssi_hyst;
+
+ ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CQM);
+ return 0;
+}
+
static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
struct net_device *dev,
const u8 *addr,
@@ -1506,4 +1531,5 @@ struct cfg80211_ops mac80211_config_ops = {
.remain_on_channel = ieee80211_remain_on_channel,
.cancel_remain_on_channel = ieee80211_cancel_remain_on_channel,
.action = ieee80211_action,
+ .set_cqm_config = ieee80211_set_cqm_config
};
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index be5f723..3ee3250 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2135,3 +2135,12 @@ int ieee80211_mgd_action(struct ieee80211_sub_if_data *sdata,
*cookie = (unsigned long) skb;
return 0;
}
+
+void ieee80211_cqm_notify(struct ieee80211_vif *vif,
+ enum nl80211_cqm_state rssi_state)
+{
+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+
+ cfg80211_cqm_notify(sdata->dev, rssi_state, GFP_KERNEL);
+}
+EXPORT_SYMBOL(ieee80211_cqm_notify);
--
1.6.3.3


2010-03-17 14:00:42

by Juuso Oikarinen

[permalink] [raw]
Subject: Re: [RFC PATCHv3 0/2] mac80211: cfg80211: Roam trigger support

On Wed, 2010-03-17 at 14:22 +0100, ext John W. Linville wrote:
> On Wed, Mar 17, 2010 at 03:01:15PM +0200, Juuso Oikarinen wrote:
> > To implement good performance WLAN roaming, it is not sufficient to start
> > scanning for other available AP's only after the currently serving association
> > is lost.
> >
> > The entity controlling the roaming will need to get indication of a
> > deteriorating WLAN connection in order to start preparing for roaming already
> > before the serving association is lost. This way, it can roam to a better AP
> > perhaps even before the serving association becomes too bad in quality.
> >
> > These patches propose an implementation facilitating this using a simple RSSI
> > threshold and hysteresis approach.
> >
> > These patches add a nl80211 interface for simply configuring a rssi threshold
> > and hysteresis value to facilitate very basic connection quality monitoring.
> >
> > For the triggering, these patches currently rely on HW support, host based
> > triggering is not implemented, but could be added later if needed.
> >
> > These patches have been tested with the wl1271 driver.
> >
> > Thanks in advance for your comments and suggestions.
> >
> > Juuso Oikarinen (2):
> > cfg80211: Add connection quality monitoring support to nl80211
> > mac80211: Add support for connection quality monitoring
>
> Any idea what other hardware (besides libertas) supports this concept?
> Do you anticipate adding a host-based implementation to mac80211?

I'm not currently anticipating on doing a host-based implementation in
the near future for this because the driver I co-maintain does not need
it and I would not have the time to do it properly.

I'm currently aware of only libertas and wl1271 with hardware support
for this. I'm relatively sure though that there are more, as this is a
pretty basic feature, supported even by some of the most hated of
operating systems ;)

> Is RSSI really a useful enough indicator for this function?
> Will applications actually use it?

RSSI by itself is perhaps not ideal, but it's still way better than
nothing. Currently we have to wait for the connection to be lost to do
roaming - taking up a significant amount of time. A dropping RSSI does
give a hint that the AP is getting further away.

I believe there is pressure for this feature from others than just me.
Based on these patches I already received queries on this feature, so
I'm positive that wider support will emerge, also in user-space.

-Juuso



> John



2010-03-17 16:21:19

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC PATCHv3 2/2] mac80211: Add support for connection quality monitoring

Sorry about the multiple mails ... This'll be the last.

> @@ -1506,4 +1531,5 @@ struct cfg80211_ops mac80211_config_ops = {
> .remain_on_channel = ieee80211_remain_on_channel,
> .cancel_remain_on_channel = ieee80211_cancel_remain_on_channel,
> .action = ieee80211_action,
> + .set_cqm_config = ieee80211_set_cqm_config

Please add a trailing comma so future changes here don't need to edit
your line.

johannes


2010-03-18 05:25:10

by Juuso Oikarinen

[permalink] [raw]
Subject: Re: [RFC PATCHv3 2/2] mac80211: Add support for connection quality monitoring

On Wed, 2010-03-17 at 17:19 +0100, ext Johannes Berg wrote:
> On Wed, 2010-03-17 at 15:01 +0200, Juuso Oikarinen wrote:
>
> > --- a/include/net/mac80211.h
> > +++ b/include/net/mac80211.h
> > @@ -599,6 +599,7 @@ enum ieee80211_conf_flags {
> > * @IEEE80211_CONF_CHANGE_RETRY_LIMITS: retry limits changed
> > * @IEEE80211_CONF_CHANGE_IDLE: Idle flag changed
> > * @IEEE80211_CONF_CHANGE_SMPS: Spatial multiplexing powersave mode changed
> > + * @IEEE80211_CONF_CHANGE_CQM: Connection quality monitor config changed
> > */
> > enum ieee80211_conf_changed {
> > IEEE80211_CONF_CHANGE_SMPS = BIT(1),
> > @@ -609,6 +610,7 @@ enum ieee80211_conf_changed {
> > IEEE80211_CONF_CHANGE_CHANNEL = BIT(6),
> > IEEE80211_CONF_CHANGE_RETRY_LIMITS = BIT(7),
> > IEEE80211_CONF_CHANGE_IDLE = BIT(8),
> > + IEEE80211_CONF_CHANGE_CQM = BIT(9),
> > };
> >
> > /**
> > @@ -662,6 +664,9 @@ enum ieee80211_smps_mode {
> > * frame, called "dot11ShortRetryLimit" in 802.11, but actually means the
> > * number of transmissions not the number of retries
> > *
> > + * @cqm_rssi_thold: Connection quality monitor RSSI threshold
> > + * @cqm_rssi_hyst: Connection quality monitor RSSI hysteresis
> > + *
> > * @smps_mode: spatial multiplexing powersave mode; note that
> > * %IEEE80211_SMPS_STATIC is used when the device is not
> > * configured for an HT channel
> > @@ -676,6 +681,9 @@ struct ieee80211_conf {
> >
> > u8 long_frame_max_tx_count, short_frame_max_tx_count;
> >
> > + s32 cqm_rssi_thold;
> > + u8 cqm_rssi_hyst;
>
> You probably don't care all that much, but I have a feeling this should
> be part of the per-BSS data not the global configuration data, since
> especially when we do it in software we could have to deal with multiple
> virtual interfaces.

Good point, for the wl12x1 it doesn't matter so much as they can only
support one virtual interface. I'll change this.

-Juuso

>
> johannes
>



2010-03-19 04:46:57

by Juuso Oikarinen

[permalink] [raw]
Subject: Re: [RFC PATCHv3 1/2] cfg80211: Add connection quality monitoring support to nl80211

On Thu, 2010-03-18 at 17:10 +0100, ext Johannes Berg wrote:
> On Thu, 2010-03-18 at 07:19 +0200, Juuso Oikarinen wrote:
> > On Wed, 2010-03-17 at 17:17 +0100, ext Johannes Berg wrote:
> > > On Wed, 2010-03-17 at 15:01 +0200, Juuso Oikarinen wrote:
> > >
> > > > +/**
> > > > + * enum nl80211_cqm_state - current state in relation to set threshold
> > > > + * @NL80211_CQM_STATE_ABOVE: the level is above the configured threshold
> > > > + * @NL80211_CQM_STATE_BELOW: the level is below the configured threshold
> > > > + */
> > > > +enum nl80211_cqm_state {
> > > > + NL80211_CQM_STATE_ABOVE,
> > > > + NL80211_CQM_STATE_BELOW,
> > > > +};
> > >
> > > Thoughts about removing this and just exporting the actual (smoothed?)
> > > RSSI instead in the event? Or do you simply not get that from the hw?
> >
> > On the wl1271 we actually do get the value that triggered the event, but
> > on the wl1251, for instance, we do not get it. On the wl1271 we get to
> > decide the above/below on the host based on the reading, but the wl1251
> > will just tell the host that now the RSSI went below, and now it just
> > went above.
> >
> > Our thinking is that the above/below information is sufficient to make a
> > decisions about roaming. Adding the literal value will give trouble with
> > HW not supporting it.
>
> Ok, that's fair. I don't want to hurt wl1251 by doing this. But then
> maybe it could just retrieve the value from the last beacon?

Alas, we cannot. The wl1251/71 atleast have beacon filtering, so the
host is not receiving beacons at all, and hence, does not have a
up-to-date RSSI value. Actually, the host does not get a decent RSSI
from anywhere, unless there happens to be some non-beacon inbound data
at just that moment.

And also, because there is fluctuation, sending the RSSI value from a
theoretical last beacon may not reflect the true reason of the trigger.
Userspace might not get the right idea for the cause of the event.

> > If you feel the actual value of the RSSI would be important, we could
> > add it as an optional field to the notifcation in addition to the
> > above/below.
>
> No ... I don't actually strongly feel that the actual value is all that
> relevant, although we'll only know when we implement roaming algorithms
> in userspace. Maybe it would be advantageous to keep this out of the
> tree for a while longer while you implement the userspace portion? But I
> don't know how much you've thought about how to use this so maybe you
> know it'll work :) And OTOH you kinda know it has to work since that's
> what you get from the hw...

The N900 has this same mechanism in it, and it's been used there
relatively successfully. So even in practice, this works.

> Anyhow, back to this patch again: For some reason I just don't like the
> above/below thing all that much. I think in part that's because on the
> one hand you say it can be extended, but on the other you call this
> nl80211_cqm_state.
>
> How about we call it nl80211_cqm_rssi_threshold_event or something like
> that? Yeah it's a long and verbose name, but I think it's better than
> "state"? The states you have at least are not really tied to the RSSI
> stuff.

Yes, I can call it whatever feels good to you and others. The name in
itself, I believe, is not an issue!

> I could, for example, imagine also using this to let userspace know
> about beacon loss events when they become too frequent. It's possible
> that this happens while the RSSI is still high, due to interference,
> after all.

Yes, that is a good idea, for later :)

-Juuso



> johannes
>



2010-03-17 16:17:43

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC PATCHv3 1/2] cfg80211: Add connection quality monitoring support to nl80211

On Wed, 2010-03-17 at 15:01 +0200, Juuso Oikarinen wrote:

> +/**
> + * enum nl80211_cqm_state - current state in relation to set threshold
> + * @NL80211_CQM_STATE_ABOVE: the level is above the configured threshold
> + * @NL80211_CQM_STATE_BELOW: the level is below the configured threshold
> + */
> +enum nl80211_cqm_state {
> + NL80211_CQM_STATE_ABOVE,
> + NL80211_CQM_STATE_BELOW,
> +};

Thoughts about removing this and just exporting the actual (smoothed?)
RSSI instead in the event? Or do you simply not get that from the hw?

johannes


2010-03-19 06:39:24

by Kalle Valo

[permalink] [raw]
Subject: Re: [RFC PATCHv3 1/2] cfg80211: Add connection quality monitoring support to nl80211

Juuso Oikarinen <[email protected]> writes:

> Add support for basic configuration of a connection quality monitoring to the
> nl80211 interface, and basic support for notifying about triggered monitoring
> events.
>
> Via this interface a user-space connection manager may configure and receive
> pre-warning events of deteriorating WLAN connection quality, and start
> preparing for roaming in advance, before the connection is already lost.

Sorry, I have been busy lately (over 500 unread emails in
linux-wireless, doh!) and I haven't had time to look at your patches
in detail. But I want to emphasise that in the future we want to
extend this interface with new events like beacon loss or
retransmissions. From a quick look your patches make this possible and
that's good.

--
Kalle Valo

2010-03-19 06:59:29

by Kalle Valo

[permalink] [raw]
Subject: Re: [RFC PATCHv3 0/2] mac80211: cfg80211: Roam trigger support

"John W. Linville" <[email protected]> writes:

> On Wed, Mar 17, 2010 at 03:01:15PM +0200, Juuso Oikarinen wrote:
>> To implement good performance WLAN roaming, it is not sufficient to start
>> scanning for other available AP's only after the currently serving association
>> is lost.
>>
>> The entity controlling the roaming will need to get indication of a
>> deteriorating WLAN connection in order to start preparing for roaming already
>> before the serving association is lost. This way, it can roam to a better AP
>> perhaps even before the serving association becomes too bad in quality.

[...]

> Any idea what other hardware (besides libertas) supports this
> concept?

I myself only know that wl1251 and wl1271 have this. But I wouldn't be
surprised if recent Intel designs also support it. It's a quite useful
feature, I would say that it's even a must-have feature for power
consumption critical devices.

And even if hardware wouldn't support this, having a host-based
implementation host would make it easier for wpa_supplicant.

> Do you anticipate adding a host-based implementation to mac80211?

I think we need a support for this, otherwise testing is next to
impossible because of small number of wl1271 and wl1251 upstream
users. I would prefer to have the host-based implementation right from
the start.

> Is RSSI really a useful enough indicator for this function?

Yes, it actually is. I implemented a similar hack for Nokia N900 which
is now in use by real customers. I just had to use WE custom events
due to project schedule constraints.

But I'm sure in the future we use different attributes for this, for
example retransmissions.

> Will applications actually use it?

The idea is that wpa_supplicant will listen to these events, and will
enable or disable backround scan (ie. scanning for new APs when
associated) based on information received from the events. When the
connection to the AP is good enough, it can disable background scan
which makes it possible to save power and also get rid of latency
introduced by the background scan.

I haven't seen any implementation for wpa_supplicant yet, but we have
talked about that few times during the last two years.

--
Kalle Valo

2010-03-17 13:04:24

by Juuso Oikarinen

[permalink] [raw]
Subject: [RFC PATCHv3 1/2] cfg80211: Add connection quality monitoring support to nl80211

Add support for basic configuration of a connection quality monitoring to the
nl80211 interface, and basic support for notifying about triggered monitoring
events.

Via this interface a user-space connection manager may configure and receive
pre-warning events of deteriorating WLAN connection quality, and start
preparing for roaming in advance, before the connection is already lost.

An example usage of such a trigger is starting scanning for nearby AP's in
an attempt to find one with better connection quality, and associate to it
before the connection characteristics of the existing connection become too bad
or the association is even lost, leading in a prolonged delay in connectivity.

The interface currently supports only RSSI, but it could be later extended
to include other parameters, such as signal-to-noise ratio, if need for that
arises.

Signed-off-by: Juuso Oikarinen <[email protected]>
---
include/linux/nl80211.h | 42 ++++++++++++++++
include/net/cfg80211.h | 18 +++++++
net/wireless/mlme.c | 12 +++++
net/wireless/nl80211.c | 119 +++++++++++++++++++++++++++++++++++++++++++++++
net/wireless/nl80211.h | 5 ++
5 files changed, 196 insertions(+), 0 deletions(-)

diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 28ba20f..b8ec9f8 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -323,6 +323,10 @@
* the TX command and %NL80211_ATTR_FRAME includes the contents of the
* frame. %NL80211_ATTR_ACK flag is included if the recipient acknowledged
* the frame.
+ * @NL80211_CMD_SET_CQM: Connection quality monitor configuration and
+ * notification. This command is used both as a command (to configure
+ * a trigger level) and as an event (to indicate the configured level was
+ * reached.) Setting zero threshold disables the feature.
*
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
@@ -419,6 +423,8 @@ enum nl80211_commands {
NL80211_CMD_SET_POWER_SAVE,
NL80211_CMD_GET_POWER_SAVE,

+ NL80211_CMD_SET_CQM,
+
/* add new commands above here */

/* used to define NL80211_CMD_MAX below */
@@ -691,6 +697,9 @@ enum nl80211_commands {
* @NL80211_ATTR_ACK: Flag attribute indicating that the frame was
* acknowledged by the recipient.
*
+ * @NL80211_ATTR_CQM: connection quality monitor configuration in a
+ * nested attribute with %NL80211_ATTR_CQM_* sub-attributes.
+ *
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@@ -842,6 +851,8 @@ enum nl80211_attrs {

NL80211_ATTR_PS_STATE,

+ NL80211_ATTR_CQM,
+
/* add attributes here, update the policy in nl80211.c */

__NL80211_ATTR_AFTER_LAST,
@@ -1583,4 +1594,35 @@ enum nl80211_ps_state {
NL80211_PS_ENABLED,
};

+/**
+ * enum nl80211_attr_cqm - connection quality monitor attributes
+ * @__NL80211_ATTR_CQM_INVALID: invalid
+ * @NL80211_ATTR_CQM_RSSI_THOLD: RSSI threshold in dBm
+ * @NL80211_ATTR_CQM_RSSI_HYST: RSSI hysteresis in dBm
+ * @NL80211_ATTR_CQM_RSSI_STATE: Current state of the RSSI in relation to
+ * the configured threshold
+ * @__NL80211_ATTR_CQM_AFTER_LAST: internal
+ * @NL80211_ATTR_CQM_MAX: highest key attribute
+ */
+enum nl80211_attr_cqm {
+ __NL80211_ATTR_CQM_INVALID,
+ NL80211_ATTR_CQM_RSSI_THOLD,
+ NL80211_ATTR_CQM_RSSI_HYST,
+ NL80211_ATTR_CQM_RSSI_STATE,
+
+ /* keep last */
+ __NL80211_ATTR_CQM_AFTER_LAST,
+ NL80211_ATTR_CQM_MAX = __NL80211_ATTR_CQM_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_cqm_state - current state in relation to set threshold
+ * @NL80211_CQM_STATE_ABOVE: the level is above the configured threshold
+ * @NL80211_CQM_STATE_BELOW: the level is below the configured threshold
+ */
+enum nl80211_cqm_state {
+ NL80211_CQM_STATE_ABOVE,
+ NL80211_CQM_STATE_BELOW,
+};
+
#endif /* __LINUX_NL80211_H */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 3d134a1..13fa1ba 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1007,6 +1007,8 @@ struct cfg80211_pmksa {
* RSN IE. It allows for faster roaming between WPA2 BSSIDs.
* @del_pmksa: Delete a cached PMKID.
* @flush_pmksa: Flush all cached PMKIDs.
+ * @set_cqm_config: Configure connection quality monitor RSSI
+ * notification threshold.
*
*/
struct cfg80211_ops {
@@ -1152,6 +1154,9 @@ struct cfg80211_ops {

int (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev,
bool enabled, int timeout);
+
+ int (*set_cqm_config)(struct wiphy *wiphy, struct net_device *dev,
+ s32 rssi_thold, u8 rssi_hyst);
};

/*
@@ -2337,4 +2342,17 @@ bool cfg80211_rx_action(struct net_device *dev, int freq, const u8 *buf,
void cfg80211_action_tx_status(struct net_device *dev, u64 cookie,
const u8 *buf, size_t len, bool ack, gfp_t gfp);

+
+/**
+ * cfg80211_cqm_notify - notification of a connection quality monitoring event
+ * @dev: network device
+ * @rssi_state: current state of the RSSI in relation to the threshold
+ * @gfp: context flags
+ *
+ * This function is called, when a configured connection quality monitoring
+ * event occurs.
+ */
+void cfg80211_cqm_notify(struct net_device *dev,
+ enum nl80211_cqm_state rssi_state, gfp_t gfp);
+
#endif /* __NET_CFG80211_H */
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 62bc885..5d0ab41 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -894,3 +894,15 @@ void cfg80211_action_tx_status(struct net_device *dev, u64 cookie,
nl80211_send_action_tx_status(rdev, dev, cookie, buf, len, ack, gfp);
}
EXPORT_SYMBOL(cfg80211_action_tx_status);
+
+void cfg80211_cqm_notify(struct net_device *dev,
+ enum nl80211_cqm_state rssi_state, gfp_t gfp)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct wiphy *wiphy = wdev->wiphy;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+ /* Indicate roaming trigger event to user space */
+ nl80211_send_cqm_notify(rdev, dev, rssi_state, gfp);
+}
+EXPORT_SYMBOL(cfg80211_cqm_notify);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index e447db0..77fab21 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -149,6 +149,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
.len = IEEE80211_MAX_DATA_LEN },
[NL80211_ATTR_FRAME_MATCH] = { .type = NLA_BINARY, },
[NL80211_ATTR_PS_STATE] = { .type = NLA_U32 },
+ [NL80211_ATTR_CQM] = { .type = NLA_NESTED, },
};

/* policy for the attributes */
@@ -4778,6 +4779,75 @@ unlock_rtnl:
return err;
}

+static struct nla_policy
+nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] __read_mostly = {
+ [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
+ [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U8 },
+ [NL80211_ATTR_CQM_RSSI_STATE] = { .type = NLA_U32 },
+};
+
+static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev;
+ struct wireless_dev *wdev;
+ struct net_device *dev;
+ struct nlattr *attrs[NL80211_ATTR_CQM_MAX + 1];
+ struct nlattr *cqm;
+ s32 rssi_thold;
+ u8 rssi_hyst;
+ int err;
+
+ cqm = info->attrs[NL80211_ATTR_CQM];
+ if (!cqm) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ err = nla_parse_nested(attrs, NL80211_ATTR_CQM_MAX, cqm,
+ nl80211_attr_cqm_policy);
+ if (err)
+ goto out;
+
+
+ if (!attrs[NL80211_ATTR_CQM_RSSI_THOLD] &&
+ !attrs[NL80211_ATTR_CQM_RSSI_HYST]) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ rssi_thold = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
+ if (rssi_thold > 0) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ rssi_hyst = nla_get_u8(attrs[NL80211_ATTR_CQM_RSSI_HYST]);
+
+ rtnl_lock();
+
+ err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
+ if (err)
+ goto unlock_rdev;
+
+ wdev = dev->ieee80211_ptr;
+
+ if (!rdev->ops->set_cqm_config) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ err = rdev->ops->set_cqm_config(wdev->wiphy, dev,
+ rssi_thold, rssi_hyst);
+
+unlock_rdev:
+ cfg80211_unlock_rdev(rdev);
+ dev_put(dev);
+ rtnl_unlock();
+
+out:
+ return err;
+}
+
static struct genl_ops nl80211_ops[] = {
{
.cmd = NL80211_CMD_GET_WIPHY,
@@ -5082,6 +5152,12 @@ static struct genl_ops nl80211_ops[] = {
.policy = nl80211_policy,
/* can be retrieved by unprivileged users */
},
+ {
+ .cmd = NL80211_CMD_SET_CQM,
+ .doit = nl80211_set_cqm,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
};

static struct genl_multicast_group nl80211_mlme_mcgrp = {
@@ -5832,6 +5908,49 @@ void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev,
nlmsg_free(msg);
}

+void nl80211_send_cqm_notify(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev,
+ enum nl80211_cqm_state rssi_state,
+ gfp_t gfp)
+{
+ struct sk_buff *msg;
+ struct nlattr *pinfoattr;
+ void *hdr;
+
+ msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
+ if (!msg)
+ return;
+
+ hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_SET_CQM);
+ if (!hdr) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
+
+ pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM);
+ if (!pinfoattr)
+ goto nla_put_failure;
+
+ NLA_PUT_U32(msg, NL80211_ATTR_CQM_RSSI_STATE, rssi_state);
+ nla_nest_end(msg, pinfoattr);
+
+ if (genlmsg_end(msg, hdr) < 0) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+ nl80211_mlme_mcgrp.id, gfp);
+ return;
+
+ nla_put_failure:
+ genlmsg_cancel(msg, hdr);
+ nlmsg_free(msg);
+}
+
static int nl80211_netlink_notify(struct notifier_block * nb,
unsigned long state,
void *_notify)
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index 4ca5111..f72ecc8 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -82,4 +82,9 @@ void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev,
const u8 *buf, size_t len, bool ack,
gfp_t gfp);

+void nl80211_send_cqm_notify(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev,
+ enum nl80211_cqm_state rssi_state,
+ gfp_t gfp);
+
#endif /* __NET_WIRELESS_NL80211_H */
--
1.6.3.3


2010-03-17 13:30:47

by John W. Linville

[permalink] [raw]
Subject: Re: [RFC PATCHv3 0/2] mac80211: cfg80211: Roam trigger support

On Wed, Mar 17, 2010 at 03:01:15PM +0200, Juuso Oikarinen wrote:
> To implement good performance WLAN roaming, it is not sufficient to start
> scanning for other available AP's only after the currently serving association
> is lost.
>
> The entity controlling the roaming will need to get indication of a
> deteriorating WLAN connection in order to start preparing for roaming already
> before the serving association is lost. This way, it can roam to a better AP
> perhaps even before the serving association becomes too bad in quality.
>
> These patches propose an implementation facilitating this using a simple RSSI
> threshold and hysteresis approach.
>
> These patches add a nl80211 interface for simply configuring a rssi threshold
> and hysteresis value to facilitate very basic connection quality monitoring.
>
> For the triggering, these patches currently rely on HW support, host based
> triggering is not implemented, but could be added later if needed.
>
> These patches have been tested with the wl1271 driver.
>
> Thanks in advance for your comments and suggestions.
>
> Juuso Oikarinen (2):
> cfg80211: Add connection quality monitoring support to nl80211
> mac80211: Add support for connection quality monitoring

Any idea what other hardware (besides libertas) supports this concept?
Do you anticipate adding a host-based implementation to mac80211?

Is RSSI really a useful enough indicator for this function?
Will applications actually use it?

John
--
John W. Linville Someday the world will need a hero, and you
[email protected] might be all we have. Be ready.

2010-03-19 15:00:10

by John W. Linville

[permalink] [raw]
Subject: Re: [RFC PATCHv3 0/2] mac80211: cfg80211: Roam trigger support

On Fri, Mar 19, 2010 at 08:59:25AM +0200, Kalle Valo wrote:
> "John W. Linville" <[email protected]> writes:

> > Will applications actually use it?
>
> The idea is that wpa_supplicant will listen to these events, and will
> enable or disable backround scan (ie. scanning for new APs when
> associated) based on information received from the events. When the
> connection to the AP is good enough, it can disable background scan
> which makes it possible to save power and also get rid of latency
> introduced by the background scan.
>
> I haven't seen any implementation for wpa_supplicant yet, but we have
> talked about that few times during the last two years.

If you can make wpa_supplicant scan less then I am sold! :-)

John
--
John W. Linville Someday the world will need a hero, and you
[email protected] might be all we have. Be ready.

2010-03-18 16:11:04

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC PATCHv3 1/2] cfg80211: Add connection quality monitoring support to nl80211

On Thu, 2010-03-18 at 07:19 +0200, Juuso Oikarinen wrote:
> On Wed, 2010-03-17 at 17:17 +0100, ext Johannes Berg wrote:
> > On Wed, 2010-03-17 at 15:01 +0200, Juuso Oikarinen wrote:
> >
> > > +/**
> > > + * enum nl80211_cqm_state - current state in relation to set threshold
> > > + * @NL80211_CQM_STATE_ABOVE: the level is above the configured threshold
> > > + * @NL80211_CQM_STATE_BELOW: the level is below the configured threshold
> > > + */
> > > +enum nl80211_cqm_state {
> > > + NL80211_CQM_STATE_ABOVE,
> > > + NL80211_CQM_STATE_BELOW,
> > > +};
> >
> > Thoughts about removing this and just exporting the actual (smoothed?)
> > RSSI instead in the event? Or do you simply not get that from the hw?
>
> On the wl1271 we actually do get the value that triggered the event, but
> on the wl1251, for instance, we do not get it. On the wl1271 we get to
> decide the above/below on the host based on the reading, but the wl1251
> will just tell the host that now the RSSI went below, and now it just
> went above.
>
> Our thinking is that the above/below information is sufficient to make a
> decisions about roaming. Adding the literal value will give trouble with
> HW not supporting it.

Ok, that's fair. I don't want to hurt wl1251 by doing this. But then
maybe it could just retrieve the value from the last beacon?

> If you feel the actual value of the RSSI would be important, we could
> add it as an optional field to the notifcation in addition to the
> above/below.

No ... I don't actually strongly feel that the actual value is all that
relevant, although we'll only know when we implement roaming algorithms
in userspace. Maybe it would be advantageous to keep this out of the
tree for a while longer while you implement the userspace portion? But I
don't know how much you've thought about how to use this so maybe you
know it'll work :) And OTOH you kinda know it has to work since that's
what you get from the hw...

Anyhow, back to this patch again: For some reason I just don't like the
above/below thing all that much. I think in part that's because on the
one hand you say it can be extended, but on the other you call this
nl80211_cqm_state.

How about we call it nl80211_cqm_rssi_threshold_event or something like
that? Yeah it's a long and verbose name, but I think it's better than
"state"? The states you have at least are not really tied to the RSSI
stuff.

I could, for example, imagine also using this to let userspace know
about beacon loss events when they become too frequent. It's possible
that this happens while the RSSI is still high, due to interference,
after all.

johannes


2010-03-17 16:19:18

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC PATCHv3 2/2] mac80211: Add support for connection quality monitoring

On Wed, 2010-03-17 at 15:01 +0200, Juuso Oikarinen wrote:

> --- a/include/net/mac80211.h
> +++ b/include/net/mac80211.h
> @@ -599,6 +599,7 @@ enum ieee80211_conf_flags {
> * @IEEE80211_CONF_CHANGE_RETRY_LIMITS: retry limits changed
> * @IEEE80211_CONF_CHANGE_IDLE: Idle flag changed
> * @IEEE80211_CONF_CHANGE_SMPS: Spatial multiplexing powersave mode changed
> + * @IEEE80211_CONF_CHANGE_CQM: Connection quality monitor config changed
> */
> enum ieee80211_conf_changed {
> IEEE80211_CONF_CHANGE_SMPS = BIT(1),
> @@ -609,6 +610,7 @@ enum ieee80211_conf_changed {
> IEEE80211_CONF_CHANGE_CHANNEL = BIT(6),
> IEEE80211_CONF_CHANGE_RETRY_LIMITS = BIT(7),
> IEEE80211_CONF_CHANGE_IDLE = BIT(8),
> + IEEE80211_CONF_CHANGE_CQM = BIT(9),
> };
>
> /**
> @@ -662,6 +664,9 @@ enum ieee80211_smps_mode {
> * frame, called "dot11ShortRetryLimit" in 802.11, but actually means the
> * number of transmissions not the number of retries
> *
> + * @cqm_rssi_thold: Connection quality monitor RSSI threshold
> + * @cqm_rssi_hyst: Connection quality monitor RSSI hysteresis
> + *
> * @smps_mode: spatial multiplexing powersave mode; note that
> * %IEEE80211_SMPS_STATIC is used when the device is not
> * configured for an HT channel
> @@ -676,6 +681,9 @@ struct ieee80211_conf {
>
> u8 long_frame_max_tx_count, short_frame_max_tx_count;
>
> + s32 cqm_rssi_thold;
> + u8 cqm_rssi_hyst;

You probably don't care all that much, but I have a feeling this should
be part of the per-BSS data not the global configuration data, since
especially when we do it in software we could have to deal with multiple
virtual interfaces.

johannes


2010-03-18 05:25:24

by Juuso Oikarinen

[permalink] [raw]
Subject: Re: [RFC PATCHv3 2/2] mac80211: Add support for connection quality monitoring

On Wed, 2010-03-17 at 17:20 +0100, ext Johannes Berg wrote:
> On Wed, 2010-03-17 at 15:01 +0200, Juuso Oikarinen wrote:
>
> > +void ieee80211_cqm_notify(struct ieee80211_vif *vif,
> > + enum nl80211_cqm_state rssi_state)
> > +{
> > + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
> > +
> > + cfg80211_cqm_notify(sdata->dev, rssi_state, GFP_KERNEL);
> > +}
> > +EXPORT_SYMBOL(ieee80211_cqm_notify);
>
> How do you know GFP_KERNEL is OK? The driver might call this from an
> interrupt? Seems better to me to ask the driver for the allocation flags
> too.

Good point, I'll change this.

-Juuso

> johannes
>



2010-03-20 22:34:16

by Kalle Valo

[permalink] [raw]
Subject: Re: [RFC PATCHv3 0/2] mac80211: cfg80211: Roam trigger support

Jouni Malinen <[email protected]> writes:

> On Fri, Mar 19, 2010 at 10:56:37AM -0400, John W. Linville wrote:
>
>> If you can make wpa_supplicant scan less then I am sold! :-)
>
> I would assume it is not really wpa_supplicant that is triggering too
> many scans for your liking, but NetworkManager..

Yes, I also believe that's the case.

> The goal here (at least from my view point) is to actually make
> wpa_supplicant itself trigger scans more frequently ;-).

Heh, that's the finnish, pessimistic, way of answering to John's
comment :) But as John is from US, we also have to use some optimism
in the answer to not make him too nervous ;)

So the aim is to to scan more when the connection is bad. But if the
connection quality is good enough, wpa_supplicant would not scan at
all. So in some cases scanning is more frequent and in some cases
background scan is completely disabled.

The ultimate goal is to reduce the background scan whenever we can,
for example when connection is good or there's very little or no
traffic at all. But we are nowhere near that yet.

> wpa_supplicant already has a notification function just waiting to be
> called from somewhere when a beacon is lost of signal strength has
> changed.. That somewhere is supposed to be the driver event handler when
> it receives one of these new roam trigger events. At that point,
> wpa_supplicant can then figure out if it should start scanning more
> frequently to find a better BSS.

Very nice.

> I would hope that this feature will make NetworkManager eventually
> stop doing its constant scans

I also hope that this will happen. I think the current setup is just
one big layering violation. After the wifi connection is established,
NetworkManager (nor Connection Manager) should not issue a scan unless
requested by the user.

> (or well, if it doesn't, I will provide an option in for
> wpa_supplicant to ignore D-Bus requests for new scans.. ;-).

That's also one way to do it. But let's hope that we can find a better
solution.

--
Kalle Valo