Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 3 Mar 2017 01:06:27 +0000 (UTC)
From:      Andriy Voskoboinyk <avos@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r314575 - head/sys/net80211
Message-ID:  <201703030106.v2316RPn082661@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: avos
Date: Fri Mar  3 01:06:27 2017
New Revision: 314575
URL: https://svnweb.freebsd.org/changeset/base/314575

Log:
  net80211: fix ieee80211_htrateset setup, return EINVAL for an unsupported
  ucast/mcast/mgmt HT rate.
  
  - Init global ieee80211_htrateset only once; neither ic_htcaps nor
  ic_txstream is changed when device is attached;
  - Move global ieee80211_htrateset structure to ieee80211com;
  there was a possible data race when more than 1 wireless device is
  used simultaneously;
  - Discard unsupported rates in ieee80211_ioctl_settxparams(); otherwise,
  an unsupported value may break connectivity (actually,
  'ifconfig wlan0 ucastrate 8' for RTL8188EU results in immediate
  disconnect + infinite 'device timeout's after it).
  
  Tested with:
   - Intel 6205, STA mode.
   - RTL8821AU, STA mode.
  
  Reviewed by:	adrian
  Differential Revision:	https://reviews.freebsd.org/D9871

Modified:
  head/sys/net80211/ieee80211.c
  head/sys/net80211/ieee80211_ht.c
  head/sys/net80211/ieee80211_ht.h
  head/sys/net80211/ieee80211_ioctl.c
  head/sys/net80211/ieee80211_var.h

Modified: head/sys/net80211/ieee80211.c
==============================================================================
--- head/sys/net80211/ieee80211.c	Fri Mar  3 00:47:42 2017	(r314574)
+++ head/sys/net80211/ieee80211.c	Fri Mar  3 01:06:27 2017	(r314575)
@@ -242,6 +242,8 @@ ieee80211_chan_init(struct ieee80211com 
 	if (ic->ic_txstream == 0)
 		ic->ic_txstream = 2;
 
+	ieee80211_init_suphtrates(ic);
+
 	/*
 	 * Set auto mode to reset active channel state and any desired channel.
 	 */
@@ -1905,6 +1907,14 @@ ieee80211_get_suprates(struct ieee80211c
 	return &ic->ic_sup_rates[ieee80211_chan2mode(c)];
 }
 
+/* XXX inline or eliminate? */
+const struct ieee80211_htrateset *
+ieee80211_get_suphtrates(struct ieee80211com *ic,
+    const struct ieee80211_channel *c)
+{
+	return &ic->ic_sup_htrates;
+}
+
 void
 ieee80211_announce(struct ieee80211com *ic)
 {

Modified: head/sys/net80211/ieee80211_ht.c
==============================================================================
--- head/sys/net80211/ieee80211_ht.c	Fri Mar  3 00:47:42 2017	(r314574)
+++ head/sys/net80211/ieee80211_ht.c	Fri Mar  3 01:06:27 2017	(r314575)
@@ -421,19 +421,17 @@ ieee80211_ht_announce(struct ieee80211co
 		ht_announce(ic, IEEE80211_MODE_11NG);
 }
 
-static struct ieee80211_htrateset htrateset;
-
-const struct ieee80211_htrateset *
-ieee80211_get_suphtrates(struct ieee80211com *ic,
-    const struct ieee80211_channel *c)
+void
+ieee80211_init_suphtrates(struct ieee80211com *ic)
 {
 #define	ADDRATE(x)	do {						\
-	htrateset.rs_rates[htrateset.rs_nrates] = x;			\
-	htrateset.rs_nrates++;						\
+	htrateset->rs_rates[htrateset->rs_nrates] = x;			\
+	htrateset->rs_nrates++;						\
 } while (0)
+	struct ieee80211_htrateset *htrateset = &ic->ic_sup_htrates;
 	int i;
 
-	memset(&htrateset, 0, sizeof(struct ieee80211_htrateset));
+	memset(htrateset, 0, sizeof(struct ieee80211_htrateset));
 	for (i = 0; i < ic->ic_txstream * 8; i++)
 		ADDRATE(i);
 	if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) &&
@@ -453,7 +451,6 @@ ieee80211_get_suphtrates(struct ieee8021
 				ADDRATE(i);
 		}
 	}
-	return &htrateset;
 #undef	ADDRATE
 }
 

Modified: head/sys/net80211/ieee80211_ht.h
==============================================================================
--- head/sys/net80211/ieee80211_ht.h	Fri Mar  3 00:47:42 2017	(r314574)
+++ head/sys/net80211/ieee80211_ht.h	Fri Mar  3 01:06:27 2017	(r314575)
@@ -177,8 +177,7 @@ struct ieee80211_mcs_rates {
 	uint16_t	ht40_rate_400ns;
 };
 extern const struct ieee80211_mcs_rates ieee80211_htrates[];
-const struct ieee80211_htrateset *ieee80211_get_suphtrates(
-		struct ieee80211com *, const struct ieee80211_channel *);
+void	ieee80211_init_suphtrates(struct ieee80211com *);
 
 struct ieee80211_node;
 int	ieee80211_setup_htrates(struct ieee80211_node *,

Modified: head/sys/net80211/ieee80211_ioctl.c
==============================================================================
--- head/sys/net80211/ieee80211_ioctl.c	Fri Mar  3 00:47:42 2017	(r314574)
+++ head/sys/net80211/ieee80211_ioctl.c	Fri Mar  3 01:06:27 2017	(r314575)
@@ -2226,13 +2226,19 @@ checkrate(const struct ieee80211_rateset
 }
 
 static int
-checkmcs(int mcs)
+checkmcs(const struct ieee80211_htrateset *rs, int mcs)
 {
+	int rate_val = IEEE80211_RV(mcs);
+	int i;
+
 	if (mcs == IEEE80211_FIXED_RATE_NONE)
 		return 1;
 	if ((mcs & IEEE80211_RATE_MCS) == 0)	/* MCS always have 0x80 set */
 		return 0;
-	return (mcs & 0x7f) <= 31;	/* XXX could search ht rate set */
+	for (i = 0; i < rs->rs_nrates; i++)
+		if (IEEE80211_RV(rs->rs_rates[i]) == rate_val)
+			return 1;
+	return 0;
 }
 
 static int
@@ -2242,6 +2248,7 @@ ieee80211_ioctl_settxparams(struct ieee8
 	struct ieee80211com *ic = vap->iv_ic;
 	struct ieee80211_txparams_req parms;	/* XXX stack use? */
 	struct ieee80211_txparam *src, *dst;
+	const struct ieee80211_htrateset *rs_ht;
 	const struct ieee80211_rateset *rs;
 	int error, mode, changed, is11n, nmodes;
 
@@ -2260,23 +2267,24 @@ ieee80211_ioctl_settxparams(struct ieee8
 		src = &parms.params[mode];
 		dst = &vap->iv_txparms[mode];
 		rs = &ic->ic_sup_rates[mode];	/* NB: 11n maps to legacy */
+		rs_ht = &ic->ic_sup_htrates;
 		is11n = (mode == IEEE80211_MODE_11NA ||
 			 mode == IEEE80211_MODE_11NG);
 		if (src->ucastrate != dst->ucastrate) {
 			if (!checkrate(rs, src->ucastrate) &&
-			    (!is11n || !checkmcs(src->ucastrate)))
+			    (!is11n || !checkmcs(rs_ht, src->ucastrate)))
 				return EINVAL;
 			changed++;
 		}
 		if (src->mcastrate != dst->mcastrate) {
 			if (!checkrate(rs, src->mcastrate) &&
-			    (!is11n || !checkmcs(src->mcastrate)))
+			    (!is11n || !checkmcs(rs_ht, src->mcastrate)))
 				return EINVAL;
 			changed++;
 		}
 		if (src->mgmtrate != dst->mgmtrate) {
 			if (!checkrate(rs, src->mgmtrate) &&
-			    (!is11n || !checkmcs(src->mgmtrate)))
+			    (!is11n || !checkmcs(rs_ht, src->mgmtrate)))
 				return EINVAL;
 			changed++;
 		}

Modified: head/sys/net80211/ieee80211_var.h
==============================================================================
--- head/sys/net80211/ieee80211_var.h	Fri Mar  3 00:47:42 2017	(r314574)
+++ head/sys/net80211/ieee80211_var.h	Fri Mar  3 01:06:27 2017	(r314575)
@@ -175,6 +175,7 @@ struct ieee80211com {
 	uint16_t		ic_holdover;	/* PM hold over duration */
 	uint16_t		ic_txpowlimit;	/* global tx power limit */
 	struct ieee80211_rateset ic_sup_rates[IEEE80211_MODE_MAX];
+	struct ieee80211_htrateset ic_sup_htrates;
 
 	/*
 	 * Channel state:
@@ -692,6 +693,8 @@ int	ieee80211_vap_attach(struct ieee8021
 void	ieee80211_vap_detach(struct ieee80211vap *);
 const struct ieee80211_rateset *ieee80211_get_suprates(struct ieee80211com *ic,
 		const struct ieee80211_channel *);
+const struct ieee80211_htrateset *ieee80211_get_suphtrates(
+		struct ieee80211com *, const struct ieee80211_channel *);
 void	ieee80211_announce(struct ieee80211com *);
 void	ieee80211_announce_channels(struct ieee80211com *);
 void	ieee80211_drain(struct ieee80211com *);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201703030106.v2316RPn082661>