summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2014-10-07 03:38:50 -0400
committerJohannes Berg <johannes.berg@intel.com>2014-10-22 04:42:09 -0400
commit02219b3abca59fca81711bfe7ee78df7abad97ce (patch)
treeafaa7b17ffde140c2791a87c9dde1a489a949f36
parentf409079bb678600be0201cd03afb4731f0480b4e (diff)
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 <emmanuel.grumbach@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--include/net/mac80211.h3
-rw-r--r--net/mac80211/agg-tx.c5
-rw-r--r--net/mac80211/cfg.c73
-rw-r--r--net/mac80211/ieee80211_i.h38
-rw-r--r--net/mac80211/mlme.c142
-rw-r--r--net/mac80211/status.c3
-rw-r--r--net/mac80211/wme.c29
-rw-r--r--net/mac80211/wme.h2
8 files changed, 272 insertions, 23 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 9bb2fc73aeaa..9dc5e7606322 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -739,7 +739,8 @@ struct ieee80211_tx_info {
739 u8 ampdu_ack_len; 739 u8 ampdu_ack_len;
740 u8 ampdu_len; 740 u8 ampdu_len;
741 u8 antenna; 741 u8 antenna;
742 void *status_driver_data[21 / sizeof(void *)]; 742 u16 tx_time;
743 void *status_driver_data[19 / sizeof(void *)];
743 } status; 744 } status;
744 struct { 745 struct {
745 struct ieee80211_tx_rate driver_rates[ 746 struct ieee80211_tx_rate driver_rates[
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index d6986f3aa5c4..9242c60048cf 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -149,11 +149,6 @@ void ieee80211_assign_tid_tx(struct sta_info *sta, int tid,
149 rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx); 149 rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx);
150} 150}
151 151
152static inline int ieee80211_ac_from_tid(int tid)
153{
154 return ieee802_1d_to_ac[tid & 7];
155}
156
157/* 152/*
158 * When multiple aggregation sessions on multiple stations 153 * When multiple aggregation sessions on multiple stations
159 * are being created/destroyed simultaneously, we need to 154 * are being created/destroyed simultaneously, we need to
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 64deb9aa0f81..d6b01ad2f7d7 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -20,6 +20,7 @@
20#include "cfg.h" 20#include "cfg.h"
21#include "rate.h" 21#include "rate.h"
22#include "mesh.h" 22#include "mesh.h"
23#include "wme.h"
23 24
24static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy, 25static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy,
25 const char *name, 26 const char *name,
@@ -3585,6 +3586,76 @@ static int ieee80211_set_ap_chanwidth(struct wiphy *wiphy,
3585 return ret; 3586 return ret;
3586} 3587}
3587 3588
3589static int ieee80211_add_tx_ts(struct wiphy *wiphy, struct net_device *dev,
3590 u8 tsid, const u8 *peer, u8 up,
3591 u16 admitted_time)
3592{
3593 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
3594 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
3595 int ac = ieee802_1d_to_ac[up];
3596
3597 if (sdata->vif.type != NL80211_IFTYPE_STATION)
3598 return -EOPNOTSUPP;
3599
3600 if (!(sdata->wmm_acm & BIT(up)))
3601 return -EINVAL;
3602
3603 if (ifmgd->tx_tspec[ac].admitted_time)
3604 return -EBUSY;
3605
3606 if (admitted_time) {
3607 ifmgd->tx_tspec[ac].admitted_time = 32 * admitted_time;
3608 ifmgd->tx_tspec[ac].tsid = tsid;
3609 ifmgd->tx_tspec[ac].up = up;
3610 }
3611
3612 return 0;
3613}
3614
3615static int ieee80211_del_tx_ts(struct wiphy *wiphy, struct net_device *dev,
3616 u8 tsid, const u8 *peer)
3617{
3618 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
3619 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
3620 struct ieee80211_local *local = wiphy_priv(wiphy);
3621 int ac;
3622
3623 for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
3624 struct ieee80211_sta_tx_tspec *tx_tspec = &ifmgd->tx_tspec[ac];
3625
3626 /* skip unused entries */
3627 if (!tx_tspec->admitted_time)
3628 continue;
3629
3630 if (tx_tspec->tsid != tsid)
3631 continue;
3632
3633 /* due to this new packets will be reassigned to non-ACM ACs */
3634 tx_tspec->up = -1;
3635
3636 /* Make sure that all packets have been sent to avoid to
3637 * restore the QoS params on packets that are still on the
3638 * queues.
3639 */
3640 synchronize_net();
3641 ieee80211_flush_queues(local, sdata);
3642
3643 /* restore the normal QoS parameters
3644 * (unconditionally to avoid races)
3645 */
3646 tx_tspec->action = TX_TSPEC_ACTION_STOP_DOWNGRADE;
3647 tx_tspec->downgraded = false;
3648 ieee80211_sta_handle_tspec_ac_params(sdata);
3649
3650 /* finally clear all the data */
3651 memset(tx_tspec, 0, sizeof(*tx_tspec));
3652
3653 return 0;
3654 }
3655
3656 return -ENOENT;
3657}
3658
3588const struct cfg80211_ops mac80211_config_ops = { 3659const struct cfg80211_ops mac80211_config_ops = {
3589 .add_virtual_intf = ieee80211_add_iface, 3660 .add_virtual_intf = ieee80211_add_iface,
3590 .del_virtual_intf = ieee80211_del_iface, 3661 .del_virtual_intf = ieee80211_del_iface,
@@ -3663,4 +3734,6 @@ const struct cfg80211_ops mac80211_config_ops = {
3663 .channel_switch = ieee80211_channel_switch, 3734 .channel_switch = ieee80211_channel_switch,
3664 .set_qos_map = ieee80211_set_qos_map, 3735 .set_qos_map = ieee80211_set_qos_map,
3665 .set_ap_chanwidth = ieee80211_set_ap_chanwidth, 3736 .set_ap_chanwidth = ieee80211_set_ap_chanwidth,
3737 .add_tx_ts = ieee80211_add_tx_ts,
3738 .del_tx_ts = ieee80211_del_tx_ts,
3666}; 3739};
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 78d6121eb372..60063be057d0 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -399,6 +399,24 @@ struct ieee80211_mgd_assoc_data {
399 u8 ie[]; 399 u8 ie[];
400}; 400};
401 401
402struct ieee80211_sta_tx_tspec {
403 /* timestamp of the first packet in the time slice */
404 unsigned long time_slice_start;
405
406 u32 admitted_time; /* in usecs, unlike over the air */
407 u8 tsid;
408 s8 up; /* signed to be able to invalidate with -1 during teardown */
409
410 /* consumed TX time in microseconds in the time slice */
411 u32 consumed_tx_time;
412 enum {
413 TX_TSPEC_ACTION_NONE = 0,
414 TX_TSPEC_ACTION_DOWNGRADE,
415 TX_TSPEC_ACTION_STOP_DOWNGRADE,
416 } action;
417 bool downgraded;
418};
419
402struct ieee80211_if_managed { 420struct ieee80211_if_managed {
403 struct timer_list timer; 421 struct timer_list timer;
404 struct timer_list conn_mon_timer; 422 struct timer_list conn_mon_timer;
@@ -509,6 +527,16 @@ struct ieee80211_if_managed {
509 527
510 u8 tdls_peer[ETH_ALEN] __aligned(2); 528 u8 tdls_peer[ETH_ALEN] __aligned(2);
511 struct delayed_work tdls_peer_del_work; 529 struct delayed_work tdls_peer_del_work;
530
531 /* WMM-AC TSPEC support */
532 struct ieee80211_sta_tx_tspec tx_tspec[IEEE80211_NUM_ACS];
533 /* Use a separate work struct so that we can do something here
534 * while the sdata->work is flushing the queues, for example.
535 * otherwise, in scenarios where we hardly get any traffic out
536 * on the BE queue, but there's a lot of VO traffic, we might
537 * get stuck in a downgraded situation and flush takes forever.
538 */
539 struct delayed_work tx_tspec_wk;
512}; 540};
513 541
514struct ieee80211_if_ibss { 542struct ieee80211_if_ibss {
@@ -1459,6 +1487,7 @@ void ieee80211_mgd_conn_tx_status(struct ieee80211_sub_if_data *sdata,
1459 __le16 fc, bool acked); 1487 __le16 fc, bool acked);
1460void ieee80211_mgd_quiesce(struct ieee80211_sub_if_data *sdata); 1488void ieee80211_mgd_quiesce(struct ieee80211_sub_if_data *sdata);
1461void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata); 1489void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata);
1490void ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata);
1462 1491
1463/* IBSS code */ 1492/* IBSS code */
1464void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local); 1493void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local);
@@ -1763,6 +1792,13 @@ static inline bool ieee80211_rx_reorder_ready(struct sk_buff_head *frames)
1763 return true; 1792 return true;
1764} 1793}
1765 1794
1795extern const int ieee802_1d_to_ac[8];
1796
1797static inline int ieee80211_ac_from_tid(int tid)
1798{
1799 return ieee802_1d_to_ac[tid & 7];
1800}
1801
1766void ieee80211_dynamic_ps_enable_work(struct work_struct *work); 1802void ieee80211_dynamic_ps_enable_work(struct work_struct *work);
1767void ieee80211_dynamic_ps_disable_work(struct work_struct *work); 1803void ieee80211_dynamic_ps_disable_work(struct work_struct *work);
1768void ieee80211_dynamic_ps_timer(unsigned long data); 1804void ieee80211_dynamic_ps_timer(unsigned long data);
@@ -1772,7 +1808,7 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local,
1772void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, 1808void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
1773 struct ieee80211_hdr *hdr); 1809 struct ieee80211_hdr *hdr);
1774void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, 1810void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata,
1775 struct ieee80211_hdr *hdr, bool ack); 1811 struct ieee80211_hdr *hdr, bool ack, u16 tx_time);
1776 1812
1777void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, 1813void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
1778 unsigned long queues, 1814 unsigned long queues,
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index fb6561509caf..4d9b4d165ce8 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1606,6 +1606,95 @@ void ieee80211_dfs_cac_timer_work(struct work_struct *work)
1606 mutex_unlock(&sdata->local->mtx); 1606 mutex_unlock(&sdata->local->mtx);
1607} 1607}
1608 1608
1609static bool
1610__ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata)
1611{
1612 struct ieee80211_local *local = sdata->local;
1613 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
1614 bool ret;
1615 int ac;
1616
1617 if (local->hw.queues < IEEE80211_NUM_ACS)
1618 return false;
1619
1620 for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
1621 struct ieee80211_sta_tx_tspec *tx_tspec = &ifmgd->tx_tspec[ac];
1622 int non_acm_ac;
1623 unsigned long now = jiffies;
1624
1625 if (tx_tspec->action == TX_TSPEC_ACTION_NONE &&
1626 tx_tspec->admitted_time &&
1627 time_after(now, tx_tspec->time_slice_start + HZ)) {
1628 tx_tspec->consumed_tx_time = 0;
1629 tx_tspec->time_slice_start = now;
1630
1631 if (tx_tspec->downgraded)
1632 tx_tspec->action =
1633 TX_TSPEC_ACTION_STOP_DOWNGRADE;
1634 }
1635
1636 switch (tx_tspec->action) {
1637 case TX_TSPEC_ACTION_STOP_DOWNGRADE:
1638 /* take the original parameters */
1639 if (drv_conf_tx(local, sdata, ac, &sdata->tx_conf[ac]))
1640 sdata_err(sdata,
1641 "failed to set TX queue parameters for queue %d\n",
1642 ac);
1643 tx_tspec->action = TX_TSPEC_ACTION_NONE;
1644 tx_tspec->downgraded = false;
1645 ret = true;
1646 break;
1647 case TX_TSPEC_ACTION_DOWNGRADE:
1648 if (time_after(now, tx_tspec->time_slice_start + HZ)) {
1649 tx_tspec->action = TX_TSPEC_ACTION_NONE;
1650 ret = true;
1651 break;
1652 }
1653 /* downgrade next lower non-ACM AC */
1654 for (non_acm_ac = ac + 1;
1655 non_acm_ac < IEEE80211_NUM_ACS;
1656 non_acm_ac++)
1657 if (!(sdata->wmm_acm & BIT(7 - 2 * non_acm_ac)))
1658 break;
1659 /* The loop will result in using BK even if it requires
1660 * admission control, such configuration makes no sense
1661 * and we have to transmit somehow - the AC selection
1662 * does the same thing.
1663 */
1664 if (drv_conf_tx(local, sdata, ac,
1665 &sdata->tx_conf[non_acm_ac]))
1666 sdata_err(sdata,
1667 "failed to set TX queue parameters for queue %d\n",
1668 ac);
1669 tx_tspec->action = TX_TSPEC_ACTION_NONE;
1670 ret = true;
1671 schedule_delayed_work(&ifmgd->tx_tspec_wk,
1672 tx_tspec->time_slice_start + HZ - now + 1);
1673 break;
1674 case TX_TSPEC_ACTION_NONE:
1675 /* nothing now */
1676 break;
1677 }
1678 }
1679
1680 return ret;
1681}
1682
1683void ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata)
1684{
1685 if (__ieee80211_sta_handle_tspec_ac_params(sdata))
1686 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS);
1687}
1688
1689static void ieee80211_sta_handle_tspec_ac_params_wk(struct work_struct *work)
1690{
1691 struct ieee80211_sub_if_data *sdata;
1692
1693 sdata = container_of(work, struct ieee80211_sub_if_data,
1694 u.mgd.tx_tspec_wk.work);
1695 ieee80211_sta_handle_tspec_ac_params(sdata);
1696}
1697
1609/* MLME */ 1698/* MLME */
1610static bool ieee80211_sta_wmm_params(struct ieee80211_local *local, 1699static bool ieee80211_sta_wmm_params(struct ieee80211_local *local,
1611 struct ieee80211_sub_if_data *sdata, 1700 struct ieee80211_sub_if_data *sdata,
@@ -1690,12 +1779,14 @@ static bool ieee80211_sta_wmm_params(struct ieee80211_local *local,
1690 params.uapsd = uapsd; 1779 params.uapsd = uapsd;
1691 1780
1692 mlme_dbg(sdata, 1781 mlme_dbg(sdata,
1693 "WMM queue=%d aci=%d acm=%d aifs=%d cWmin=%d cWmax=%d txop=%d uapsd=%d\n", 1782 "WMM queue=%d aci=%d acm=%d aifs=%d cWmin=%d cWmax=%d txop=%d uapsd=%d, downgraded=%d\n",
1694 queue, aci, acm, 1783 queue, aci, acm,
1695 params.aifs, params.cw_min, params.cw_max, 1784 params.aifs, params.cw_min, params.cw_max,
1696 params.txop, params.uapsd); 1785 params.txop, params.uapsd,
1786 ifmgd->tx_tspec[queue].downgraded);
1697 sdata->tx_conf[queue] = params; 1787 sdata->tx_conf[queue] = params;
1698 if (drv_conf_tx(local, sdata, queue, &params)) 1788 if (!ifmgd->tx_tspec[queue].downgraded &&
1789 drv_conf_tx(local, sdata, queue, &params))
1699 sdata_err(sdata, 1790 sdata_err(sdata,
1700 "failed to set TX queue parameters for queue %d\n", 1791 "failed to set TX queue parameters for queue %d\n",
1701 queue); 1792 queue);
@@ -1958,6 +2049,10 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
1958 } 2049 }
1959 mutex_unlock(&local->mtx); 2050 mutex_unlock(&local->mtx);
1960 2051
2052 /* existing TX TSPEC sessions no longer exist */
2053 memset(ifmgd->tx_tspec, 0, sizeof(ifmgd->tx_tspec));
2054 cancel_delayed_work_sync(&ifmgd->tx_tspec_wk);
2055
1961 sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; 2056 sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;
1962} 2057}
1963 2058
@@ -2010,9 +2105,46 @@ out:
2010 mutex_unlock(&local->mtx); 2105 mutex_unlock(&local->mtx);
2011} 2106}
2012 2107
2108static void ieee80211_sta_tx_wmm_ac_notify(struct ieee80211_sub_if_data *sdata,
2109 struct ieee80211_hdr *hdr,
2110 u16 tx_time)
2111{
2112 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
2113 u16 tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
2114 int ac = ieee80211_ac_from_tid(tid);
2115 struct ieee80211_sta_tx_tspec *tx_tspec = &ifmgd->tx_tspec[ac];
2116 unsigned long now = jiffies;
2117
2118 if (likely(!tx_tspec->admitted_time))
2119 return;
2120
2121 if (time_after(now, tx_tspec->time_slice_start + HZ)) {
2122 tx_tspec->consumed_tx_time = 0;
2123 tx_tspec->time_slice_start = now;
2124
2125 if (tx_tspec->downgraded) {
2126 tx_tspec->action = TX_TSPEC_ACTION_STOP_DOWNGRADE;
2127 schedule_delayed_work(&ifmgd->tx_tspec_wk, 0);
2128 }
2129 }
2130
2131 if (tx_tspec->downgraded)
2132 return;
2133
2134 tx_tspec->consumed_tx_time += tx_time;
2135
2136 if (tx_tspec->consumed_tx_time >= tx_tspec->admitted_time) {
2137 tx_tspec->downgraded = true;
2138 tx_tspec->action = TX_TSPEC_ACTION_DOWNGRADE;
2139 schedule_delayed_work(&ifmgd->tx_tspec_wk, 0);
2140 }
2141}
2142
2013void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, 2143void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata,
2014 struct ieee80211_hdr *hdr, bool ack) 2144 struct ieee80211_hdr *hdr, bool ack, u16 tx_time)
2015{ 2145{
2146 ieee80211_sta_tx_wmm_ac_notify(sdata, hdr, tx_time);
2147
2016 if (!ieee80211_is_data(hdr->frame_control)) 2148 if (!ieee80211_is_data(hdr->frame_control))
2017 return; 2149 return;
2018 2150
@@ -3834,6 +3966,8 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
3834 (unsigned long) sdata); 3966 (unsigned long) sdata);
3835 setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer, 3967 setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer,
3836 (unsigned long) sdata); 3968 (unsigned long) sdata);
3969 INIT_DELAYED_WORK(&ifmgd->tx_tspec_wk,
3970 ieee80211_sta_handle_tspec_ac_params_wk);
3837 3971
3838 ifmgd->flags = 0; 3972 ifmgd->flags = 0;
3839 ifmgd->powersave = sdata->wdev.ps; 3973 ifmgd->powersave = sdata->wdev.ps;
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 89290e33dafe..9612d89fad56 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -704,7 +704,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
704 704
705 if ((sta->sdata->vif.type == NL80211_IFTYPE_STATION) && 705 if ((sta->sdata->vif.type == NL80211_IFTYPE_STATION) &&
706 (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)) 706 (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS))
707 ieee80211_sta_tx_notify(sta->sdata, (void *) skb->data, acked); 707 ieee80211_sta_tx_notify(sta->sdata, (void *) skb->data,
708 acked, info->status.tx_time);
708 709
709 if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) { 710 if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) {
710 if (info->flags & IEEE80211_TX_STAT_ACK) { 711 if (info->flags & IEEE80211_TX_STAT_ACK) {
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)
54} 54}
55 55
56static u16 ieee80211_downgrade_queue(struct ieee80211_sub_if_data *sdata, 56static u16 ieee80211_downgrade_queue(struct ieee80211_sub_if_data *sdata,
57 struct sk_buff *skb) 57 struct sta_info *sta, struct sk_buff *skb)
58{ 58{
59 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
60
59 /* in case we are a client verify acm is not set for this ac */ 61 /* in case we are a client verify acm is not set for this ac */
60 while (unlikely(sdata->wmm_acm & BIT(skb->priority))) { 62 while (sdata->wmm_acm & BIT(skb->priority)) {
63 int ac = ieee802_1d_to_ac[skb->priority];
64
65 if (ifmgd->tx_tspec[ac].admitted_time &&
66 skb->priority == ifmgd->tx_tspec[ac].up)
67 return ac;
68
61 if (wme_downgrade_ac(skb)) { 69 if (wme_downgrade_ac(skb)) {
62 /* 70 /*
63 * This should not really happen. The AP has marked all 71 * 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,
96 p = ieee80211_get_qos_ctl(hdr); 104 p = ieee80211_get_qos_ctl(hdr);
97 skb->priority = *p & IEEE80211_QOS_CTL_TAG1D_MASK; 105 skb->priority = *p & IEEE80211_QOS_CTL_TAG1D_MASK;
98 106
99 return ieee80211_downgrade_queue(sdata, skb); 107 return ieee80211_downgrade_queue(sdata, NULL, skb);
100} 108}
101 109
102/* Indicate which queue to use. */ 110/* Indicate which queue to use. */
@@ -108,6 +116,7 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
108 const u8 *ra = NULL; 116 const u8 *ra = NULL;
109 bool qos = false; 117 bool qos = false;
110 struct mac80211_qos_map *qos_map; 118 struct mac80211_qos_map *qos_map;
119 u16 ret;
111 120
112 if (local->hw.queues < IEEE80211_NUM_ACS || skb->len < 6) { 121 if (local->hw.queues < IEEE80211_NUM_ACS || skb->len < 6) {
113 skb->priority = 0; /* required for correct WPA/11i MIC */ 122 skb->priority = 0; /* required for correct WPA/11i MIC */
@@ -148,27 +157,29 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
148 if (sta) 157 if (sta)
149 qos = sta->sta.wme; 158 qos = sta->sta.wme;
150 } 159 }
151 rcu_read_unlock();
152 160
153 if (!qos) { 161 if (!qos) {
154 skb->priority = 0; /* required for correct WPA/11i MIC */ 162 skb->priority = 0; /* required for correct WPA/11i MIC */
155 return IEEE80211_AC_BE; 163 ret = IEEE80211_AC_BE;
164 goto out;
156 } 165 }
157 166
158 if (skb->protocol == sdata->control_port_protocol) { 167 if (skb->protocol == sdata->control_port_protocol) {
159 skb->priority = 7; 168 skb->priority = 7;
160 return ieee80211_downgrade_queue(sdata, skb); 169 goto downgrade;
161 } 170 }
162 171
163 /* use the data classifier to determine what 802.1d tag the 172 /* use the data classifier to determine what 802.1d tag the
164 * data frame has */ 173 * data frame has */
165 rcu_read_lock();
166 qos_map = rcu_dereference(sdata->qos_map); 174 qos_map = rcu_dereference(sdata->qos_map);
167 skb->priority = cfg80211_classify8021d(skb, qos_map ? 175 skb->priority = cfg80211_classify8021d(skb, qos_map ?
168 &qos_map->qos_map : NULL); 176 &qos_map->qos_map : NULL);
169 rcu_read_unlock();
170 177
171 return ieee80211_downgrade_queue(sdata, skb); 178 downgrade:
179 ret = ieee80211_downgrade_queue(sdata, sta, skb);
180 out:
181 rcu_read_unlock();
182 return ret;
172} 183}
173 184
174/** 185/**
diff --git a/net/mac80211/wme.h b/net/mac80211/wme.h
index 7fea4bb8acbc..80151edc5195 100644
--- a/net/mac80211/wme.h
+++ b/net/mac80211/wme.h
@@ -13,8 +13,6 @@
13#include <linux/netdevice.h> 13#include <linux/netdevice.h>
14#include "ieee80211_i.h" 14#include "ieee80211_i.h"
15 15
16extern const int ieee802_1d_to_ac[8];
17
18u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata, 16u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata,
19 struct sk_buff *skb, 17 struct sk_buff *skb,
20 struct ieee80211_hdr *hdr); 18 struct ieee80211_hdr *hdr);