Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 7 Jan 2017 02:07:05 +0000 (UTC)
From:      Adrian Chadd <adrian@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r311579 - head/sbin/ifconfig
Message-ID:  <201701070207.v07275AV012867@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: adrian
Date: Sat Jan  7 02:07:05 2017
New Revision: 311579
URL: https://svnweb.freebsd.org/changeset/base/311579

Log:
  [ifconfig] add initial VHT (802.11ac) configuration and channel support to ifconfig.
  
  This is very preliminary and mostly enough for me (with other patches)
  to work on VHT support.
  
  It adds:
  
  * VHT20, VHT40 and VHT80 regulatory/band awareness
  * VHT20, VHT40 and VHT80 channel configuration / population
  * Parses vht channel specifications (eg ifconfig wlan0 create wlandev athp0 wlanmode monitor channel 36:vht/80)
  * Configuration of VHT, VHT40, VHT80, VHT80+80, VHT160 channel
    width (IEEE80211_FVHT_VHT* flags in net80211)
  
  TODO:
  
  * No VHT80+80 or VHT160 channels yet - I don't yet have hardware, and I'm
    not yet sure how to support/populate VHT80+80 channels.
  * No, I won't update the manpage until this is "more done", lest someone
    tries using vht and gets upset with me.
  * No, I won't commit the regulatory database I'm testing with, so you'll
    just end up with no VHT channels ever populated.  Which is good, as there
    isn't an 11ac driver in-tree yet to try it with.

Modified:
  head/sbin/ifconfig/ifieee80211.c

Modified: head/sbin/ifconfig/ifieee80211.c
==============================================================================
--- head/sbin/ifconfig/ifieee80211.c	Sat Jan  7 01:59:39 2017	(r311578)
+++ head/sbin/ifconfig/ifieee80211.c	Sat Jan  7 02:07:05 2017	(r311579)
@@ -119,6 +119,7 @@
 #define	IEEE80211_NODE_ASSOCID	0x020000	/* xmit requires associd */
 #define	IEEE80211_NODE_AMSDU_RX	0x040000	/* AMSDU rx enabled */
 #define	IEEE80211_NODE_AMSDU_TX	0x080000	/* AMSDU tx enabled */
+#define	IEEE80211_NODE_VHT	0x100000	/* VHT enabled */
 #endif
 
 #define	MAXCHAN	1536		/* max 1.5K channels */
@@ -143,7 +144,9 @@ static const char *modename[IEEE80211_MO
 	[IEEE80211_MODE_11NA]	  = "11na",
 	[IEEE80211_MODE_11NG]	  = "11ng",
 	[IEEE80211_MODE_HALF]	  = "half",
-	[IEEE80211_MODE_QUARTER]  = "quarter"
+	[IEEE80211_MODE_QUARTER]  = "quarter",
+	[IEEE80211_MODE_VHT_2GHZ] = "11acg",
+	[IEEE80211_MODE_VHT_5GHZ] = "11ac",
 };
 
 static void set80211(int s, int type, int val, int len, void *data);
@@ -183,6 +186,20 @@ gethtconf(int s)
 	gothtconf = 1;
 }
 
+/* VHT */
+static int vhtconf = 0;
+static	int gotvhtconf = 0;
+
+static void
+getvhtconf(int s)
+{
+	if (gotvhtconf)
+		return;
+	if (get80211val(s, IEEE80211_IOC_VHTCONF, &vhtconf) < 0)
+		warn("unable to get VHT configuration information");
+	gotvhtconf = 1;
+}
+
 /*
  * Collect channel info from the kernel.  We use this (mostly)
  * to handle mapping between frequency and IEEE channel number.
@@ -200,6 +217,7 @@ getchaninfo(int s)
 		err(1, "unable to get channel information");
 	ifmr = ifmedia_getstate(s);
 	gethtconf(s);
+	getvhtconf(s);
 }
 
 static struct regdata *
@@ -255,6 +273,9 @@ canpromote(int i, int from, int to)
  * channe list (e.g. mode 11a); we want to honor that to avoid
  * confusing behaviour.
  */
+/*
+ * XXX VHT
+ */
 static int
 promote(int i)
 {
@@ -361,6 +382,10 @@ getcurchan(int s)
 static enum ieee80211_phymode
 chan2mode(const struct ieee80211_channel *c)
 {
+	if (IEEE80211_IS_CHAN_VHTA(c))
+		return IEEE80211_MODE_VHT_5GHZ;
+	if (IEEE80211_IS_CHAN_VHTG(c))
+		return IEEE80211_MODE_VHT_2GHZ;
 	if (IEEE80211_IS_CHAN_HTA(c))
 		return IEEE80211_MODE_11NA;
 	if (IEEE80211_IS_CHAN_HTG(c))
@@ -502,9 +527,12 @@ setregdomain_cb(int s, void *arg)
 		printf("drivercaps: 0x%x\n", dc->dc_drivercaps);
 		printf("cryptocaps: 0x%x\n", dc->dc_cryptocaps);
 		printf("htcaps    : 0x%x\n", dc->dc_htcaps);
+		printf("vhtcaps   : 0x%x\n", dc->dc_vhtcaps);
+#if 0
 		memcpy(chaninfo, &dc->dc_chaninfo,
 		    IEEE80211_CHANINFO_SPACE(&dc->dc_chaninfo));
 		print_channels(s, &dc->dc_chaninfo, 1/*allchans*/, 1/*verbose*/);
+#endif
 	}
 #endif
 	req = malloc(IEEE80211_REGDOMAIN_SIZE(dc->dc_chaninfo.ic_nchans));
@@ -616,6 +644,7 @@ getchannelflags(const char *val, int fre
 #define	_CHAN_HT	0x80000000
 	const char *cp;
 	int flags;
+	int is_vht = 0;
 
 	flags = 0;
 
@@ -636,6 +665,9 @@ getchannelflags(const char *val, int fre
 			case 'g':		/* 802.11g */
 				flags |= IEEE80211_CHAN_G;
 				break;
+			case 'v':		/* vht: 802.11ac */
+				is_vht = 1;
+				/* Fallthrough */
 			case 'h':		/* ht = 802.11n */
 			case 'n':		/* 802.11n */
 				flags |= _CHAN_HT;	/* NB: private */
@@ -674,6 +706,15 @@ getchannelflags(const char *val, int fre
 			flags |= IEEE80211_CHAN_HT20;
 			break;
 		case 40:
+		case 80:
+		case 160:
+			/* Handle the 80/160 VHT flag */
+			if (cw == 80)
+				flags |= IEEE80211_CHAN_VHT80;
+			else if (cw == 160)
+				flags |= IEEE80211_CHAN_VHT160;
+
+			/* Fallthrough */
 			if (ep != NULL && *ep == '+')
 				flags |= IEEE80211_CHAN_HT40U;
 			else if (ep != NULL && *ep == '-')
@@ -683,6 +724,7 @@ getchannelflags(const char *val, int fre
 			errx(-1, "%s: Invalid channel width\n", val);
 		}
 	}
+
 	/*
 	 * Cleanup specifications.
 	 */ 
@@ -695,6 +737,7 @@ getchannelflags(const char *val, int fre
 		 * are also usable for legacy operation; e.g. freq:n/40.
 		 */
 		flags &= ~IEEE80211_CHAN_HT;
+		flags &= ~IEEE80211_CHAN_VHT;
 	} else {
 		/*
 		 * Remove private indicator that this is an HT channel
@@ -714,6 +757,25 @@ getchannelflags(const char *val, int fre
 				mapchan(&chan, freq, 0);
 			flags |= (chan.ic_flags & IEEE80211_CHAN_HT);
 		}
+
+		/*
+		 * If VHT is enabled, then also set the VHT flag and the
+		 * relevant channel up/down.
+		 */
+		if (is_vht && (flags & IEEE80211_CHAN_HT)) {
+			/*
+			 * XXX yes, maybe we should just have VHT, and reuse
+			 * HT20/HT40U/HT40D
+			 */
+			if (flags & IEEE80211_CHAN_VHT80)
+				;
+			else if (flags & IEEE80211_CHAN_HT20)
+				flags |= IEEE80211_CHAN_VHT20;
+			else if (flags & IEEE80211_CHAN_HT40U)
+				flags |= IEEE80211_CHAN_VHT40U;
+			else if (flags & IEEE80211_CHAN_HT40D)
+				flags |= IEEE80211_CHAN_VHT40D;
+		}
 	}
 	return flags;
 #undef _CHAN_HT
@@ -1447,6 +1509,10 @@ getmodeflags(const char *val)
 			case 'q':		/* 1/4-width channels */
 				flags |= IEEE80211_CHAN_QUARTER;
 				break;
+			case 'v':
+				/* XXX set HT too? */
+				flags |= IEEE80211_CHAN_VHT;
+				break;
 			default:
 				errx(-1, "%s: Invalid mode attribute %c\n",
 				    val, *cp);
@@ -1863,6 +1929,21 @@ set80211rifs(const char *val, int d, int
 	set80211(s, IEEE80211_IOC_RIFS, d, 0, NULL);
 }
 
+static void
+set80211vhtconf(const char *val, int d, int s, const struct afswtch *rafp)
+{
+	if (get80211val(s, IEEE80211_IOC_VHTCONF, &vhtconf) < 0)
+		errx(-1, "cannot set VHT setting");
+	printf("%s: vhtconf=0x%08x, d=%d\n", __func__, vhtconf, d);
+	if (d < 0) {
+		d = -d;
+		vhtconf &= ~d;
+	} else
+		vhtconf |= d;
+	printf("%s: vhtconf is now 0x%08x\n", __func__, vhtconf);
+	set80211(s, IEEE80211_IOC_VHTCONF, vhtconf, 0, NULL);
+}
+
 static
 DECL_CMD_FUNC(set80211tdmaslot, val, d)
 {
@@ -2035,6 +2116,7 @@ regdomain_addchans(struct ieee80211req_c
 	hi_adj = (chanFlags & IEEE80211_CHAN_HT40U) ? -20 : 0;
 	lo_adj = (chanFlags & IEEE80211_CHAN_HT40D) ? 20 : 0;
 	channelSep = (chanFlags & IEEE80211_CHAN_2GHZ) ? 0 : 40;
+
 	LIST_FOREACH(nb, bands, next) {
 		b = nb->band;
 		if (verbose) {
@@ -2045,6 +2127,7 @@ regdomain_addchans(struct ieee80211req_c
 			putchar('\n');
 		}
 		prev = NULL;
+
 		for (freq = b->freqStart + lo_adj;
 		     freq <= b->freqEnd + hi_adj; freq += b->chanSep) {
 			/*
@@ -2055,6 +2138,40 @@ regdomain_addchans(struct ieee80211req_c
 			 * then constrained according by channel separation.
 			 */
 			flags = nb->flags | b->flags;
+
+			/*
+			 * VHT first - HT is a subset.
+			 *
+			 * XXX TODO: VHT80p80, VHT160 is not yet done.
+			 */
+			if (flags & IEEE80211_CHAN_VHT) {
+				if ((chanFlags & IEEE80211_CHAN_VHT20) &&
+				    (flags & IEEE80211_CHAN_VHT20) == 0) {
+					if (verbose)
+						printf("%u: skip, not a "
+						    "VHT20 channel\n", freq);
+					continue;
+				}
+				if ((chanFlags & IEEE80211_CHAN_VHT40) &&
+				    (flags & IEEE80211_CHAN_VHT40) == 0) {
+					if (verbose)
+						printf("%u: skip, not a "
+						    "VHT40 channel\n", freq);
+					continue;
+				}
+				if ((chanFlags & IEEE80211_CHAN_VHT80) &&
+				    (flags & IEEE80211_CHAN_VHT80) == 0) {
+					if (verbose)
+						printf("%u: skip, not a "
+						    "VHT80 channel\n", freq);
+					continue;
+				}
+
+				flags &= ~IEEE80211_CHAN_VHT;
+				flags |= chanFlags & IEEE80211_CHAN_VHT;
+			}
+
+			/* Now, constrain HT */
 			if (flags & IEEE80211_CHAN_HT) {
 				/*
 				 * HT channels are generated specially; we're
@@ -2127,7 +2244,7 @@ regdomain_addchans(struct ieee80211req_c
 			memset(c, 0, sizeof(*c));
 			c->ic_freq = freq;
 			c->ic_flags = flags;
-			if (c->ic_flags & IEEE80211_CHAN_DFS)
+		if (c->ic_flags & IEEE80211_CHAN_DFS)
 				c->ic_maxregpower = nb->maxPowerDFS;
 			else
 				c->ic_maxregpower = nb->maxPower;
@@ -2204,6 +2321,40 @@ regdomain_makechannels(
 				    &dc->dc_chaninfo);
 			}
 		}
+		if (!LIST_EMPTY(&rd->bands_11ac) && dc->dc_vhtcaps != 0) {
+			regdomain_addchans(ci, &rd->bands_11ac, reg,
+			    IEEE80211_CHAN_A | IEEE80211_CHAN_HT20 |
+			    IEEE80211_CHAN_VHT20,
+			    &dc->dc_chaninfo);
+
+			/* VHT40 is a function of HT40.. */
+			if (dc->dc_htcaps & IEEE80211_HTCAP_CHWIDTH40) {
+				regdomain_addchans(ci, &rd->bands_11ac, reg,
+				    IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U |
+				    IEEE80211_CHAN_VHT40U,
+				    &dc->dc_chaninfo);
+				regdomain_addchans(ci, &rd->bands_11ac, reg,
+				    IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D |
+				    IEEE80211_CHAN_VHT40D,
+				    &dc->dc_chaninfo);
+			}
+
+			/* VHT80 */
+			/* XXX dc_vhtcap? */
+			if (1) {
+				regdomain_addchans(ci, &rd->bands_11ac, reg,
+				    IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U |
+				    IEEE80211_CHAN_VHT80,
+				    &dc->dc_chaninfo);
+				regdomain_addchans(ci, &rd->bands_11ac, reg,
+				    IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D |
+				    IEEE80211_CHAN_VHT80,
+				    &dc->dc_chaninfo);
+			}
+
+			/* XXX TODO: VHT80_80, VHT160 */
+		}
+
 		if (!LIST_EMPTY(&rd->bands_11ng) && dc->dc_htcaps != 0) {
 			regdomain_addchans(ci, &rd->bands_11ng, reg,
 			    IEEE80211_CHAN_G | IEEE80211_CHAN_HT20,
@@ -2435,6 +2586,8 @@ getflags(int flags)
 		if (flags & IEEE80211_NODE_HTCOMPAT)
 			*cp++ = '+';
 	}
+	if (flags & IEEE80211_NODE_VHT)
+		*cp++ = 'V';
 	if (flags & IEEE80211_NODE_WPS)
 		*cp++ = 'W';
 	if (flags & IEEE80211_NODE_TSN)
@@ -3574,14 +3727,31 @@ get_chaninfo(const struct ieee80211_chan
 	if (IEEE80211_IS_CHAN_TURBO(c))
 		strlcat(buf, " Turbo", bsize);
 	if (precise) {
-		if (IEEE80211_IS_CHAN_HT20(c))
+		/* XXX should make VHT80U, VHT80D */
+		if (IEEE80211_IS_CHAN_VHT80(c) &&
+		    IEEE80211_IS_CHAN_HT40D(c))
+			strlcat(buf, " vht/80-", bsize);
+		else if (IEEE80211_IS_CHAN_VHT80(c) &&
+		    IEEE80211_IS_CHAN_HT40U(c))
+			strlcat(buf, " vht/80+", bsize);
+		else if (IEEE80211_IS_CHAN_VHT80(c))
+			strlcat(buf, " vht/80", bsize);
+		else if (IEEE80211_IS_CHAN_VHT40D(c))
+			strlcat(buf, " vht/40-", bsize);
+		else if (IEEE80211_IS_CHAN_VHT40U(c))
+			strlcat(buf, " vht/40+", bsize);
+		else if (IEEE80211_IS_CHAN_VHT20(c))
+			strlcat(buf, " vht/20", bsize);
+		else if (IEEE80211_IS_CHAN_HT20(c))
 			strlcat(buf, " ht/20", bsize);
 		else if (IEEE80211_IS_CHAN_HT40D(c))
 			strlcat(buf, " ht/40-", bsize);
 		else if (IEEE80211_IS_CHAN_HT40U(c))
 			strlcat(buf, " ht/40+", bsize);
 	} else {
-		if (IEEE80211_IS_CHAN_HT(c))
+		if (IEEE80211_IS_CHAN_VHT(c))
+			strlcat(buf, " vht", bsize);
+		else if (IEEE80211_IS_CHAN_HT(c))
 			strlcat(buf, " ht", bsize);
 	}
 	return buf;
@@ -3612,6 +3782,16 @@ print_chaninfo(const struct ieee80211_ch
 static int
 chanpref(const struct ieee80211_channel *c)
 {
+	if (IEEE80211_IS_CHAN_VHT160(c))
+		return 80;
+	if (IEEE80211_IS_CHAN_VHT80_80(c))
+		return 75;
+	if (IEEE80211_IS_CHAN_VHT80(c))
+		return 70;
+	if (IEEE80211_IS_CHAN_VHT40(c))
+		return 60;
+	if (IEEE80211_IS_CHAN_VHT20(c))
+		return 50;
 	if (IEEE80211_IS_CHAN_HT40(c))
 		return 40;
 	if (IEEE80211_IS_CHAN_HT20(c))
@@ -3807,6 +3987,11 @@ list_capabilities(int s)
 		putchar('\n');
 		printb("htcaps", dc->dc_htcaps, IEEE80211_HTCAP_BITS);
 	}
+	if (dc->dc_vhtcaps != 0 || verbose) {
+		putchar('\n');
+		printb("vhtcaps", dc->dc_vhtcaps, IEEE80211_VHTCAP_BITS);
+	}
+
 	putchar('\n');
 	if (verbose) {
 		chaninfo = &dc->dc_chaninfo;	/* XXX */
@@ -4847,6 +5032,30 @@ end:
 		}
 	}
 
+	if (IEEE80211_IS_CHAN_VHT(c) || verbose) {
+		getvhtconf(s);
+		if (vhtconf & 0x1)
+			LINE_CHECK("vht");
+		else
+			LINE_CHECK("-vht");
+		if (vhtconf & 0x2)
+			LINE_CHECK("vht40");
+		else
+			LINE_CHECK("-vht40");
+		if (vhtconf & 0x4)
+			LINE_CHECK("vht80");
+		else
+			LINE_CHECK("-vht80");
+		if (vhtconf & 0x8)
+			LINE_CHECK("vht80p80");
+		else
+			LINE_CHECK("-vht80p80");
+		if (vhtconf & 0x10)
+			LINE_CHECK("vht160");
+		else
+			LINE_CHECK("-vht160");
+	}
+
 	if (get80211val(s, IEEE80211_IOC_WME, &wme) != -1) {
 		if (wme)
 			LINE_CHECK("wme");
@@ -5426,6 +5635,16 @@ static struct cmd ieee80211_cmds[] = {
 	DEF_CMD("-ht40",	0,	set80211htconf),
 	DEF_CMD("ht",		3,	set80211htconf),	/* NB: 20+40 */
 	DEF_CMD("-ht",		0,	set80211htconf),
+	DEF_CMD("vht",		1,	set80211vhtconf),
+	DEF_CMD("-vht",		0,	set80211vhtconf),
+	DEF_CMD("vht40",		2,	set80211vhtconf),
+	DEF_CMD("-vht40",		-2,	set80211vhtconf),
+	DEF_CMD("vht80",		4,	set80211vhtconf),
+	DEF_CMD("-vht80",		-4,	set80211vhtconf),
+	DEF_CMD("vht80p80",		8,	set80211vhtconf),
+	DEF_CMD("-vht80p80",		-8,	set80211vhtconf),
+	DEF_CMD("vht160",		16,	set80211vhtconf),
+	DEF_CMD("-vht160",		-16,	set80211vhtconf),
 	DEF_CMD("rifs",		1,	set80211rifs),
 	DEF_CMD("-rifs",	0,	set80211rifs),
 	DEF_CMD("smps",		IEEE80211_HTCAP_SMPS_ENA,	set80211smps),



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