mac80211: set default QoS values according to spec

We've never really cared about the default QoS (WMM) values, but
we really should if the AP doesn't send any. This patch makes
mac80211 use the default values according to 802.11-2007, and
additionally syncs the default values when we disassociate so
whatever the last AP said gets "unconfigured".

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 97b613a..0689a8f 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -708,26 +708,62 @@
 {
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_tx_queue_params qparam;
-	int i;
+	int queue;
+	bool use_11b;
+	int aCWmin, aCWmax;
 
 	if (!local->ops->conf_tx)
 		return;
 
 	memset(&qparam, 0, sizeof(qparam));
 
-	qparam.aifs = 2;
+	use_11b = (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) &&
+		 !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE);
 
-	if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&
-	    !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE))
-		qparam.cw_min = 31;
-	else
-		qparam.cw_min = 15;
+	for (queue = 0; queue < local_to_hw(local)->queues; queue++) {
+		/* Set defaults according to 802.11-2007 Table 7-37 */
+		aCWmax = 1023;
+		if (use_11b)
+			aCWmin = 31;
+		else
+			aCWmin = 15;
 
-	qparam.cw_max = 1023;
-	qparam.txop = 0;
+		switch (queue) {
+		case 3: /* AC_BK */
+			qparam.cw_max = aCWmin;
+			qparam.cw_min = aCWmax;
+			qparam.txop = 0;
+			qparam.aifs = 7;
+			break;
+		default: /* never happens but let's not leave undefined */
+		case 2: /* AC_BE */
+			qparam.cw_max = aCWmin;
+			qparam.cw_min = aCWmax;
+			qparam.txop = 0;
+			qparam.aifs = 3;
+			break;
+		case 1: /* AC_VI */
+			qparam.cw_max = aCWmin;
+			qparam.cw_min = (aCWmin + 1) / 2 - 1;
+			if (use_11b)
+				qparam.txop = 6016/32;
+			else
+				qparam.txop = 3008/32;
+			qparam.aifs = 2;
+			break;
+		case 0: /* AC_VO */
+			qparam.cw_max = (aCWmin + 1) / 2 - 1;
+			qparam.cw_min = (aCWmin + 1) / 4 - 1;
+			if (use_11b)
+				qparam.txop = 3264/32;
+			else
+				qparam.txop = 1504/32;
+			qparam.aifs = 2;
+			break;
+		}
 
-	for (i = 0; i < local_to_hw(local)->queues; i++)
-		drv_conf_tx(local, i, &qparam);
+		drv_conf_tx(local, queue, &qparam);
+	}
 }
 
 void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,