From 02219b3abca59fca81711bfe7ee78df7abad97ce Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 7 Oct 2014 10:38:50 +0300 Subject: mac80211: add WMM admission control support Use the currently existing APIs between mac80211 and the low level driver to implement WMM admission control. The low level driver needs to report the media time used by each transmitted packet in ieee80211_tx_status. Based on that information, mac80211 will modify the QoS parameters of the admission controlled Access Category when the limit is reached. Once the original QoS parameters can be restored, mac80211 will do so. One issue with this approach is that management frames will also erroneously be downgraded, but the upside is that the implementation is simple. In the future, it can be extended to driver- or device-based implementations that are better. Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- net/mac80211/wme.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) (limited to 'net/mac80211/wme.c') diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 3b873989992c..d3c5672d775f 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -54,10 +54,18 @@ static int wme_downgrade_ac(struct sk_buff *skb) } static u16 ieee80211_downgrade_queue(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb) + struct sta_info *sta, struct sk_buff *skb) { + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + /* in case we are a client verify acm is not set for this ac */ - while (unlikely(sdata->wmm_acm & BIT(skb->priority))) { + while (sdata->wmm_acm & BIT(skb->priority)) { + int ac = ieee802_1d_to_ac[skb->priority]; + + if (ifmgd->tx_tspec[ac].admitted_time && + skb->priority == ifmgd->tx_tspec[ac].up) + return ac; + if (wme_downgrade_ac(skb)) { /* * This should not really happen. The AP has marked all @@ -96,7 +104,7 @@ u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata, p = ieee80211_get_qos_ctl(hdr); skb->priority = *p & IEEE80211_QOS_CTL_TAG1D_MASK; - return ieee80211_downgrade_queue(sdata, skb); + return ieee80211_downgrade_queue(sdata, NULL, skb); } /* Indicate which queue to use. */ @@ -108,6 +116,7 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, const u8 *ra = NULL; bool qos = false; struct mac80211_qos_map *qos_map; + u16 ret; if (local->hw.queues < IEEE80211_NUM_ACS || skb->len < 6) { skb->priority = 0; /* required for correct WPA/11i MIC */ @@ -148,27 +157,29 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, if (sta) qos = sta->sta.wme; } - rcu_read_unlock(); if (!qos) { skb->priority = 0; /* required for correct WPA/11i MIC */ - return IEEE80211_AC_BE; + ret = IEEE80211_AC_BE; + goto out; } if (skb->protocol == sdata->control_port_protocol) { skb->priority = 7; - return ieee80211_downgrade_queue(sdata, skb); + goto downgrade; } /* use the data classifier to determine what 802.1d tag the * data frame has */ - rcu_read_lock(); qos_map = rcu_dereference(sdata->qos_map); skb->priority = cfg80211_classify8021d(skb, qos_map ? &qos_map->qos_map : NULL); - rcu_read_unlock(); - return ieee80211_downgrade_queue(sdata, skb); + downgrade: + ret = ieee80211_downgrade_queue(sdata, sta, skb); + out: + rcu_read_unlock(); + return ret; } /** -- cgit v1.2.3-59-g8ed1b