On Wed, Oct 17, 2012 at 07:23:31PM -0700, [email protected] wrote:
> From: Marco Porsch <[email protected]>
> 
> According to IEEE802.11-2012 a mesh peering is always associated between
> two mesh STAs. Both mesh STAs have their own mesh power mode for the
> mesh peering. This power mode is called the link-specific power mode.
> The peer_ps_mode field has been added to the sta_info structure to
> represent the peer's link-specific power mode towards the local station.
> The nonpeer_ps_mode field has been added to represent the peer's power
> mode towards all non-peer stations.
> 
> The peer's link-specific power modes are tracked from the Power Management
> field in the Frame Control field and the Mesh Power Save Level field
> in the QoS Control field. Peer and non-peer modes are tracked independently
> from respective frames. This allows fast reconfiguration after a peering
> change.
> 
> Signed-off-by: Marco Porsch <[email protected]>
> 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 |   10 +++++++
>  net/mac80211/mesh.h       |    4 +++
>  net/mac80211/mesh_ps.c    |   73 
> +++++++++++++++++++++++++++++++++++++++++++++
>  net/mac80211/rx.c         |   27 +++++++++++++++++
>  net/mac80211/sta_info.h   |    4 +++
>  5 files changed, 118 insertions(+)
> 
> diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
> index 26fefe5..3048774 100644
> --- a/include/linux/ieee80211.h
> +++ b/include/linux/ieee80211.h
> @@ -571,6 +571,16 @@ static inline int ieee80211_is_first_frag(__le16 
> seq_ctrl)
>       return (seq_ctrl & cpu_to_le16(IEEE80211_SCTL_FRAG)) == 0;
>  }
>  
> +/**
> + * ieee80211_has_qos_pm - check Power Save Level in QoS control
> + * @qc - QoS control bytes in little-endian byteorder
> + */
> +

Extra newline.

> +static inline int ieee80211_has_qos_pm(__le16 qc)
> +{
> +     return (qc & cpu_to_le16(IEEE80211_QOS_CTL_MESH_PS_LEVEL)) != 0;

The 1st conditional alone should be sufficient?

> +}
> +
>  struct ieee80211s_hdr {
>       u8 flags;
>       u8 ttl;
> diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
> index 22c3fd6..b342933 100644
> --- a/net/mac80211/mesh.h
> +++ b/net/mac80211/mesh.h
> @@ -268,6 +268,10 @@ void ieee80211_set_local_ps_mode(struct sta_info *sta,
>                                enum nl80211_mesh_power_mode pm, u32 delay);
>  void ieee80211_set_mesh_ps_fields(struct ieee80211_sub_if_data *sdata,
>                                 struct ieee80211_hdr *hdr);
> +void ieee80211_set_peer_ps_mode(struct sta_info *sta,
> +                             struct ieee80211_hdr *hdr);
> +void ieee80211_set_nonpeer_ps_mode(struct sta_info *sta,
> +                                struct ieee80211_hdr *hdr);
>  
>  /* Mesh paths */
>  int mesh_nexthop_lookup(struct sk_buff *skb,
> diff --git a/net/mac80211/mesh_ps.c b/net/mac80211/mesh_ps.c
> index 15b3abe..5ddf7be 100644
> --- a/net/mac80211/mesh_ps.c
> +++ b/net/mac80211/mesh_ps.c
> @@ -259,3 +259,76 @@ void ieee80211_set_mesh_ps_fields(struct 
> ieee80211_sub_if_data *sdata,
>       else
>               *qc &= cpu_to_le16(~IEEE80211_QOS_CTL_MESH_PS_LEVEL);
>  }
> +
> +/**
> + * ieee80211_set_peer_ps_mode - track the neighbor mesh STA's peer-specific
> + * power mode towards the local STA
> + *
> + * @sta: STA info to update
> + * @hdr: IEEE 802.11 QoS Header
> + */
> +void ieee80211_set_peer_ps_mode(struct sta_info *sta,
> +                             struct ieee80211_hdr *hdr)
> +{
> +     enum nl80211_mesh_power_mode pm;
> +     __le16 *qc = (__le16 *) ieee80211_get_qos_ctl(hdr);
> +     static const char *modes[] = {
> +             [NL80211_MESH_POWER_ACTIVE] = "active",
> +             [NL80211_MESH_POWER_LIGHT_SLEEP] = "light sleep",
> +             [NL80211_MESH_POWER_DEEP_SLEEP] = "deep sleep",
> +     };
> +
> +     BUG_ON(!ieee80211_is_data_qos(hdr->frame_control) ||
> +            is_multicast_ether_addr(hdr->addr1));

BUG_ON(1) crashes the kernel. Can't we just WARN_ON_ONCE() then return?

> +     if (ieee80211_has_pm(hdr->frame_control)) {
> +             if (ieee80211_has_qos_pm(*qc))
> +                     pm = NL80211_MESH_POWER_DEEP_SLEEP;
> +             else
> +                     pm = NL80211_MESH_POWER_LIGHT_SLEEP;
> +     } else {
> +             pm = NL80211_MESH_POWER_ACTIVE;
> +     }
> +
> +     if (sta->peer_ps_mode == pm)
> +             return;
> +
> +     mps_dbg(sta->sdata, "STA %pM enters %s mode\n",
> +             sta->sta.addr, modes[pm]);
> +
> +     sta->peer_ps_mode = pm;
> +
> +     ieee80211_sta_ps_update(sta);
> +}
> +
> +/**
> + * ieee80211_set_nonpeer_ps_mode - track the neighbor mesh STA's
> + * power mode towards non-peer STA
> + *
> + * @sta: STA info to update
> + * @hdr: IEEE 802.11 (QoS) Header
> + */
> +void ieee80211_set_nonpeer_ps_mode(struct sta_info *sta,
> +                                struct ieee80211_hdr *hdr)
> +{
> +     enum nl80211_mesh_power_mode pm;
> +     static const char *modes[] = {
> +             [NL80211_MESH_POWER_ACTIVE] = "active",
> +             [NL80211_MESH_POWER_DEEP_SLEEP] = "deep sleep",
> +     };
> +
> +     if (ieee80211_has_pm(hdr->frame_control))
> +             pm = NL80211_MESH_POWER_DEEP_SLEEP;
> +     else
> +             pm = NL80211_MESH_POWER_ACTIVE;
> +
> +     if (sta->nonpeer_ps_mode == pm)
> +             return;
> +
> +     mps_dbg(sta->sdata, "STA %pM sets non-peer mode to %s\n",
> +             sta->sta.addr, modes[pm]);
> +
> +     sta->nonpeer_ps_mode = pm;
> +
> +     ieee80211_sta_ps_update(sta);
> +}
> diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
> index 8cedf22..b88e420 100644
> --- a/net/mac80211/rx.c
> +++ b/net/mac80211/rx.c
> @@ -1350,6 +1350,33 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data 
> *rx)
>       }
>  
>       /*
> +      * Test Power Managment field of frame control (PW) and
> +      * mesh power save level subfield of QoS control field (PSL)
> +      *
> +      * | PM | PSL| Mesh Power Mode |
> +      * +----+----+-----------------+
> +      * | 0  |Rsrv|    Active       |
> +      * | 1  | 0  |    Light        |
> +      * | 1  | 1  |    Deep         |
> +      */
> +     if (ieee80211_vif_is_mesh(&rx->sdata->vif)) {
> +             if (is_unicast_ether_addr(hdr->addr1) &&
> +                 ieee80211_is_data_qos(hdr->frame_control)) {
> +                     /*
> +                      * individually addressed QoS Data/Null frames contain
> +                      * peer's link-specific PS mode towards the local STA
> +                      */
> +                     ieee80211_set_peer_ps_mode(sta, hdr);
> +             } else {
> +                     /*
> +                      * can only determine non-peer PS mode
> +                      * (see IEEE802.11-2012 8.2.4.1.7)
> +                      */
> +                     ieee80211_set_nonpeer_ps_mode(sta, hdr);
> +             }
> +     }
> +
> +     /*
>        * 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 e911527..5fdb9d3 100644
> --- a/net/mac80211/sta_info.h
> +++ b/net/mac80211/sta_info.h
> @@ -278,6 +278,8 @@ struct sta_ampdu_mlme {
>   * @local_ps_mode: local link-specific power save mode
>   * @local_ps_mode_delayed: temp. storage for delayed setting of local_ps_mode
>   * @local_ps_mode_timer: timer for delayed setting of local_ps_mode
> + * @peer_ps_mode: peer's link-specific power save mode
> + * @nonpeer_ps_mode: STA's power save mode towards non-peer neighbors
>   * @debugfs: debug filesystem info
>   * @dead: set to true when sta is unlinked
>   * @uploaded: set to true when sta is uploaded to the driver
> @@ -378,6 +380,8 @@ struct sta_info {
>       enum nl80211_mesh_power_mode local_ps_mode;
>       enum nl80211_mesh_power_mode local_ps_mode_delayed;
>       struct timer_list local_ps_mode_timer;
> +     enum nl80211_mesh_power_mode peer_ps_mode;
> +     enum nl80211_mesh_power_mode nonpeer_ps_mode;
>  #endif
>  
>  #ifdef CONFIG_MAC80211_DEBUGFS
> -- 
> 1.7.9.5
> 
_______________________________________________
Devel mailing list
[email protected]
http://lists.open80211s.org/cgi-bin/mailman/listinfo/devel

Reply via email to