From 4a58a871c46a589263f565ee7b755d5f3d695580 Mon Sep 17 00:00:00 2001
From: Felix Fietkau <nbd@nbd.name>
Date: Thu, 23 Jan 2020 14:51:58 +0100
Subject: hostapd: fix faulty WMM IE parameters with ETSI regulatory domains

hostapd sets minimum values for CWmin/CWmax/AIFS and maximum for TXOP.
The code for applying those values had a few bugs leading to bogus values,
which caused significant latency and packet loss.

Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
 ...211-fix-WMM-queue-mapping-for-regulatory-.patch | 41 +++++++++++++++++++
 ...211-fix-regulatory-limits-for-wmm-cwmin-c.patch | 47 ++++++++++++++++++++++
 2 files changed, 88 insertions(+)
 create mode 100644 package/network/services/hostapd/patches/070-driver_nl80211-fix-WMM-queue-mapping-for-regulatory-.patch
 create mode 100644 package/network/services/hostapd/patches/071-driver_nl80211-fix-regulatory-limits-for-wmm-cwmin-c.patch

diff --git a/package/network/services/hostapd/patches/070-driver_nl80211-fix-WMM-queue-mapping-for-regulatory-.patch b/package/network/services/hostapd/patches/070-driver_nl80211-fix-WMM-queue-mapping-for-regulatory-.patch
new file mode 100644
index 0000000000..240411236a
--- /dev/null
+++ b/package/network/services/hostapd/patches/070-driver_nl80211-fix-WMM-queue-mapping-for-regulatory-.patch
@@ -0,0 +1,41 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Thu, 23 Jan 2020 13:50:47 +0100
+Subject: [PATCH] driver_nl80211: fix WMM queue mapping for regulatory
+ limit
+
+nl80211 uses a different queue mapping from hostap, so AC indexes need to
+be converted.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/src/drivers/driver_nl80211_capa.c
++++ b/src/drivers/driver_nl80211_capa.c
+@@ -1403,6 +1403,12 @@ static void phy_info_freq(struct hostapd
+ 			[NL80211_WMMR_AIFSN] = { .type = NLA_U8 },
+ 			[NL80211_WMMR_TXOP] = { .type = NLA_U16 },
+ 		};
++		static const u8 wmm_map[4] = {
++			[NL80211_AC_BE] = WMM_AC_BE,
++			[NL80211_AC_BK] = WMM_AC_BK,
++			[NL80211_AC_VI] = WMM_AC_VI,
++			[NL80211_AC_VO] = WMM_AC_VO,
++		};
+ 		struct nlattr *nl_wmm;
+ 		struct nlattr *tb_wmm[NL80211_WMMR_MAX + 1];
+ 		int rem_wmm, ac, count = 0;
+@@ -1424,12 +1430,13 @@ static void phy_info_freq(struct hostapd
+ 				return;
+ 			}
+ 			ac = nl_wmm->nla_type;
+-			if (ac < 0 || ac >= WMM_AC_NUM) {
++			if (ac >= ARRAY_SIZE(wmm_map)) {
+ 				wpa_printf(MSG_DEBUG,
+ 					   "nl80211: Invalid AC value %d", ac);
+ 				return;
+ 			}
+ 
++			ac = wmm_map[ac];
+ 			chan->wmm_rules[ac].min_cwmin =
+ 				nla_get_u16(tb_wmm[NL80211_WMMR_CW_MIN]);
+ 			chan->wmm_rules[ac].min_cwmax =
diff --git a/package/network/services/hostapd/patches/071-driver_nl80211-fix-regulatory-limits-for-wmm-cwmin-c.patch b/package/network/services/hostapd/patches/071-driver_nl80211-fix-regulatory-limits-for-wmm-cwmin-c.patch
new file mode 100644
index 0000000000..fe41e2b788
--- /dev/null
+++ b/package/network/services/hostapd/patches/071-driver_nl80211-fix-regulatory-limits-for-wmm-cwmin-c.patch
@@ -0,0 +1,47 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Thu, 23 Jan 2020 14:10:20 +0100
+Subject: [PATCH] driver_nl80211: fix regulatory limits for wmm cwmin/cwmax
+ values
+
+The internal WMM AC parameters use just the exponent of the CW value, while
+nl80211 reports the full CW value.
+This led to completely bogus CWmin/CWmax values in the WMM IE when a regulatory
+limit was present. Fix this by converting the value to the exponent before
+passing it on
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/src/drivers/driver_nl80211_capa.c
++++ b/src/drivers/driver_nl80211_capa.c
+@@ -1336,6 +1336,18 @@ static void phy_info_vht_capa(struct hos
+ 	}
+ }
+ 
++static inline int cw2ecw(unsigned int cw)
++{
++	int bit;
++
++	if (cw == 0)
++		return 0;
++
++	for (bit = 1; cw != 1; bit++)
++		cw >>= 1;
++
++	return bit;
++}
+ 
+ static void phy_info_freq(struct hostapd_hw_modes *mode,
+ 			  struct hostapd_channel_data *chan,
+@@ -1438,9 +1450,9 @@ static void phy_info_freq(struct hostapd
+ 
+ 			ac = wmm_map[ac];
+ 			chan->wmm_rules[ac].min_cwmin =
+-				nla_get_u16(tb_wmm[NL80211_WMMR_CW_MIN]);
++				cw2ecw(nla_get_u16(tb_wmm[NL80211_WMMR_CW_MIN]));
+ 			chan->wmm_rules[ac].min_cwmax =
+-				nla_get_u16(tb_wmm[NL80211_WMMR_CW_MAX]);
++				cw2ecw(nla_get_u16(tb_wmm[NL80211_WMMR_CW_MAX]));
+ 			chan->wmm_rules[ac].min_aifs =
+ 				nla_get_u8(tb_wmm[NL80211_WMMR_AIFSN]);
+ 			chan->wmm_rules[ac].max_txop =
-- 
cgit v1.2.3