Hook the evaluator into ieee80211_select_queue(), which every data transmit path of an AP reaches, including 802.11 encapsulation offload and the unicast copies of a multicast frame. The TID it produces selects the TXQ, the AC and the block ack session, so the classification has to run before the frame is queued. It runs before cfg80211_classify8021d(), which preserves the priority that a frame already carries. A frame forwarded between two stations of the same AP carries its received TID that way and has to be classified like any other MSDU. The hook is limited to AP and AP_VLAN interfaces, because only the AP side classifies downlink MSDUs. Signed-off-by: Felix Fietkau --- net/mac80211/ieee80211_i.h | 1 + net/mac80211/scs.c | 31 +++++++++++++++++++++++++++++++ net/mac80211/wme.c | 7 +++++++ 3 files changed, 39 insertions(+) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index ff4b17f2d7b6..47d703688478 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2221,6 +2221,7 @@ int ieee80211_set_scs(struct wiphy *wiphy, struct net_device *dev, int ieee80211_set_mscs(struct wiphy *wiphy, struct net_device *dev, const u8 *peer, struct cfg80211_mscs_desc *desc); void ieee80211_sta_scs_free(struct sta_info *sta); +bool ieee80211_flow_classify(struct sta_info *sta, struct sk_buff *skb); /* link handling */ void ieee80211_link_setup(struct ieee80211_link_data *link); diff --git a/net/mac80211/scs.c b/net/mac80211/scs.c index b8e9fe062ff5..89982e1f4b89 100644 --- a/net/mac80211/scs.c +++ b/net/mac80211/scs.c @@ -84,6 +84,37 @@ ieee80211_scs_sta_build(struct cfg80211_scs_desc * const *rule, u8 n_rules) return scs; } +/** + * ieee80211_flow_classify - give an MSDU the user priority of its stream + * + * @sta: the receiver + * @skb: the MSDU, in IEEE 802.3 format + * + * Return: %true when it set skb->priority, %false to leave the frame to the + * QoS map. + */ +bool ieee80211_flow_classify(struct sta_info *sta, struct sk_buff *skb) +{ + struct cfg80211_scs_verdict verdict; + struct cfg80211_flow_info info; + struct ieee80211_scs_sta *scs; + + scs = rcu_dereference(sta->scs); + if (!scs) + return false; + + if (!cfg80211_flow_parse(skb, &info)) + return false; + + cfg80211_scs_evaluate(scs->rule, scs->n_rules, &info, &verdict); + if (!verdict.match) + return false; + + skb->priority = verdict.up; + + return true; +} + int ieee80211_set_scs(struct wiphy *wiphy, struct net_device *dev, const u8 *peer, struct cfg80211_scs_desc * const *desc, struct cfg80211_scs_result *res, u8 n_desc) diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 1601be576414..9fcee1bc6ad5 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -174,6 +174,13 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, goto downgrade; } + /* A stream priority overrides the received one of a forwarded frame */ + if (sta && + (sdata->vif.type == NL80211_IFTYPE_AP || + sdata->vif.type == NL80211_IFTYPE_AP_VLAN) && + ieee80211_flow_classify(sta, skb)) + goto downgrade; + /* use the data classifier to determine what 802.1d tag the * data frame has */ qos_map = rcu_dereference(sdata->qos_map); -- git-series 0.9.1