2011-11-21 14:41:23

by Ivan Bezyazychnyy

[permalink] [raw]
Subject: [RFC v2 0/8] mesh power saving implementation: indication

Hi!

We have updated our patches and also we would like to add some words
what our work is about.

Based on the latest IEEE 802.11s standard the power saving mechanism
can be divided into the following implementation phases:
* indication of mesh STAs' power modes in frames;
* a buffering and identification sending frames in mesh STA;
* Mesh Awake Window implementation;
* Peer service periods.

This patchset implements the phase of indication of mesh STAs'
power modes in frames. There are two types of mesh power modes:
* peer power mode: a mesh STA indicates its mesh power mode for each
mesh peering and obtains the mesh power modes of its peer mesh STAs;
* non-peer power mode: mesh station also indicates mesh power mode for
non-peer mesh stations. It determines when non-peer mesh STAs may send
Probe Request and Mesh Peering Open Request frames to the mesh STA.

Peer power mode should be indicated with Power Management field in the Frame
Control field and the Mesh Power Save Level field in all transmitted
individually addressed Mesh Data or QoS Null frames on this link.

Non-peer power mode should be indicated with the Power Management
field in the Frame Control field and the Mesh Power Save Level field
in the Mesh Capability field in Beacon and Probe Response frames. A
mesh STA shall also indicate its non-peer mesh power mode with the
Power Management field in the Frame Control field and the Mesh Power
Save Level field in the QoS Control field in group addressed Mesh Data
frames.

We would appreciate comments and advice.

Thanks,
Ivan

Ivan Bezyazychnyy (8):
cfg80211 and nl80211: mesh power mode config parameter
mac80211: mesh power mode indication in QoS frames
mac80211: tracking mesh peer link-specific power mode
mac80211: mesh non-peer power mode indication in beacons
mac80211: setting link-specific mesh power modes when plink opens
cfg80211 and nl80211: Setting local link-specific power mode
cfg80211 and nl80211: getting local and peer mesh power modes
cfg80211 and nl80211: setting and getting mesh non-peer power mode

include/linux/ieee80211.h | 14 ++++++++++
include/linux/nl80211.h | 41 ++++++++++++++++++++++++++++++
include/net/cfg80211.h | 14 +++++++++-
net/mac80211/cfg.c | 16 +++++++++++-
net/mac80211/mesh.c | 35 +++++++++++++++++++++++++
net/mac80211/mesh.h | 11 ++++++++
net/mac80211/mesh_plink.c | 22 +++++++++++++++-
net/mac80211/rx.c | 61 +++++++++++++++++++++++++++++++++++++++++++++
net/mac80211/sta_info.h | 4 +++
net/mac80211/tx.c | 46 ++++++++++++++++++++++++++++++++++
net/wireless/mesh.c | 1 +
net/wireless/nl80211.c | 22 ++++++++++++++++
12 files changed, 284 insertions(+), 3 deletions(-)

--
1.7.3.4



2011-11-21 14:41:46

by Ivan Bezyazychnyy

[permalink] [raw]
Subject: [RFC v2 3/8] mac80211: tracking mesh peer link-specific power mode

peer_ps_mode field has been added to sta_info structure to represent
peer's link-specific power mode for our station.

Peer's link-specific power mode is tracked from the Power Management
field in the Frame Control field and the Mesh Power Save Level field
in the QoS Control field at the end of a frame exchange sequence.

Signed-off-by: Ivan Bezyazychnyy <[email protected]>
Signed-off-by: Mike Krinkin <[email protected]>
Signed-off-by: Max Filippov <[email protected]>
---
include/linux/ieee80211.h | 11 ++++++++
net/mac80211/mesh.h | 2 +
net/mac80211/rx.c | 61 +++++++++++++++++++++++++++++++++++++++++++++
net/mac80211/sta_info.h | 2 +
4 files changed, 76 insertions(+), 0 deletions(-)

diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 483fa46..44e9c0d 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -546,6 +546,17 @@ static inline int ieee80211_is_qos_nullfunc(__le16 fc)
cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_NULLFUNC);
}

+/**
+ * ieee80211s_has_qos_pm - check Power Save Level in QoS control
+ * @qc - QoS control bytes in little-endian byteorder
+ */
+
+static inline int ieee80211s_has_qos_pm(__le16 qc)
+{
+ return (qc & cpu_to_le16(
+ IEEE80211_QOS_CTL_MESH_PS_LEVEL)) != 0;
+}
+
struct ieee80211s_hdr {
u8 flags;
u8 ttl;
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index 8c00e2d..6842453 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -222,6 +222,8 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata);
void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata);
void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata);
void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh);
+void ieee80211s_set_sta_ps_mode(struct sta_info *sta,
+ enum nl80211_mesh_power_mode mode);

/* Mesh paths */
int mesh_nexthop_lookup(struct sk_buff *skb,
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index b867bd5..40ad4ed 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1162,6 +1162,34 @@ int ieee80211_sta_ps_transition(struct ieee80211_sta *sta, bool start)
}
EXPORT_SYMBOL(ieee80211_sta_ps_transition);

+void ieee80211s_set_sta_ps_mode(struct sta_info *sta,
+ enum nl80211_mesh_power_mode mode)
+{
+ if (sta->peer_ps_mode != mode) {
+ sta->peer_ps_mode = mode;
+#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
+ switch (mode) {
+ case NL80211_MESH_POWER_ACTIVE:
+ printk(KERN_DEBUG "%s: STA %pM enters active mode\n",
+ sta->sdata->name, sta->sta.addr);
+ break;
+ case NL80211_MESH_POWER_LIGHT_SLEEP:
+ printk(KERN_DEBUG "%s: STA %pM enters light sleep mode\n",
+ sta->sdata->name, sta->sta.addr);
+ break;
+ case NL80211_MESH_POWER_DEEP_SLEEP:
+ printk(KERN_DEBUG "%s: STA %pM enters deep sleep mode\n",
+ sta->sdata->name, sta->sta.addr);
+ break;
+ default:
+ printk(KERN_DEBUG "%s: STA %pM used invalid power save mode\n",
+ sta->sdata->name, sta->sta.addr);
+ break;
+ }
+#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
+ }
+}
+
static ieee80211_rx_result debug_noinline
ieee80211_rx_h_uapsd_and_pspoll(struct ieee80211_rx_data *rx)
{
@@ -1314,6 +1342,39 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
}

/*
+ * Test mesh power save level subfield of QoS control field (PSL)
+ * and Power Managment field of frame control (PW)
+ * +----+----+-----------------+
+ * | PM | PSL| Mesh Power Mode |
+ * +----+----+-----------------+
+ * | 0 |Rsrv| Active |
+ * +----+----+-----------------+
+ * | 1 | 0 | Light |
+ * +----+----+-----------------+
+ * | 1 | 1 | Deep |
+ * +----+----+-----------------+
+ */
+ if (!ieee80211_has_morefrags(hdr->frame_control) &&
+ !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) &&
+ ieee80211_vif_is_mesh(&rx->sdata->vif) &&
+ (ieee80211_is_data(hdr->frame_control) ||
+ ieee80211_is_nullfunc(hdr->frame_control))) {
+ if (ieee80211_has_pm(hdr->frame_control)) {
+ __le16 *qc = (__le16 *) ieee80211_get_qos_ctl(hdr);
+ if (ieee80211s_has_qos_pm(*qc)) {
+ ieee80211s_set_sta_ps_mode(sta,
+ NL80211_MESH_POWER_DEEP_SLEEP);
+ } else {
+ ieee80211s_set_sta_ps_mode(sta,
+ NL80211_MESH_POWER_LIGHT_SLEEP);
+ }
+ } else {
+ ieee80211s_set_sta_ps_mode(sta,
+ NL80211_MESH_POWER_ACTIVE);
+ }
+ }
+
+ /*
* Drop (qos-)data::nullfunc frames silently, since they
* are used only to control station power saving mode.
*/
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 8742668..86fe10a 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -251,6 +251,7 @@ struct sta_ampdu_mlme {
* @ignore_plink_timer: ignore the peer-link timer (used internally)
* @plink_state: peer link state
* @local_ps_mode: local link-specific power save mode
+ * @peer_ps_mode: peer link-specific power save mode
* @plink_timeout: timeout of peer link
* @plink_timer: peer link watch timer
* @plink_timer_was_running: used by suspend/resume to restore timers
@@ -340,6 +341,7 @@ struct sta_info {
bool plink_timer_was_running;
enum nl80211_plink_state plink_state;
enum nl80211_mesh_power_mode local_ps_mode;
+ enum nl80211_mesh_power_mode peer_ps_mode;
u32 plink_timeout;
struct timer_list plink_timer;
#endif
--
1.7.3.4


2011-11-25 18:40:21

by Ivan Bezyazychnyy

[permalink] [raw]
Subject: Re: [RFC v2 0/8] mesh power saving implementation: indication

On 25 November 2011 05:40, Javier Cardona <[email protected]> wrote:
> Hi Ivan,
>
> Good work! ?Comments inline.
>
> On Mon, Nov 21, 2011 at 6:40 AM, Ivan Bezyazychnyy
> <[email protected]> wrote:
>> We have updated our patches and also we would like to add some words
>> what our work is about.
>>
>> Based on the latest IEEE 802.11s standard the power saving mechanism
>> can be divided into the following implementation phases:
>> * indication of mesh STAs' power modes in frames;
>> * a buffering and identification sending frames in mesh STA;
>> * Mesh Awake Window implementation;
>> * Peer service periods.
>
> My recommendation would be to implement this bottom up. ?That is,
> start by implementing the Extensible synchronization framework
> (Section 13.12.2, 802.11mb D10.0), as power save will not work without
> syncronization. ?After that, continue as...
>
> 13.13.8.4 Operation in light sleep mode for a mesh peering
> 13.13.4 TIM transmissions in an MBSS (and buffering)
> 13.13.6 Mesh awake window
> 13.13.9 Mesh peer service periods
>
> Only after this is implemented I would advertise this capability in
> beacons and make it configurable via userspace (i.e. what you've done
> in this patchset). ?That approach would also make it easier to test;
> only after you get the TSF right you should attempt to implement the
> awake windows and so on.
>
> Does that make sense to you?
>
Thanks. Definitely that makes sense, but we have to better understand
the first part about synchronization. We will study it.

Best regards,
Ivan

2011-11-25 01:41:17

by Javier Cardona

[permalink] [raw]
Subject: Re: [RFC v2 0/8] mesh power saving implementation: indication

Hi Ivan,

Good work! Comments inline.

On Mon, Nov 21, 2011 at 6:40 AM, Ivan Bezyazychnyy
<[email protected]> wrote:
> We have updated our patches and also we would like to add some words
> what our work is about.
>
> Based on the latest IEEE 802.11s standard the power saving mechanism
> can be divided into the following implementation phases:
> * indication of mesh STAs' power modes in frames;
> * a buffering and identification sending frames in mesh STA;
> * Mesh Awake Window implementation;
> * Peer service periods.

My recommendation would be to implement this bottom up. That is,
start by implementing the Extensible synchronization framework
(Section 13.12.2, 802.11mb D10.0), as power save will not work without
syncronization. After that, continue as...

13.13.8.4 Operation in light sleep mode for a mesh peering
13.13.4 TIM transmissions in an MBSS (and buffering)
13.13.6 Mesh awake window
13.13.9 Mesh peer service periods

Only after this is implemented I would advertise this capability in
beacons and make it configurable via userspace (i.e. what you've done
in this patchset). That approach would also make it easier to test;
only after you get the TSF right you should attempt to implement the
awake windows and so on.

Does that make sense to you?

Cheers,

Javier

---


> Ivan Bezyazychnyy (8):
> ?cfg80211 and nl80211: mesh power mode config parameter
> ?mac80211: mesh power mode indication in QoS frames
> ?mac80211: tracking mesh peer link-specific power mode
> ?mac80211: mesh non-peer power mode indication in beacons
> ?mac80211: setting link-specific mesh power modes when plink opens
> ?cfg80211 and nl80211: Setting local link-specific power mode
> ?cfg80211 and nl80211: getting local and peer mesh power modes
> ?cfg80211 and nl80211: setting and getting mesh non-peer power mode
>
> ?include/linux/ieee80211.h | ? 14 ++++++++++
> ?include/linux/nl80211.h ? | ? 41 ++++++++++++++++++++++++++++++
> ?include/net/cfg80211.h ? ?| ? 14 +++++++++-
> ?net/mac80211/cfg.c ? ? ? ?| ? 16 +++++++++++-
> ?net/mac80211/mesh.c ? ? ? | ? 35 +++++++++++++++++++++++++
> ?net/mac80211/mesh.h ? ? ? | ? 11 ++++++++
> ?net/mac80211/mesh_plink.c | ? 22 +++++++++++++++-
> ?net/mac80211/rx.c ? ? ? ? | ? 61 +++++++++++++++++++++++++++++++++++++++++++++
> ?net/mac80211/sta_info.h ? | ? ?4 +++
> ?net/mac80211/tx.c ? ? ? ? | ? 46 ++++++++++++++++++++++++++++++++++
> ?net/wireless/mesh.c ? ? ? | ? ?1 +
> ?net/wireless/nl80211.c ? ?| ? 22 ++++++++++++++++
> ?12 files changed, 284 insertions(+), 3 deletions(-)
>
> --
> 1.7.3.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to [email protected]
> More majordomo info at ?http://vger.kernel.org/majordomo-info.html
>



--
Javier Cardona
cozybit Inc.
http://www.cozybit.com

2011-11-24 18:33:20

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC v2 0/8] mesh power saving implementation: indication

On Mon, 2011-11-21 at 18:40 +0400, Ivan Bezyazychnyy wrote:

> Based on the latest IEEE 802.11s standard the power saving mechanism
> can be divided into the following implementation phases:
> * indication of mesh STAs' power modes in frames;
> * a buffering and identification sending frames in mesh STA;
> * Mesh Awake Window implementation;
> * Peer service periods.
>
> This patchset implements the phase of indication of mesh STAs'
> power modes in frames. There are two types of mesh power modes:
> * peer power mode: a mesh STA indicates its mesh power mode for each
> mesh peering and obtains the mesh power modes of its peer mesh STAs;
> * non-peer power mode: mesh station also indicates mesh power mode for
> non-peer mesh stations. It determines when non-peer mesh STAs may send
> Probe Request and Mesh Peering Open Request frames to the mesh STA.
>
> Peer power mode should be indicated with Power Management field in the Frame
> Control field and the Mesh Power Save Level field in all transmitted
> individually addressed Mesh Data or QoS Null frames on this link.
>
> Non-peer power mode should be indicated with the Power Management
> field in the Frame Control field and the Mesh Power Save Level field
> in the Mesh Capability field in Beacon and Probe Response frames. A
> mesh STA shall also indicate its non-peer mesh power mode with the
> Power Management field in the Frame Control field and the Mesh Power
> Save Level field in the QoS Control field in group addressed Mesh Data
> frames.
>
> We would appreciate comments and advice.

I just did a cursory review -- I only looked at code style and general
issues.

I expect that Thomas/Javier will review this from a functionality POV, I
have no idea if these per-station things etc. even make sense.

johannes


2011-11-21 14:41:49

by Ivan Bezyazychnyy

[permalink] [raw]
Subject: [RFC v2 4/8] mac80211: mesh non-peer power mode indication in beacons

According to IEEE80211s standard a mesh STA shall indicate its
non-peer mesh power mode with the Power Management field in the Frame
Control field and the Mesh Power Save Level field in the Mesh
Capability field in Beacon and Probe Response frames.

Signed-off-by: Ivan Bezyazychnyy <[email protected]>
Signed-off-by: Mike Krinkin <[email protected]>
Signed-off-by: Max Filippov <[email protected]>
---
net/mac80211/mesh.c | 2 ++
net/mac80211/mesh.h | 3 +++
net/mac80211/tx.c | 3 +++
3 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index a7078fd..5b8c5d3 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -242,6 +242,8 @@ mesh_add_meshconf_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
/* Mesh capability */
ifmsh->accepting_plinks = mesh_plink_availables(sdata);
*pos = MESHCONF_CAPAB_FORWARDING;
+ if (sdata->u.mesh.mshcfg.power_mode == NL80211_MESH_POWER_DEEP_SLEEP)
+ *pos |= MESHCONF_CAPAB_POWER_SAVE_LEVEL;
*pos++ |= ifmsh->accepting_plinks ?
MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00;
*pos++ = 0x00;
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index 6842453..e62c53b 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -188,6 +188,9 @@ struct mesh_rmc {
/* Maximum number of paths per interface */
#define MESH_MAX_MPATHS 1024

+/* capability power save flag mask */
+#define MESHCONF_CAPAB_POWER_SAVE_LEVEL 0x80
+
/* Public interfaces */
/* Various */
int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 500c3ce..aeb2968 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2339,6 +2339,9 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
mgmt->frame_control =
cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON);
+ if (sdata->u.mesh.mshcfg.power_mode !=
+ NL80211_MESH_POWER_ACTIVE)
+ mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
memset(mgmt->da, 0xff, ETH_ALEN);
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
--
1.7.3.4


2011-11-21 14:41:52

by Ivan Bezyazychnyy

[permalink] [raw]
Subject: [RFC v2 5/8] mac80211: setting link-specific mesh power modes when plink opens

When plink is opened peer link-specific power mode is set up equal to
peer non-peer power mode value.

When plink is opened local link-specific power mode is set up equal
to local non-peer value.

Signed-off-by: Ivan Bezyazychnyy <[email protected]>
Signed-off-by: Mike Krinkin <[email protected]>
Signed-off-by: Max Filippov <[email protected]>
---
net/mac80211/mesh.c | 33 +++++++++++++++++++++++++++++++++
net/mac80211/mesh.h | 6 ++++++
net/mac80211/mesh_plink.c | 22 +++++++++++++++++++++-
3 files changed, 60 insertions(+), 1 deletions(-)

diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 5b8c5d3..5963164 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -386,6 +386,39 @@ void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh)
}
}

+void ieee80211s_set_local_ps_mode(struct sta_info *sta, u8 pm)
+{
+ switch (pm) {
+ case NL80211_MESH_POWER_ACTIVE:
+ sta->local_ps_mode = NL80211_MESH_POWER_ACTIVE;
+#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
+ printk(KERN_DEBUG "%s: local STA operates in active mode with STA %pM\n",
+ sta->sdata->name, sta->sta.addr);
+#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
+ break;
+ case NL80211_MESH_POWER_LIGHT_SLEEP:
+ sta->local_ps_mode = NL80211_MESH_POWER_LIGHT_SLEEP;
+#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
+ printk(KERN_DEBUG "%s: local STA operates in light sleep mode with STA %pM\n",
+ sta->sdata->name, sta->sta.addr);
+#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
+ break;
+ case NL80211_MESH_POWER_DEEP_SLEEP:
+ sta->local_ps_mode = NL80211_MESH_POWER_DEEP_SLEEP;
+#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
+ printk(KERN_DEBUG "%s: local STA operates in deep sleep mode with STA %pM\n",
+ sta->sdata->name, sta->sta.addr);
+#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
+ break;
+ default:
+#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
+ printk(KERN_DEBUG "%s: local STA used invalid power mode to operate with STA %pM\n",
+ sta->sdata->name, sta->sta.addr);
+#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
+ break;
+ }
+}
+
/**
* ieee80211_fill_mesh_addresses - fill addresses of a locally originated mesh frame
* @hdr: 802.11 frame header
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index e62c53b..1b2c58d 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -227,6 +227,7 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata);
void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh);
void ieee80211s_set_sta_ps_mode(struct sta_info *sta,
enum nl80211_mesh_power_mode mode);
+void ieee80211s_set_local_ps_mode(struct sta_info *sta, u8 pm);

/* Mesh paths */
int mesh_nexthop_lookup(struct sk_buff *skb,
@@ -312,6 +313,11 @@ static inline bool mesh_path_sel_is_hwmp(struct ieee80211_sub_if_data *sdata)
return sdata->u.mesh.mesh_pp_id == IEEE80211_PATH_PROTOCOL_HWMP;
}

+static inline bool ieee80211s_has_capab_pm(__le16 capab_info)
+{
+ return (capab_info & MESHCONF_CAPAB_POWER_SAVE_LEVEL) != 0;
+}
+
void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local);

void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata);
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 7e57f5d..a8f92f3 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -248,6 +248,8 @@ void mesh_neighbour_update(u8 *hw_addr, u32 rates,
{
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
+ struct ieee80211_mgmt *mgmt = container_of(hw_addr,
+ struct ieee80211_mgmt, sa[0]);

rcu_read_lock();

@@ -275,8 +277,26 @@ void mesh_neighbour_update(u8 *hw_addr, u32 rates,
if (mesh_peer_accepts_plinks(elems) &&
sta->plink_state == NL80211_PLINK_LISTEN &&
sdata->u.mesh.accepting_plinks &&
- sdata->u.mesh.mshcfg.auto_open_plinks)
+ sdata->u.mesh.mshcfg.auto_open_plinks) {
+ if (ieee80211_has_pm(mgmt->frame_control)) {
+ __le16 capab_info = mgmt->u.probe_resp.capab_info;
+ if (ieee80211s_has_capab_pm(capab_info)) {
+ ieee80211s_set_sta_ps_mode(sta,
+ NL80211_MESH_POWER_DEEP_SLEEP);
+ } else {
+ ieee80211s_set_sta_ps_mode(sta,
+ NL80211_MESH_POWER_LIGHT_SLEEP);
+ }
+ } else {
+ ieee80211s_set_sta_ps_mode(sta,
+ NL80211_MESH_POWER_ACTIVE);
+ }
+
+ ieee80211s_set_local_ps_mode(sta,
+ sdata->u.mesh.mshcfg.power_mode);
+
mesh_plink_open(sta);
+ }

rcu_read_unlock();
}
--
1.7.3.4


2011-11-21 14:41:55

by Ivan Bezyazychnyy

[permalink] [raw]
Subject: [RFC v2 6/8] cfg80211 and nl80211: Setting local link-specific power mode

Local link-specific power mode defines a mesh power mode in which it
operates for the mesh peering with the station. Possibility of setting
local link-specific power mode is added.

Signed-off-by: Ivan Bezyazychnyy <[email protected]>
Signed-off-by: Mike Krinkin <[email protected]>
---
include/linux/nl80211.h | 3 +++
include/net/cfg80211.h | 2 ++
net/mac80211/cfg.c | 5 +++++
net/wireless/nl80211.c | 8 ++++++++
4 files changed, 18 insertions(+), 0 deletions(-)

diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 001e9e3..ce789ce 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -1054,6 +1054,7 @@ enum nl80211_commands {
* %NL80211_ATTR_SUPPORTED_IFTYPES) containing the interface types that
* are managed in software: interfaces of these types aren't subject to
* any restrictions in their number or combinations.
+ * @NL80211_ATTR_LOCAL_MESH_POWER_MODE: local mesh STA link-specific power mode
*
* @%NL80211_ATTR_REKEY_DATA: nested attribute containing the information
* necessary for GTK rekeying in the device, see &enum nl80211_rekey_data.
@@ -1337,6 +1338,8 @@ enum nl80211_attrs {
NL80211_ATTR_TDLS_SUPPORT,
NL80211_ATTR_TDLS_EXTERNAL_SETUP,

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

__NL80211_ATTR_AFTER_LAST,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index e00e04e..2204222 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -456,6 +456,7 @@ enum station_parameters_apply_mask {
* as the AC bitmap in the QoS info field
* @max_sp: max Service Period. same format as the MAX_SP in the
* QoS info field (but already shifted down)
+ * @local_ps_mode: local link-specific mesh power save mode
*/
struct station_parameters {
u8 *supported_rates;
@@ -470,6 +471,7 @@ struct station_parameters {
struct ieee80211_ht_cap *ht_capa;
u8 uapsd_queues;
u8 max_sp;
+ u8 local_ps_mode;
};

/**
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index e253afa..78c61ee 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -804,6 +804,11 @@ static void sta_apply_parameters(struct ieee80211_local *local,
mesh_plink_block(sta);
break;
}
+
+ if (params->local_ps_mode) {
+ ieee80211s_set_local_ps_mode(sta,
+ params->local_ps_mode);
+ }
#endif
}
}
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 48260c2..80bc2a7 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2517,6 +2517,10 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
params.plink_state =
nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_STATE]);

+ if (info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE])
+ params.local_ps_mode =
+ nla_get_u8(info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE]);
+
err = get_vlan(info, rdev, &params.vlan);
if (err)
goto out;
@@ -2531,6 +2535,8 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
/* disallow mesh-specific things */
if (params.plink_action)
err = -EINVAL;
+ if (params.local_ps_mode)
+ err = -EINVAL;
break;
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_STATION:
@@ -2554,6 +2560,8 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) &&
(params.sta_flags_mask & BIT(NL80211_STA_FLAG_TDLS_PEER)))
err = -EINVAL;
+ if (params.local_ps_mode)
+ err = -EINVAL;
break;
case NL80211_IFTYPE_MESH_POINT:
/* disallow things mesh doesn't support */
--
1.7.3.4


2011-11-21 14:41:57

by Ivan Bezyazychnyy

[permalink] [raw]
Subject: [RFC v2 7/8] cfg80211 and nl80211: getting local and peer mesh power modes

Link-specific power mode defines a mesh power mode in which it
operates for the mesh peering with the station. Possibility of getting
local link-specific power mode and peer link-specific power mode is
added.

Signed-off-by: Ivan Bezyazychnyy <[email protected]>
Signed-off-by: Mike Krinkin <[email protected]>
---
include/linux/nl80211.h | 6 ++++++
include/net/cfg80211.h | 10 +++++++++-
net/mac80211/cfg.c | 6 +++++-
net/wireless/nl80211.c | 6 ++++++
4 files changed, 26 insertions(+), 2 deletions(-)

diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index ce789ce..4f4bfb8 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -1552,6 +1552,10 @@ enum nl80211_sta_bss_param {
* containing info as possible, see &enum nl80211_sta_bss_param
* @NL80211_STA_INFO_CONNECTED_TIME: time since the station is last connected
* @NL80211_STA_INFO_STA_FLAGS: Contains a struct nl80211_sta_flag_update.
+ * @NL80211_STA_INFO_LOCAL_MESH_PS_MODE: local mesh STA link-specific power
+ * save mode
+ * @NL80211_STA_INFO_PEER_MESH_PS_MODE: peer mesh STA link-specific power
+ * save mode
* @__NL80211_STA_INFO_AFTER_LAST: internal
* @NL80211_STA_INFO_MAX: highest possible station info attribute
*/
@@ -1574,6 +1578,8 @@ enum nl80211_sta_info {
NL80211_STA_INFO_BSS_PARAM,
NL80211_STA_INFO_CONNECTED_TIME,
NL80211_STA_INFO_STA_FLAGS,
+ NL80211_STA_INFO_LOCAL_MESH_PS_MODE,
+ NL80211_STA_INFO_PEER_MESH_PS_MODE,

/* keep last */
__NL80211_STA_INFO_AFTER_LAST,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 2204222..845937c 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -500,6 +500,8 @@ struct station_parameters {
* @STATION_INFO_CONNECTED_TIME: @connected_time filled
* @STATION_INFO_ASSOC_REQ_IES: @assoc_req_ies filled
* @STATION_INFO_STA_FLAGS: @sta_flags filled
+ * @STATION_INFO_LOCAL_MESH_PS_MODE: @local_ps_mode filled
+ * @STATION_INFO_PEER_MESH_PS_MODE: @peer_ps_mode filled
*/
enum station_info_flags {
STATION_INFO_INACTIVE_TIME = 1<<0,
@@ -520,7 +522,9 @@ enum station_info_flags {
STATION_INFO_BSS_PARAM = 1<<15,
STATION_INFO_CONNECTED_TIME = 1<<16,
STATION_INFO_ASSOC_REQ_IES = 1<<17,
- STATION_INFO_STA_FLAGS = 1<<18
+ STATION_INFO_STA_FLAGS = 1<<18,
+ STATION_INFO_LOCAL_MESH_PS_MODE = 1<<17,
+ STATION_INFO_PEER_MESH_PS_MODE = 1<<18
};

/**
@@ -608,6 +612,8 @@ struct sta_bss_parameters {
* @tx_failed: number of failed transmissions (retries exceeded, no ACK)
* @rx_dropped_misc: Dropped for un-specified reason.
* @bss_param: current BSS parameters
+ * @local_ps_mode: local mesh STA power save mode
+ * @peer_ps_mode: peer mesh STA power save mode
* @generation: generation number for nl80211 dumps.
* This number should increase every time the list of stations
* changes, i.e. when a station is added or removed, so that
@@ -638,6 +644,8 @@ struct station_info {
u32 rx_dropped_misc;
struct sta_bss_parameters bss_param;
struct nl80211_sta_flag_update sta_flags;
+ u8 local_ps_mode;
+ u8 peer_ps_mode;

int generation;

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 78c61ee..2b0cc2c 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -388,11 +388,15 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
#ifdef CONFIG_MAC80211_MESH
sinfo->filled |= STATION_INFO_LLID |
STATION_INFO_PLID |
- STATION_INFO_PLINK_STATE;
+ STATION_INFO_PLINK_STATE |
+ STATION_INFO_LOCAL_MESH_PS_MODE |
+ STATION_INFO_PEER_MESH_PS_MODE;

sinfo->llid = le16_to_cpu(sta->llid);
sinfo->plid = le16_to_cpu(sta->plid);
sinfo->plink_state = sta->plink_state;
+ sinfo->local_ps_mode = sta->local_ps_mode;
+ sinfo->peer_ps_mode = sta->peer_ps_mode;
#endif
}

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 80bc2a7..c53c8bb 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2325,6 +2325,12 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
if (sinfo->filled & STATION_INFO_TX_FAILED)
NLA_PUT_U32(msg, NL80211_STA_INFO_TX_FAILED,
sinfo->tx_failed);
+ if (sinfo->filled & STATION_INFO_LOCAL_MESH_PS_MODE)
+ NLA_PUT_U8(msg, NL80211_STA_INFO_LOCAL_MESH_PS_MODE,
+ sinfo->local_ps_mode);
+ if (sinfo->filled & STATION_INFO_PEER_MESH_PS_MODE)
+ NLA_PUT_U8(msg, NL80211_STA_INFO_PEER_MESH_PS_MODE,
+ sinfo->peer_ps_mode);
if (sinfo->filled & STATION_INFO_BSS_PARAM) {
bss_param = nla_nest_start(msg, NL80211_STA_INFO_BSS_PARAM);
if (!bss_param)
--
1.7.3.4


2011-11-21 14:42:00

by Ivan Bezyazychnyy

[permalink] [raw]
Subject: [RFC v2 8/8] cfg80211 and nl80211: setting and getting mesh non-peer power mode

The non-peer mesh power mode determines when non-peer mesh STAs may
send Probe Request and Mesh Peering Open Request frames to the mesh STA.
Possibilities of setting and getting mesh non-peer power mode are
added.

Signed-off-by: Ivan Bezyazychnyy <[email protected]>
Signed-off-by: Mike Krinkin <[email protected]>
---
include/linux/nl80211.h | 3 +++
net/mac80211/cfg.c | 5 +++++
net/wireless/nl80211.c | 8 ++++++++
3 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 4f4bfb8..78807f4 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -2015,6 +2015,8 @@ enum nl80211_mesh_power_mode {
* access to a broader network beyond the MBSS. This is done via Root
* Announcement frames.
*
+ * @NL80211_MESHCONF_POWER_MODE: mesh non-peer power mode
+ *
* @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute
*
* @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
@@ -2038,6 +2040,7 @@ enum nl80211_meshconf_params {
NL80211_MESHCONF_ELEMENT_TTL,
NL80211_MESHCONF_HWMP_RANN_INTERVAL,
NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
+ NL80211_MESHCONF_POWER_MODE,

/* keep last */
__NL80211_MESHCONF_ATTR_AFTER_LAST,
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 2b0cc2c..e841740 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1227,6 +1227,11 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy,
conf->dot11MeshHWMPRannInterval =
nconf->dot11MeshHWMPRannInterval;
}
+ if (_chg_mesh_attr(NL80211_MESHCONF_POWER_MODE, mask)) {
+ conf->power_mode = nconf->power_mode;
+ ieee80211_bss_info_change_notify(sdata,
+ BSS_CHANGED_BEACON);
+ }
return 0;
}

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index c53c8bb..cfa8b0e 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -3144,6 +3144,8 @@ static int nl80211_get_mesh_config(struct sk_buff *skb,
cur_params.dot11MeshHWMPRannInterval);
NLA_PUT_U8(msg, NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
cur_params.dot11MeshGateAnnouncementProtocol);
+ NLA_PUT_U8(msg, NL80211_MESHCONF_POWER_MODE,
+ cur_params.power_mode);
nla_nest_end(msg, pinfoattr);
genlmsg_end(msg, hdr);
return genlmsg_reply(msg, info);
@@ -3174,6 +3176,8 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A
[NL80211_MESHCONF_HWMP_ROOTMODE] = { .type = NLA_U8 },
[NL80211_MESHCONF_HWMP_RANN_INTERVAL] = { .type = NLA_U16 },
[NL80211_MESHCONF_GATE_ANNOUNCEMENTS] = { .type = NLA_U8 },
+
+ [NL80211_MESHCONF_POWER_MODE] = { .type = NLA_U8 },
};

static const struct nla_policy
@@ -3260,6 +3264,10 @@ do {\
dot11MeshGateAnnouncementProtocol, mask,
NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
nla_get_u8);
+ FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
+ power_mode, mask,
+ NL80211_MESHCONF_POWER_MODE,
+ nla_get_u8);
if (mask_out)
*mask_out = mask;

--
1.7.3.4


2011-11-21 14:41:40

by Ivan Bezyazychnyy

[permalink] [raw]
Subject: [RFC v2 1/8] cfg80211 and nl80211: mesh power mode config parameter

According to IEEE80211s standard a mesh STA maintains a mesh power mode
for non-peer mesh STAs. Non-peer mesh power mode is a mesh configuration
parameter so it should be presented in mesh_config structure. Possible
values for mesh power mode are presented in nl80211_mesh_power_mode
enumeration. These modes are active, light sleep and deep sleep.

Signed-off-by: Ivan Bezyazychnyy <[email protected]>
Signed-off-by: Mike Krinkin <[email protected]>
---
include/linux/nl80211.h | 29 +++++++++++++++++++++++++++++
include/net/cfg80211.h | 2 ++
net/wireless/mesh.c | 1 +
3 files changed, 32 insertions(+), 0 deletions(-)

diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 8049bf7..001e9e3 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -1915,6 +1915,35 @@ enum nl80211_mntr_flags {
};

/**
+ * enum nl80211_mesh_power_mode - mesh power save modes
+ *
+ * @__NL80211_MESH_POWER_INVALID - internal use
+ *
+ * @NL80211_MESH_POWER_ACTIVE - active mesh power mode, mesh STA
+ * in Awake state all the time
+ * @NL80211_MESH_POWER_LIGHT_SLEEP - light sleep mode, mesh STA
+ * alternate between Active and Doze states,
+ * mesh STA should listen to all the beacons
+ * @NL80211_MESH_POWER_DEEP_SLEEP - deep sleep mode, mesh STA
+ * alternates between Active and Doze states,
+ * may choose not listen to the beacons
+ *
+ * @__NL80211_MESH_POWER_AFTER_LAST - internal use
+ * @NL80211_MESH_POWER_MAX - highest possible power save level
+ */
+
+enum nl80211_mesh_power_mode {
+ __NL80211_MESH_POWER_INVALID,
+
+ NL80211_MESH_POWER_ACTIVE,
+ NL80211_MESH_POWER_LIGHT_SLEEP,
+ NL80211_MESH_POWER_DEEP_SLEEP,
+
+ __NL80211_MESH_POWER_AFTER_LAST,
+ NL80211_MESH_POWER_MAX = __NL80211_MESH_POWER_AFTER_LAST - 1
+};
+
+/**
* enum nl80211_meshconf_params - mesh configuration parameters
*
* Mesh configuration parameters. These can be changed while the mesh is
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 92cf1c2..e00e04e 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -765,6 +765,8 @@ struct mesh_config {
u16 dot11MeshMaxPeerLinks;
u8 dot11MeshMaxRetries;
u8 dot11MeshTTL;
+ /* non-peer mesh power save mode */
+ u8 power_mode;
/* ttl used in path selection information elements */
u8 element_ttl;
bool auto_open_plinks;
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index 4423e64..5febd0b 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -52,6 +52,7 @@ const struct mesh_config default_mesh_config = {
.min_discovery_timeout = MESH_MIN_DISCOVERY_TIMEOUT,
.dot11MeshHWMPRannInterval = MESH_RANN_INTERVAL,
.dot11MeshGateAnnouncementProtocol = false,
+ .power_mode = NL80211_MESH_POWER_ACTIVE,
};

const struct mesh_setup default_mesh_setup = {
--
1.7.3.4


2011-11-24 18:31:27

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC v2 7/8] cfg80211 and nl80211: getting local and peer mesh power modes

On Mon, 2011-11-21 at 18:40 +0400, Ivan Bezyazychnyy wrote:

> @@ -520,7 +522,9 @@ enum station_info_flags {
> STATION_INFO_BSS_PARAM = 1<<15,
> STATION_INFO_CONNECTED_TIME = 1<<16,
> STATION_INFO_ASSOC_REQ_IES = 1<<17,
> - STATION_INFO_STA_FLAGS = 1<<18
> + STATION_INFO_STA_FLAGS = 1<<18,
> + STATION_INFO_LOCAL_MESH_PS_MODE = 1<<17,
> + STATION_INFO_PEER_MESH_PS_MODE = 1<<18
> };

Did you ever even test this?

johannes


2011-11-21 14:41:43

by Ivan Bezyazychnyy

[permalink] [raw]
Subject: [RFC v2 2/8] mac80211: mesh power mode indication in QoS frames

According to IEEE80211s standard a mesh peering is always associated
with two mesh STAs. Both mesh STAs have their own mesh power mode for
the mesh peering. This power mode is called as link-specific power
mode.

local_ps_mode field has been added to sta_info structure to represent
link-specific power mode at this station for station represented by
this structure.

According to this standard mesh STA shall indicate its non-peer mesh
power mode with the Power Management field in the Frame Control field
and the Mesh Power Save Level field in the QoS Control field in group
addressed Mesh Data frames.

And mesh STA shall indicate link-specific power mode with the Power
Management field in the Frame Control field and the Mesh Power Save
Level field in the QoS Control field in all transmitted individually
addressed Mesh Data frames and QoS Null frames.

The Power Management field set to 1 and the Mesh Power Save Level
subfield set to 0 indicate that the mesh STA is operating in light
mode. The Power Management field set to 0 and the mesh Power Save
Level subfield set to 1 indicate that the mesh STA is operating in
deep sleep mode. The Mesh Power Save Level subfield is reserved, if
the Power Management subfield is set to 0.

Signed-off-by: Ivan Bezyazychnyy <[email protected]>
Signed-off-by: Mike Krinkin <[email protected]>
Signed-off-by: Max Filippov <[email protected]>
Signed-off-by: Marco Porsch <[email protected]>
---
include/linux/ieee80211.h | 3 +++
net/mac80211/sta_info.h | 2 ++
net/mac80211/tx.c | 43 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 48 insertions(+), 0 deletions(-)

diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 48363c3..483fa46 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -133,6 +133,9 @@
/* Mesh Control 802.11s */
#define IEEE80211_QOS_CTL_MESH_CONTROL_PRESENT 0x0100

+/* mesh power save level subfield mask */
+#define IEEE80211_QOS_CTL_MESH_PS_LEVEL 0x0200
+
/* U-APSD queue for WMM IEs sent by AP */
#define IEEE80211_WMM_IE_AP_QOSINFO_UAPSD (1<<7)
#define IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK 0x0f
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 8c8ce05..8742668 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -250,6 +250,7 @@ struct sta_ampdu_mlme {
* @plink_retries: Retries in establishment
* @ignore_plink_timer: ignore the peer-link timer (used internally)
* @plink_state: peer link state
+ * @local_ps_mode: local link-specific power save mode
* @plink_timeout: timeout of peer link
* @plink_timer: peer link watch timer
* @plink_timer_was_running: used by suspend/resume to restore timers
@@ -338,6 +339,7 @@ struct sta_info {
bool ignore_plink_timer;
bool plink_timer_was_running;
enum nl80211_plink_state plink_state;
+ enum nl80211_mesh_power_mode local_ps_mode;
u32 plink_timeout;
struct timer_list plink_timer;
#endif
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 48bbb96..500c3ce 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1033,6 +1033,47 @@ ieee80211_tx_h_calculate_duration(struct ieee80211_tx_data *tx)
return TX_CONTINUE;
}

+static enum nl80211_mesh_power_mode
+ieee80211s_get_ps_mode(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_hdr *hdr)
+{
+ enum nl80211_mesh_power_mode pm = NL80211_MESH_POWER_ACTIVE;
+ struct mesh_path *mpath;
+
+ if (is_multicast_ether_addr(hdr->addr1)) {
+ pm = (enum nl80211_mesh_power_mode)
+ sdata->u.mesh.mshcfg.power_mode;
+ } else {
+ rcu_read_lock();
+ mpath = mesh_path_lookup(hdr->addr3, sdata);
+ if (mpath) {
+ pm = mpath->next_hop->local_ps_mode;
+ }
+ rcu_read_unlock();
+ }
+
+ return pm;
+}
+
+static void ieee80211_set_mesh_ps_fields(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_hdr *hdr)
+{
+ if (ieee80211_vif_is_mesh(&sdata->vif) &&
+ (ieee80211_is_data_qos(hdr->frame_control)
+ || ieee80211_is_qos_nullfunc(hdr->frame_control))) {
+ enum nl80211_mesh_power_mode
+ pm = ieee80211s_get_ps_mode(sdata, hdr);
+ if (pm != NL80211_MESH_POWER_ACTIVE) {
+ __le16 *qc = (__le16 *) ieee80211_get_qos_ctl(hdr);
+ hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
+ if (pm == NL80211_MESH_POWER_DEEP_SLEEP) {
+ *qc |= cpu_to_le16(
+ IEEE80211_QOS_CTL_MESH_PS_LEVEL);
+ }
+ }
+ }
+}
+
/* actual transmit path */

static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx,
@@ -1437,6 +1478,8 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
}

ieee80211_set_qos_hdr(sdata, skb);
+ if (ieee80211_vif_is_mesh(&sdata->vif))
+ ieee80211_set_mesh_ps_fields(sdata, hdr);
ieee80211_tx(sdata, skb, false);
rcu_read_unlock();
}
--
1.7.3.4


2011-11-24 18:26:09

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC v2 3/8] mac80211: tracking mesh peer link-specific power mode

On Mon, 2011-11-21 at 18:40 +0400, Ivan Bezyazychnyy wrote:
> peer_ps_mode field has been added to sta_info structure to represent
> peer's link-specific power mode for our station.
>
> Peer's link-specific power mode is tracked from the Power Management
> field in the Frame Control field and the Mesh Power Save Level field
> in the QoS Control field at the end of a frame exchange sequence.
>
> Signed-off-by: Ivan Bezyazychnyy <[email protected]>
> Signed-off-by: Mike Krinkin <[email protected]>
> Signed-off-by: Max Filippov <[email protected]>
> ---
> include/linux/ieee80211.h | 11 ++++++++
> net/mac80211/mesh.h | 2 +
> net/mac80211/rx.c | 61 +++++++++++++++++++++++++++++++++++++++++++++
> net/mac80211/sta_info.h | 2 +
> 4 files changed, 76 insertions(+), 0 deletions(-)
>
> diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
> index 483fa46..44e9c0d 100644
> --- a/include/linux/ieee80211.h
> +++ b/include/linux/ieee80211.h
> @@ -546,6 +546,17 @@ static inline int ieee80211_is_qos_nullfunc(__le16 fc)
> cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_NULLFUNC);
> }
>
> +/**
> + * ieee80211s_has_qos_pm - check Power Save Level in QoS control
> + * @qc - QoS control bytes in little-endian byteorder
> + */
> +
> +static inline int ieee80211s_has_qos_pm(__le16 qc)

bool

> +{
> + return (qc & cpu_to_le16(
> + IEEE80211_QOS_CTL_MESH_PS_LEVEL)) != 0;
> +}

and with bool there's no need for the != 0 part.

> +void ieee80211s_set_sta_ps_mode(struct sta_info *sta,
> + enum nl80211_mesh_power_mode mode)

static?

> static ieee80211_rx_result debug_noinline
> ieee80211_rx_h_uapsd_and_pspoll(struct ieee80211_rx_data *rx)
> {
> @@ -1314,6 +1342,39 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
> }
>
> /*
> + * Test mesh power save level subfield of QoS control field (PSL)
> + * and Power Managment field of frame control (PW)
> + * +----+----+-----------------+
> + * | PM | PSL| Mesh Power Mode |
> + * +----+----+-----------------+
> + * | 0 |Rsrv| Active |
> + * +----+----+-----------------+
> + * | 1 | 0 | Light |
> + * +----+----+-----------------+
> + * | 1 | 1 | Deep |
> + * +----+----+-----------------+
> + */
> + if (!ieee80211_has_morefrags(hdr->frame_control) &&
> + !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) &&
> + ieee80211_vif_is_mesh(&rx->sdata->vif) &&
> + (ieee80211_is_data(hdr->frame_control) ||
> + ieee80211_is_nullfunc(hdr->frame_control))) {
> + if (ieee80211_has_pm(hdr->frame_control)) {
> + __le16 *qc = (__le16 *) ieee80211_get_qos_ctl(hdr);
> + if (ieee80211s_has_qos_pm(*qc)) {

I don't think you guaranteed that it even has a QoS header.

johannes


2011-11-25 18:35:36

by Ivan Bezyazychnyy

[permalink] [raw]
Subject: Re: [RFC v2 0/8] mesh power saving implementation: indication

On 24 November 2011 22:33, Johannes Berg <[email protected]> wrote:
> On Mon, 2011-11-21 at 18:40 +0400, Ivan Bezyazychnyy wrote:
>
>> Based on the latest IEEE 802.11s standard the power saving mechanism
>> can be divided into the following implementation phases:
>> * indication of mesh STAs' power modes in frames;
>> * a buffering and identification sending frames in mesh STA;
>> * Mesh Awake Window implementation;
>> * Peer service periods.
>>
>> This patchset implements the phase of indication of mesh STAs'
>> power modes in frames. There are two types of mesh power modes:
>> * peer power mode: a mesh STA indicates its mesh power mode for each
>> mesh peering and obtains the mesh power modes of its peer mesh STAs;
>> * non-peer power mode: mesh station also indicates mesh power mode for
>> non-peer mesh stations. It determines when non-peer mesh STAs may send
>> Probe Request and Mesh Peering Open Request frames to the mesh STA.
>>
>> Peer power mode should be indicated with Power Management field in the Frame
>> Control field and the Mesh Power Save Level field in all transmitted
>> individually addressed Mesh Data or QoS Null frames on this link.
>>
>> Non-peer power mode should be indicated with the Power Management
>> field in the Frame Control field and the Mesh Power Save Level field
>> in the Mesh Capability field in Beacon and Probe Response frames. A
>> mesh STA shall also indicate its non-peer mesh power mode with the
>> Power Management field in the Frame Control field and the Mesh Power
>> Save Level field in the QoS Control field in group addressed Mesh Data
>> frames.
>>
>> We would appreciate comments and advice.
>
> I just did a cursory review -- I only looked at code style and general
> issues.
>
Thanks for review,

Best regards,
Ivan

2011-11-24 18:29:07

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC v2 5/8] mac80211: setting link-specific mesh power modes when plink opens

On Mon, 2011-11-21 at 18:40 +0400, Ivan Bezyazychnyy wrote:

> +static inline bool ieee80211s_has_capab_pm(__le16 capab_info)
> +{
> + return (capab_info & MESHCONF_CAPAB_POWER_SAVE_LEVEL) != 0;
> +}

To me it look like sparse will warn here.

> --- a/net/mac80211/mesh_plink.c
> +++ b/net/mac80211/mesh_plink.c
> @@ -248,6 +248,8 @@ void mesh_neighbour_update(u8 *hw_addr, u32 rates,
> {
> struct ieee80211_local *local = sdata->local;
> struct sta_info *sta;
> + struct ieee80211_mgmt *mgmt = container_of(hw_addr,
> + struct ieee80211_mgmt, sa[0]);

You've got to be kidding! Change the prototypes accordingly if you need
more stuff.

johannes