2011-09-08 00:50:00

by Javier Cardona

[permalink] [raw]
Subject: [PATCH v2 0/3] QoS headers for mesh

Mesh frames are required to QoS headers to indicate the presence of a Mesh
Control Header in the payload. These patches add QoS headers to mesh frames,
but note that they don't implement full QoS support: mesh stations don't
currently advertise QoS capabilities.

v2:
- Pretend all mesh stations are QoS capable (Johannes). I've also checked that
mesh stations must support QoS (I could only find that in the informative
sections of the 11s draft, section Y.1), so this seems to be the right thing.
I would like to prevent the creation of mesh interfaces if the underlying
hardware does not support QoS. That will be in a follow up patch.

- Do not strip the QoS header in mesh traffic until any frames to be forwarded
have been cloned.

Javier Cardona (3):
mac80211: Start implementing QoS support for mesh interfaces
mac80211: Mesh data frames must have the QoS header
mac80211: Mark all mesh stations as QoS capable

---
include/linux/ieee80211.h | 2 ++
net/mac80211/mesh.c | 9 +++++----
net/mac80211/mesh_pathtbl.c | 4 ++++
net/mac80211/mesh_plink.c | 2 +-
net/mac80211/rx.c | 14 +++++++-------
net/mac80211/tx.c | 9 +++++++--
net/mac80211/wme.c | 16 +++++++---------
net/mac80211/wme.h | 3 ++-
8 files changed, 35 insertions(+), 24 deletions(-)

--
1.7.6



2011-09-08 00:50:09

by Javier Cardona

[permalink] [raw]
Subject: [PATCH v2 2/3] mac80211: Mesh data frames must have the QoS header

Per sec 7.1.3.5 of draft 12.0 of 802.11s, mesh frames indicate the
presence of the mesh control header in their QoS header.

Signed-off-by: Javier Cardona <[email protected]>
---
include/linux/ieee80211.h | 2 ++
net/mac80211/mesh.c | 3 +--
net/mac80211/mesh_pathtbl.c | 2 +-
net/mac80211/rx.c | 6 +++---
net/mac80211/tx.c | 2 +-
net/mac80211/wme.c | 10 ++++++----
net/mac80211/wme.h | 3 ++-
7 files changed, 16 insertions(+), 12 deletions(-)

diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 37f95f2..72f3933 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -130,6 +130,8 @@
#define IEEE80211_QOS_CTL_ACK_POLICY_BLOCKACK 0x0060
/* A-MSDU 802.11n */
#define IEEE80211_QOS_CTL_A_MSDU_PRESENT 0x0080
+/* Mesh Control 802.11s */
+#define IEEE80211_QOS_CTL_MESH_CONTROL_PRESENT 0x0100

/* U-APSD queue for WMM IEs sent by AP */
#define IEEE80211_WMM_IE_AP_QOSINFO_UAPSD (1<<7)
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 28ab510..576ef7e 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -464,8 +464,7 @@ int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
memcpy(hdr->addr3, meshsa, ETH_ALEN);
return 24;
} else {
- *fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS |
- IEEE80211_FCTL_TODS);
+ *fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
/* RA TA DA SA */
memset(hdr->addr1, 0, ETH_ALEN); /* RA is resolved later */
memcpy(hdr->addr2, meshsa, ETH_ALEN);
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index b51fce6..8ac712b 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -223,7 +223,7 @@ void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta)
hdr = (struct ieee80211_hdr *) skb->data;
memcpy(hdr->addr1, sta->sta.addr, ETH_ALEN);
skb_set_queue_mapping(skb, ieee80211_select_queue(sdata, skb));
- ieee80211_set_qos_hdr(sdata->local, skb);
+ ieee80211_set_qos_hdr(sdata, skb);
__skb_queue_tail(&tmpq, skb);
}

diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 1146991..2c44b08 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1907,7 +1907,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
fwded_mcast);
skb_set_queue_mapping(fwd_skb,
ieee80211_select_queue(sdata, fwd_skb));
- ieee80211_set_qos_hdr(local, fwd_skb);
+ ieee80211_set_qos_hdr(sdata, fwd_skb);
} else {
int err;
/*
@@ -2569,12 +2569,12 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx)
CALL_RXH(ieee80211_rx_h_ps_poll)
CALL_RXH(ieee80211_rx_h_michael_mic_verify)
/* must be after MMIC verify so header is counted in MPDU mic */
- CALL_RXH(ieee80211_rx_h_remove_qos_control)
- CALL_RXH(ieee80211_rx_h_amsdu)
#ifdef CONFIG_MAC80211_MESH
if (ieee80211_vif_is_mesh(&rx->sdata->vif))
CALL_RXH(ieee80211_rx_h_mesh_fwding);
#endif
+ CALL_RXH(ieee80211_rx_h_remove_qos_control)
+ CALL_RXH(ieee80211_rx_h_amsdu)
CALL_RXH(ieee80211_rx_h_data)
CALL_RXH(ieee80211_rx_h_ctrl);
CALL_RXH(ieee80211_rx_h_mgmt_check)
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 4c567e1..e6fe16a 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1595,7 +1595,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
return;
}

- ieee80211_set_qos_hdr(local, skb);
+ ieee80211_set_qos_hdr(sdata, skb);
ieee80211_tx(sdata, skb, false);
rcu_read_unlock();
}
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
index a9fee2b..971004c 100644
--- a/net/mac80211/wme.c
+++ b/net/mac80211/wme.c
@@ -135,7 +135,8 @@ u16 ieee80211_downgrade_queue(struct ieee80211_local *local,
return ieee802_1d_to_ac[skb->priority];
}

-void ieee80211_set_qos_hdr(struct ieee80211_local *local, struct sk_buff *skb)
+void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb)
{
struct ieee80211_hdr *hdr = (void *)skb->data;

@@ -146,10 +147,11 @@ void ieee80211_set_qos_hdr(struct ieee80211_local *local, struct sk_buff *skb)

tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;

- if (unlikely(local->wifi_wme_noack_test))
+ if (unlikely(sdata->local->wifi_wme_noack_test))
ack_policy |= IEEE80211_QOS_CTL_ACK_POLICY_NOACK;
- /* qos header is 2 bytes, second reserved */
+ /* qos header is 2 bytes */
*p++ = ack_policy | tid;
- *p = 0;
+ *p = ieee80211_vif_is_mesh(&sdata->vif) ?
+ (IEEE80211_QOS_CTL_MESH_CONTROL_PRESENT >> 8) : 0;
}
}
diff --git a/net/mac80211/wme.h b/net/mac80211/wme.h
index faead6d..34e166f 100644
--- a/net/mac80211/wme.h
+++ b/net/mac80211/wme.h
@@ -17,7 +17,8 @@ extern const int ieee802_1d_to_ac[8];

u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb);
-void ieee80211_set_qos_hdr(struct ieee80211_local *local, struct sk_buff *skb);
+void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb);
u16 ieee80211_downgrade_queue(struct ieee80211_local *local,
struct sk_buff *skb);

--
1.7.6


2011-09-09 08:02:28

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH v2 1/3] mac80211: Start implementing QoS support for mesh interfaces

On Thu, 2011-09-08 at 09:17 -0700, Javier Cardona wrote:
> On Thu, Sep 8, 2011 at 12:01 AM, Johannes Berg
> <[email protected]> wrote:
> > On Wed, 2011-09-07 at 17:49 -0700, Javier Cardona wrote:
> >
> >> + /* For mesh, the use of the QoS header is mandatory */
> >> + if (ieee80211_vif_is_mesh(&sdata->vif))
> >> + sta_flags |= WLAN_STA_WME;
> >> +
> >
> > With patch 3, this piece seems unnecessary?
>
> At that point we don't know who the next hop peer will so the previous
> block (below) will not find an sta. Also, we want the QoS header in
> multicast frames. So I thought this might be the least intrusive way.
>
> >>>
> if (!is_multicast_ether_addr(hdr.addr1)) {
> rcu_read_lock();
> sta = sta_info_get(sdata, hdr.addr1);
> if (sta)
> sta_flags = get_sta_flags(sta);
> rcu_read_unlock();
> }
> >>>

Ok, yeah, that makes sense.

johannes


2011-09-08 00:50:10

by Javier Cardona

[permalink] [raw]
Subject: [PATCH v2 3/3] mac80211: Mark all mesh stations as QoS capable

Signed-off-by: Javier Cardona <[email protected]>
---
net/mac80211/mesh_plink.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 1a00d0f..4396906 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -88,7 +88,7 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
if (!sta)
return NULL;

- sta->flags = WLAN_STA_AUTHORIZED | WLAN_STA_AUTH;
+ sta->flags = WLAN_STA_AUTHORIZED | WLAN_STA_AUTH | WLAN_STA_WME;
sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
rate_control_rate_init(sta);

--
1.7.6


2011-09-08 23:33:10

by Javier Cardona

[permalink] [raw]
Subject: Re: [PATCH v2 1/3] mac80211: Start implementing QoS support for mesh interfaces

On Thu, Sep 8, 2011 at 12:01 AM, Johannes Berg
<[email protected]> wrote:
> On Wed, 2011-09-07 at 17:49 -0700, Javier Cardona wrote:
>
>> + ? ? /* For mesh, the use of the QoS header is mandatory */
>> + ? ? if (ieee80211_vif_is_mesh(&sdata->vif))
>> + ? ? ? ? ? ? sta_flags |= WLAN_STA_WME;
>> +
>
> With patch 3, this piece seems unnecessary?

At that point we don't know who the next hop peer will so the previous
block (below) will not find an sta. Also, we want the QoS header in
multicast frames. So I thought this might be the least intrusive way.

>>>
if (!is_multicast_ether_addr(hdr.addr1)) {
rcu_read_lock();
sta = sta_info_get(sdata, hdr.addr1);
if (sta)
sta_flags = get_sta_flags(sta);
rcu_read_unlock();
}
>>>

Javier

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

2011-09-08 00:50:08

by Javier Cardona

[permalink] [raw]
Subject: [PATCH v2 1/3] mac80211: Start implementing QoS support for mesh interfaces

In order to support QoS in mesh, we need to assign queue mapping only
after the next hop has been resolved, both for forwarded and locally
originated frames. Also, now that this is fixed, remove the XXX comment
in ieee80211_select_queue().

Also, V-Shy Ho reported that the queue mapping was not being applied to
the forwarded frame (fwd_skb instead of skb). Fixed that as well.

Signed-off-by: Javier Cardona <[email protected]>
---
net/mac80211/mesh_pathtbl.c | 4 ++++
net/mac80211/rx.c | 10 +++++-----
net/mac80211/tx.c | 4 ++++
net/mac80211/wme.c | 6 +-----
4 files changed, 14 insertions(+), 10 deletions(-)

diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index ede4f52..b51fce6 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -14,6 +14,7 @@
#include <linux/spinlock.h>
#include <linux/string.h>
#include <net/mac80211.h>
+#include "wme.h"
#include "ieee80211_i.h"
#include "mesh.h"

@@ -210,6 +211,7 @@ void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta)
struct ieee80211_hdr *hdr;
struct sk_buff_head tmpq;
unsigned long flags;
+ struct ieee80211_sub_if_data *sdata = mpath->sdata;

rcu_assign_pointer(mpath->next_hop, sta);

@@ -220,6 +222,8 @@ void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta)
while ((skb = __skb_dequeue(&mpath->frame_queue)) != NULL) {
hdr = (struct ieee80211_hdr *) skb->data;
memcpy(hdr->addr1, sta->sta.addr, ETH_ALEN);
+ skb_set_queue_mapping(skb, ieee80211_select_queue(sdata, skb));
+ ieee80211_set_qos_hdr(sdata->local, skb);
__skb_queue_tail(&tmpq, skb);
}

diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index f45fd2f..1146991 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1902,13 +1902,13 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
memset(info, 0, sizeof(*info));
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
info->control.vif = &rx->sdata->vif;
- skb_set_queue_mapping(skb,
- ieee80211_select_queue(rx->sdata, fwd_skb));
- ieee80211_set_qos_hdr(local, skb);
- if (is_multicast_ether_addr(fwd_hdr->addr1))
+ if (is_multicast_ether_addr(fwd_hdr->addr1)) {
IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
fwded_mcast);
- else {
+ skb_set_queue_mapping(fwd_skb,
+ ieee80211_select_queue(sdata, fwd_skb));
+ ieee80211_set_qos_hdr(local, fwd_skb);
+ } else {
int err;
/*
* Save TA to addr1 to send TA a path error if a
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 0107263..4c567e1 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1878,6 +1878,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
rcu_read_unlock();
}

+ /* For mesh, the use of the QoS header is mandatory */
+ if (ieee80211_vif_is_mesh(&sdata->vif))
+ sta_flags |= WLAN_STA_WME;
+
/* receiver and we are QoS enabled, use a QoS type frame */
if ((sta_flags & WLAN_STA_WME) && local->hw.queues >= 4) {
fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
index 7a49532..a9fee2b 100644
--- a/net/mac80211/wme.c
+++ b/net/mac80211/wme.c
@@ -83,11 +83,7 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
break;
#ifdef CONFIG_MAC80211_MESH
case NL80211_IFTYPE_MESH_POINT:
- /*
- * XXX: This is clearly broken ... but already was before,
- * because ieee80211_fill_mesh_addresses() would clear A1
- * except for multicast addresses.
- */
+ ra = skb->data;
break;
#endif
case NL80211_IFTYPE_STATION:
--
1.7.6


2011-09-08 07:01:57

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH v2 1/3] mac80211: Start implementing QoS support for mesh interfaces

On Wed, 2011-09-07 at 17:49 -0700, Javier Cardona wrote:

> + /* For mesh, the use of the QoS header is mandatory */
> + if (ieee80211_vif_is_mesh(&sdata->vif))
> + sta_flags |= WLAN_STA_WME;
> +

With patch 3, this piece seems unnecessary?

johannes