--- /dev/null
+From: Markus Theil <markus.theil@tu-ilmenau.de>
+Date: Sat, 6 Feb 2021 12:51:12 +0100
+Subject: [PATCH] mac80211: enable QoS support for nl80211 ctrl port
+
+This patch unifies sending control port frames
+over nl80211 and AF_PACKET sockets a little more.
+
+Before this patch, EAPOL frames got QoS prioritization
+only when using AF_PACKET sockets.
+
+__ieee80211_select_queue only selects a QoS-enabled queue
+for control port frames, when the control port protocol
+is set correctly on the skb. For the AF_PACKET path this
+works, but the nl80211 path used ETH_P_802_3.
+
+Another check for injected frames in wme.c then prevented
+the QoS TID to be copied in the frame.
+
+In order to fix this, get rid of the frame injection marking
+for nl80211 ctrl port and set the correct ethernet protocol.
+
+Please note:
+An erlier version of this path tried to prevent
+frame aggregation for control port frames in order to speed up
+the initial connection setup a little. This seemed to cause
+issues on my older Intel dvm-based hardware, and was therefore
+removed again. Future commits which try to reintroduce this
+have to check carefully how hw behaves with aggregated and
+non-aggregated traffic for the same TID.
+My NIC: Intel(R) Centrino(R) Ultimate-N 6300 AGN, REV=0x74
+
+Reported-by: kernel test robot <lkp@intel.com>
+Signed-off-by: Markus Theil <markus.theil@tu-ilmenau.de>
+Link: https://lore.kernel.org/r/20210206115112.567881-1-markus.theil@tu-ilmenau.de
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+
+--- a/net/mac80211/status.c
++++ b/net/mac80211/status.c
+@@ -628,16 +628,12 @@ static void ieee80211_report_ack_skb(str
+ u64 cookie = IEEE80211_SKB_CB(skb)->ack.cookie;
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_hdr *hdr = (void *)skb->data;
+- __be16 ethertype = 0;
+-
+- if (skb->len >= ETH_HLEN && skb->protocol == cpu_to_be16(ETH_P_802_3))
+- skb_copy_bits(skb, 2 * ETH_ALEN, ðertype, ETH_TLEN);
+
+ rcu_read_lock();
+ sdata = ieee80211_sdata_from_skb(local, skb);
+ if (sdata) {
+- if (ethertype == sdata->control_port_protocol ||
+- ethertype == cpu_to_be16(ETH_P_PREAUTH))
++ if (skb->protocol == sdata->control_port_protocol ||
++ skb->protocol == cpu_to_be16(ETH_P_PREAUTH))
+ cfg80211_control_port_tx_status(&sdata->wdev,
+ cookie,
+ skb->data,
+--- a/net/mac80211/tx.c
++++ b/net/mac80211/tx.c
+@@ -1195,9 +1195,7 @@ ieee80211_tx_prepare(struct ieee80211_su
+ tx->sta = rcu_dereference(sdata->u.vlan.sta);
+ if (!tx->sta && sdata->wdev.use_4addr)
+ return TX_DROP;
+- } else if (info->flags & (IEEE80211_TX_INTFL_NL80211_FRAME_TX |
+- IEEE80211_TX_CTL_INJECTED) ||
+- tx->sdata->control_port_protocol == tx->skb->protocol) {
++ } else if (tx->sdata->control_port_protocol == tx->skb->protocol) {
+ tx->sta = sta_info_get_bss(sdata, hdr->addr1);
+ }
+ if (!tx->sta && !is_multicast_ether_addr(hdr->addr1))
+@@ -5421,6 +5419,7 @@ int ieee80211_tx_control_port(struct wip
+ {
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_local *local = sdata->local;
++ struct sta_info *sta;
+ struct sk_buff *skb;
+ struct ethhdr *ehdr;
+ u32 ctrl_flags = 0;
+@@ -5443,8 +5442,7 @@ int ieee80211_tx_control_port(struct wip
+ if (cookie)
+ ctrl_flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
+
+- flags |= IEEE80211_TX_INTFL_NL80211_FRAME_TX |
+- IEEE80211_TX_CTL_INJECTED;
++ flags |= IEEE80211_TX_INTFL_NL80211_FRAME_TX;
+
+ skb = dev_alloc_skb(local->hw.extra_tx_headroom +
+ sizeof(struct ethhdr) + len);
+@@ -5461,10 +5459,25 @@ int ieee80211_tx_control_port(struct wip
+ ehdr->h_proto = proto;
+
+ skb->dev = dev;
+- skb->protocol = htons(ETH_P_802_3);
++ skb->protocol = proto;
+ skb_reset_network_header(skb);
+ skb_reset_mac_header(skb);
+
++ /* update QoS header to prioritize control port frames if possible,
++ * priorization also happens for control port frames send over
++ * AF_PACKET
++ */
++ rcu_read_lock();
++
++ if (ieee80211_lookup_ra_sta(sdata, skb, &sta) == 0 && !IS_ERR(sta)) {
++ u16 queue = __ieee80211_select_queue(sdata, sta, skb);
++
++ skb_set_queue_mapping(skb, queue);
++ skb_get_hash(skb);
++ }
++
++ rcu_read_unlock();
++
+ /* mutex lock is only needed for incrementing the cookie counter */
+ mutex_lock(&local->mtx);
+
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
-@@ -1780,8 +1780,6 @@ static int invoke_tx_handlers_early(stru
+@@ -1778,8 +1778,6 @@ static int invoke_tx_handlers_early(stru
CALL_TXH(ieee80211_tx_h_ps_buf);
CALL_TXH(ieee80211_tx_h_check_control_port_protocol);
CALL_TXH(ieee80211_tx_h_select_key);
txh_done:
if (unlikely(res == TX_DROP)) {
-@@ -1814,6 +1812,9 @@ static int invoke_tx_handlers_late(struc
+@@ -1812,6 +1810,9 @@ static int invoke_tx_handlers_late(struc
goto txh_done;
}
CALL_TXH(ieee80211_tx_h_michael_mic_add);
CALL_TXH(ieee80211_tx_h_sequence);
CALL_TXH(ieee80211_tx_h_fragment);
-@@ -3384,15 +3385,21 @@ out:
+@@ -3382,15 +3383,21 @@ out:
* Can be called while the sta lock is held. Anything that can cause packets to
* be generated will cause deadlock!
*/
if (key)
info->control.hw_key = &key->conf;
-@@ -3441,6 +3448,8 @@ static void ieee80211_xmit_fast_finish(s
+@@ -3439,6 +3446,8 @@ static void ieee80211_xmit_fast_finish(s
break;
}
}
}
static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
-@@ -3544,24 +3553,17 @@ static bool ieee80211_xmit_fast(struct i
+@@ -3542,24 +3551,17 @@ static bool ieee80211_xmit_fast(struct i
tx.sta = sta;
tx.key = fast_tx->key;
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
sdata = container_of(sdata->bss,
-@@ -3672,8 +3674,12 @@ begin:
+@@ -3670,8 +3672,12 @@ begin:
(tx.key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV))
pn_offs = ieee80211_hdrlen(hdr->frame_control);
int tid;
memset(tx, 0, sizeof(*tx));
-@@ -1202,8 +1226,10 @@ ieee80211_tx_prepare(struct ieee80211_su
- tx->sdata->control_port_protocol == tx->skb->protocol) {
+@@ -1200,8 +1224,10 @@ ieee80211_tx_prepare(struct ieee80211_su
+ } else if (tx->sdata->control_port_protocol == tx->skb->protocol) {
tx->sta = sta_info_get_bss(sdata, hdr->addr1);
}
- if (!tx->sta && !is_multicast_ether_addr(hdr->addr1))
}
if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) &&
-@@ -1213,8 +1239,12 @@ ieee80211_tx_prepare(struct ieee80211_su
+@@ -1211,8 +1237,12 @@ ieee80211_tx_prepare(struct ieee80211_su
struct tid_ampdu_tx *tid_tx;
tid = ieee80211_get_tid(hdr);
if (tid_tx) {
bool queued;
-@@ -3949,29 +3979,6 @@ void ieee80211_txq_schedule_start(struct
+@@ -3947,29 +3977,6 @@ void ieee80211_txq_schedule_start(struct
}
EXPORT_SYMBOL(ieee80211_txq_schedule_start);