Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 28 Jan 2009 21:52:45 +0000 (UTC)
From:      Sam Leffler <sam@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r187872 - projects/vap7/sbin/ifconfig
Message-ID:  <200901282152.n0SLqjJa034491@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: sam
Date: Wed Jan 28 21:52:45 2009
New Revision: 187872
URL: http://svn.freebsd.org/changeset/base/187872

Log:
  sync 802.11 changes with head

Modified:
  projects/vap7/sbin/ifconfig/   (props changed)
  projects/vap7/sbin/ifconfig/ifieee80211.c

Modified: projects/vap7/sbin/ifconfig/ifieee80211.c
==============================================================================
--- projects/vap7/sbin/ifconfig/ifieee80211.c	Wed Jan 28 21:42:17 2009	(r187871)
+++ projects/vap7/sbin/ifconfig/ifieee80211.c	Wed Jan 28 21:52:45 2009	(r187872)
@@ -79,6 +79,7 @@
 
 #include <net80211/ieee80211_ioctl.h>
 
+#include <assert.h>
 #include <ctype.h>
 #include <err.h>
 #include <errno.h>
@@ -119,6 +120,8 @@
 #define	IEEE80211_NODE_RIFS	0x4000		/* RIFS enabled */
 #endif
 
+#define	MAXCHAN	1536		/* max 1.5K channels */
+
 #define	MAXCOL	78
 static	int col;
 static	char spacer;
@@ -145,7 +148,7 @@ static void print_channels(int, const st
 static void regdomain_makechannels(struct ieee80211_regdomain_req *,
     const struct ieee80211_devcaps_req *);
 
-static struct ieee80211req_chaninfo chaninfo;
+static struct ieee80211req_chaninfo *chaninfo;
 static struct ieee80211_regdomain regdomain;
 static int gotregdomain = 0;
 static struct ieee80211_roamparams_req roamparams;
@@ -175,10 +178,14 @@ gethtconf(int s)
 static void
 getchaninfo(int s)
 {
-	if (chaninfo.ic_nchans != 0)
+	if (chaninfo != NULL)
 		return;
-	if (get80211(s, IEEE80211_IOC_CHANINFO, &chaninfo, sizeof(chaninfo)) < 0)
-		errx(1, "unable to get channel information");
+	chaninfo = malloc(IEEE80211_CHANINFO_SIZE(MAXCHAN));
+	if (chaninfo == NULL)
+		errx(1, "no space for channel list");
+	if (get80211(s, IEEE80211_IOC_CHANINFO, chaninfo,
+	    IEEE80211_CHANINFO_SIZE(MAXCHAN)) < 0)
+		err(1, "unable to get channel information");
 	ifmr = ifmedia_getstate(s);
 	gethtconf(s);
 }
@@ -205,19 +212,19 @@ getregdata(void)
 static int
 canpromote(int i, int from, int to)
 {
-	const struct ieee80211_channel *fc = &chaninfo.ic_chans[i];
+	const struct ieee80211_channel *fc = &chaninfo->ic_chans[i];
 	int j;
 
 	if ((fc->ic_flags & from) != from)
 		return i;
 	/* NB: quick check exploiting ordering of chans w/ same frequency */
-	if (i+1 < chaninfo.ic_nchans &&
-	    chaninfo.ic_chans[i+1].ic_freq == fc->ic_freq &&
-	    (chaninfo.ic_chans[i+1].ic_flags & to) == to)
+	if (i+1 < chaninfo->ic_nchans &&
+	    chaninfo->ic_chans[i+1].ic_freq == fc->ic_freq &&
+	    (chaninfo->ic_chans[i+1].ic_flags & to) == to)
 		return i+1;
 	/* brute force search in case channel list is not ordered */
-	for (j = 0; j < chaninfo.ic_nchans; j++) {
-		const struct ieee80211_channel *tc = &chaninfo.ic_chans[j];
+	for (j = 0; j < chaninfo->ic_nchans; j++) {
+		const struct ieee80211_channel *tc = &chaninfo->ic_chans[j];
 		if (j != i &&
 		    tc->ic_freq == fc->ic_freq && (tc->ic_flags & to) == to)
 		return j;
@@ -287,13 +294,13 @@ mapfreq(struct ieee80211_channel *chan, 
 {
 	int i;
 
-	for (i = 0; i < chaninfo.ic_nchans; i++) {
-		const struct ieee80211_channel *c = &chaninfo.ic_chans[i];
+	for (i = 0; i < chaninfo->ic_nchans; i++) {
+		const struct ieee80211_channel *c = &chaninfo->ic_chans[i];
 
 		if (c->ic_freq == freq && (c->ic_flags & flags) == flags) {
 			if (flags == 0) {
 				/* when ambiguous promote to ``best'' */
-				c = &chaninfo.ic_chans[promote(i)];
+				c = &chaninfo->ic_chans[promote(i)];
 			}
 			*chan = *c;
 			return;
@@ -307,13 +314,13 @@ mapchan(struct ieee80211_channel *chan, 
 {
 	int i;
 
-	for (i = 0; i < chaninfo.ic_nchans; i++) {
-		const struct ieee80211_channel *c = &chaninfo.ic_chans[i];
+	for (i = 0; i < chaninfo->ic_nchans; i++) {
+		const struct ieee80211_channel *c = &chaninfo->ic_chans[i];
 
 		if (c->ic_ieee == ieee && (c->ic_flags & flags) == flags) {
 			if (flags == 0) {
 				/* when ambiguous promote to ``best'' */
-				c = &chaninfo.ic_chans[promote(i)];
+				c = &chaninfo->ic_chans[promote(i)];
 			}
 			*chan = *c;
 			return;
@@ -331,7 +338,7 @@ getcurchan(int s)
 		int val;
 		/* fall back to legacy ioctl */
 		if (get80211val(s, IEEE80211_IOC_CHANNEL, &val) < 0)
-			errx(-1, "cannot figure out current channel");
+			err(-1, "cannot figure out current channel");
 		getchaninfo(s);
 		mapchan(&curchan, val, 0);
 	}
@@ -370,7 +377,7 @@ getroam(int s)
 		return;
 	if (get80211(s, IEEE80211_IOC_ROAM,
 	    &roamparams, sizeof(roamparams)) < 0)
-		errx(1, "unable to get roaming parameters");
+		err(1, "unable to get roaming parameters");
 	gotroam = 1;
 }
 
@@ -388,7 +395,7 @@ gettxparams(int s)
 		return;
 	if (get80211(s, IEEE80211_IOC_TXPARAMS,
 	    &txparams, sizeof(txparams)) < 0)
-		errx(1, "unable to get transmit parameters");
+		err(1, "unable to get transmit parameters");
 	gottxparams = 1;
 }
 
@@ -406,23 +413,24 @@ getregdomain(int s)
 		return;
 	if (get80211(s, IEEE80211_IOC_REGDOMAIN,
 	    &regdomain, sizeof(regdomain)) < 0)
-		errx(1, "unable to get regulatory domain info");
+		err(1, "unable to get regulatory domain info");
 	gotregdomain = 1;
 }
 
 static void
 getdevcaps(int s, struct ieee80211_devcaps_req *dc)
 {
-	if (get80211(s, IEEE80211_IOC_DEVCAPS, dc, sizeof(*dc)) < 0)
-		errx(1, "unable to get device capabilities");
+	if (get80211(s, IEEE80211_IOC_DEVCAPS, dc,
+	    IEEE80211_DEVCAPS_SPACE(dc)) < 0)
+		err(1, "unable to get device capabilities");
 }
 
 static void
 setregdomain_cb(int s, void *arg)
 {
-	struct ieee80211_regdomain_req req;
+	struct ieee80211_regdomain_req *req;
 	struct ieee80211_regdomain *rd = arg;
-	struct ieee80211_devcaps_req dc;
+	struct ieee80211_devcaps_req *dc;
 	struct regdata *rdp = getregdata();
 
 	if (rd->country != NO_COUNTRY) {
@@ -462,34 +470,52 @@ setregdomain_cb(int s, void *arg)
 				   rp->name);
 		}
 	}
-	req.rd = *rd;
 	/*
 	 * Fetch the device capabilities and calculate the
 	 * full set of netbands for which we request a new
 	 * channel list be constructed.  Once that's done we
 	 * push the regdomain info + channel list to the kernel.
 	 */
-	getdevcaps(s, &dc);
+	dc = malloc(IEEE80211_DEVCAPS_SIZE(MAXCHAN));
+	if (dc == NULL)
+		errx(1, "no space for device capabilities");
+	dc->dc_chaninfo.ic_nchans = MAXCHAN;
+	getdevcaps(s, dc);
 #if 0
 	if (verbose) {
-		printf("drivercaps: 0x%x\n", dc.dc_drivercaps);
-		printf("cryptocaps: 0x%x\n", dc.dc_cryptocaps);
-		printf("htcaps    : 0x%x\n", dc.dc_htcaps);
-		memcpy(&chaninfo, &dc.dc_chaninfo, sizeof(chaninfo));
-		print_channels(s, &dc.dc_chaninfo, 1/*allchans*/, 1/*verbose*/);
+		printf("drivercaps: 0x%x\n", dc->dc_drivercaps);
+		printf("cryptocaps: 0x%x\n", dc->dc_cryptocaps);
+		printf("htcaps    : 0x%x\n", dc->dc_htcaps);
+		memcpy(chaninfo, &dc->dc_chaninfo,
+		    IEEE80211_CHANINFO_SPACE(&dc->dc_chaninfo));
+		print_channels(s, &dc->dc_chaninfo, 1/*allchans*/, 1/*verbose*/);
 	}
 #endif
-	regdomain_makechannels(&req, &dc);
+	req = malloc(IEEE80211_REGDOMAIN_SIZE(dc->dc_chaninfo.ic_nchans));
+	if (req == NULL)
+		errx(1, "no space for regdomain request");
+	req->rd = *rd;
+	regdomain_makechannels(req, dc);
 	if (verbose) {
 		LINE_INIT(':');
 		print_regdomain(rd, 1/*verbose*/);
 		LINE_BREAK();
-		memcpy(&chaninfo, &req.chaninfo, sizeof(chaninfo));
-		print_channels(s, &req.chaninfo, 1/*allchans*/, 1/*verbose*/);
+		/* blech, reallocate channel list for new data */
+		if (chaninfo != NULL)
+			free(chaninfo);
+		chaninfo = malloc(IEEE80211_CHANINFO_SPACE(&req->chaninfo));
+		if (chaninfo == NULL)
+			errx(1, "no space for channel list");
+		memcpy(chaninfo, &req->chaninfo,
+		    IEEE80211_CHANINFO_SPACE(&req->chaninfo));
+		print_channels(s, &req->chaninfo, 1/*allchans*/, 1/*verbose*/);
 	}
-	if (req.chaninfo.ic_nchans == 0)
+	if (req->chaninfo.ic_nchans == 0)
 		errx(1, "no channels calculated");
-	set80211(s, IEEE80211_IOC_REGDOMAIN, 0, sizeof(req), &req);
+	set80211(s, IEEE80211_IOC_REGDOMAIN, 0,
+	    IEEE80211_REGDOMAIN_SPACE(req), req);
+	free(req);
+	free(dc);
 }
 
 static int
@@ -980,7 +1006,6 @@ static void
 set80211chanlist(const char *val, int d, int s, const struct afswtch *rafp)
 {
 	struct ieee80211req_chanlist chanlist;
-#define	MAXCHAN	(sizeof(chanlist.ic_channels)*NBBY)
 	char *temp, *cp, *tp;
 
 	temp = malloc(strlen(val) + 1);
@@ -997,18 +1022,18 @@ set80211chanlist(const char *val, int d,
 			*tp++ = '\0';
 		switch (sscanf(cp, "%u-%u", &first, &last)) {
 		case 1:
-			if (first > MAXCHAN)
+			if (first > IEEE80211_CHAN_MAX)
 				errx(-1, "channel %u out of range, max %zu",
-					first, MAXCHAN);
+					first, IEEE80211_CHAN_MAX);
 			setbit(chanlist.ic_channels, first);
 			break;
 		case 2:
-			if (first > MAXCHAN)
+			if (first > IEEE80211_CHAN_MAX)
 				errx(-1, "channel %u out of range, max %zu",
-					first, MAXCHAN);
-			if (last > MAXCHAN)
+					first, IEEE80211_CHAN_MAX);
+			if (last > IEEE80211_CHAN_MAX)
 				errx(-1, "channel %u out of range, max %zu",
-					last, MAXCHAN);
+					last, IEEE80211_CHAN_MAX);
 			if (first > last)
 				errx(-1, "void channel range, %u > %u",
 					first, last);
@@ -1026,7 +1051,6 @@ set80211chanlist(const char *val, int d,
 		cp = tp;
 	}
 	set80211(s, IEEE80211_IOC_CHANLIST, 0, sizeof(chanlist), &chanlist);
-#undef MAXCHAN
 }
 
 static void
@@ -1641,7 +1665,7 @@ set80211amsdu(const char *val, int d, in
 	int amsdu;
 
 	if (get80211val(s, IEEE80211_IOC_AMSDU, &amsdu) < 0)
-		errx(-1, "cannot get AMSDU setting");
+		err(-1, "cannot get AMSDU setting");
 	if (d < 0) {
 		d = -d;
 		amsdu &= ~d;
@@ -1765,6 +1789,19 @@ chanlookup(const struct ieee80211_channe
 	return NULL;
 }
 
+static int
+chanfind(const struct ieee80211_channel chans[], int nchans, int flags)
+{
+	int i;
+
+	for (i = 0; i < nchans; i++) {
+		const struct ieee80211_channel *c = &chans[i];
+		if ((c->ic_flags & flags) == flags)
+			return 1;
+	}
+	return 0;
+}
+
 static void
 regdomain_addchans(struct ieee80211req_chaninfo *ci,
 	const netband_head *bands,
@@ -1775,53 +1812,72 @@ regdomain_addchans(struct ieee80211req_c
 	const struct netband *nb;
 	const struct freqband *b;
 	struct ieee80211_channel *c, *prev;
-	int freq, channelSep;
+	int freq, channelSep, hasHalfChans, hasQuarterChans;
 
 	channelSep = (chanFlags & IEEE80211_CHAN_2GHZ) ? 0 : 40;
+	hasHalfChans = chanfind(avail->ic_chans, avail->ic_nchans,
+	    IEEE80211_CHAN_HALF |
+	       (chanFlags & (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ)));
+	hasQuarterChans = chanfind(avail->ic_chans, avail->ic_nchans,
+	    IEEE80211_CHAN_QUARTER |
+	        (chanFlags & (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ)));
 	LIST_FOREACH(nb, bands, next) {
 		b = nb->band;
-		if (verbose)
-			printf("%s: chanFlags 0x%x b %p\n",
-			    __func__, chanFlags, b);
+		if (verbose) {
+			printf("%s:", __func__);
+			printb(" chanFlags", chanFlags, IEEE80211_CHAN_BITS);
+			printb(" bandFlags", nb->flags | b->flags,
+			    IEEE80211_CHAN_BITS);
+			putchar('\n');
+		}
 		prev = NULL;
 		for (freq = b->freqStart; freq <= b->freqEnd; freq += b->chanSep) {
 			uint32_t flags = nb->flags | b->flags;
 
 			/* check if device can operate on this frequency */
-			if (chanlookup(avail->ic_chans, avail->ic_nchans, freq, chanFlags) == NULL) {
-				if (verbose)
-					printf("%u: skip, flags 0x%x not available\n", freq, chanFlags);
-				continue;
-			}
 			/*
-			 * NB: don't enforce 1/2 and 1/4 rate channels being
-			 * specified in the device's calibration list for
-			 * 900MHz cards because most are not self-identifying.
+			 * XXX GSM frequency mapping is handled in the kernel
+			 * so we cannot find them in the calibration table;
+			 * just construct the list and the kernel will reject
+			 * if it's wrong.
 			 */
-			if ((flags & IEEE80211_CHAN_HALF) &&
-			    ((chanFlags & IEEE80211_CHAN_HALF) == 0 &&
-			     (flags & IEEE80211_CHAN_GSM) == 0)) {
+			if (chanlookup(avail->ic_chans, avail->ic_nchans, freq, chanFlags) == NULL &&
+			    (flags & IEEE80211_CHAN_GSM) == 0) {
+				if (verbose) {
+					printf("%u: skip, ", freq);
+					printb("flags", chanFlags,
+					    IEEE80211_CHAN_BITS);
+					printf(" not available\n");
+				}
+				continue;
+			}
+			if ((flags & IEEE80211_CHAN_HALF) && !hasHalfChans) {
 				if (verbose)
-					printf("%u: skip, device does not support half-rate channels\n", freq);
+					printf("%u: skip, device does not "
+					    "support half-rate channel\n",
+					    freq);
 				continue;
 			}
 			if ((flags & IEEE80211_CHAN_QUARTER) &&
-			    ((chanFlags & IEEE80211_CHAN_QUARTER) == 0 &&
-			     (flags & IEEE80211_CHAN_GSM) == 0)) {
+			    !hasQuarterChans) {
 				if (verbose)
-					printf("%u: skip, device does not support quarter-rate channels\n", freq);
+					printf("%u: skip, device does not "
+					    "support quarter-rate channel\n",
+					    freq);
 				continue;
 			}
 			if ((flags & IEEE80211_CHAN_HT20) &&
 			    (chanFlags & IEEE80211_CHAN_HT20) == 0) {
 				if (verbose)
-					printf("%u: skip, device does not support HT20 operation\n", freq);
+					printf("%u: skip, device does not "
+					    "support HT20 operation\n", freq);
 				continue;
 			}
 			if ((flags & IEEE80211_CHAN_HT40) &&
 			    (chanFlags & IEEE80211_CHAN_HT40) == 0) {
 				if (verbose)
-					printf("%u: skip, device does not support HT40 operation\n", freq);
+					printf("%u: skip, device does not "
+					    "support HT40 operation\n", freq);
 				continue;
 			}
 			if ((flags & REQ_ECM) && !reg->ecm) {
@@ -1844,10 +1900,12 @@ regdomain_addchans(struct ieee80211req_c
 			}
 			if (ci->ic_nchans == IEEE80211_CHAN_MAX) {
 				if (verbose)
-					printf("%u: skip, channel table full\n", freq);
+					printf("%u: skip, channel table full\n",
+					    freq);
 				break;
 			}
 			c = &ci->ic_chans[ci->ic_nchans++];
+			memset(c, 0, sizeof(*c));
 			c->ic_freq = freq;
 			c->ic_flags = chanFlags |
 			    (flags &~ (REQ_FLAGS | IEEE80211_CHAN_HT40));
@@ -1855,10 +1913,12 @@ regdomain_addchans(struct ieee80211req_c
 				c->ic_maxregpower = nb->maxPowerDFS;
 			else
 				c->ic_maxregpower = nb->maxPower;
-			if (verbose)
-				printf("[%3d] add freq %u flags 0x%x power %u\n",
-				    ci->ic_nchans-1, c->ic_freq, c->ic_flags,
-				    c->ic_maxregpower);
+			if (verbose) {
+				printf("[%3d] add freq %u ",
+				    ci->ic_nchans-1, c->ic_freq);
+				printb("flags", c->ic_flags, IEEE80211_CHAN_BITS);
+				printf(" power %u\n", c->ic_maxregpower);
+			}
 			/* NB: kernel fills in other fields */
 			prev = c;
 		}
@@ -1896,30 +1956,23 @@ regdomain_makechannels(
 		errx(1, "internal error, regdomain %d not found",
 			    reg->regdomain);
 	if (rd->sku != SKU_DEBUG) {
-		memset(ci, 0, sizeof(*ci));
+		/*
+		 * regdomain_addchans incrememnts the channel count for
+		 * each channel it adds so initialize ic_nchans to zero.
+		 * Note that we know we have enough space to hold all possible
+		 * channels because the devcaps list size was used to
+		 * allocate our request.
+		 */
+		ci->ic_nchans = 0;
 		if (!LIST_EMPTY(&rd->bands_11b))
 			regdomain_addchans(ci, &rd->bands_11b, reg,
 			    IEEE80211_CHAN_B, &dc->dc_chaninfo);
-		if (!LIST_EMPTY(&rd->bands_11g)) {
+		if (!LIST_EMPTY(&rd->bands_11g))
 			regdomain_addchans(ci, &rd->bands_11g, reg,
 			    IEEE80211_CHAN_G, &dc->dc_chaninfo);
-			regdomain_addchans(ci, &rd->bands_11g, reg,
-			    IEEE80211_CHAN_G | IEEE80211_CHAN_HALF,
-			    &dc->dc_chaninfo);
-			regdomain_addchans(ci, &rd->bands_11g, reg,
-			    IEEE80211_CHAN_G | IEEE80211_CHAN_QUARTER,
-			    &dc->dc_chaninfo);
-		}
-		if (!LIST_EMPTY(&rd->bands_11a)) {
+		if (!LIST_EMPTY(&rd->bands_11a))
 			regdomain_addchans(ci, &rd->bands_11a, reg,
 			    IEEE80211_CHAN_A, &dc->dc_chaninfo);
-			regdomain_addchans(ci, &rd->bands_11a, reg,
-			    IEEE80211_CHAN_A | IEEE80211_CHAN_HALF,
-			    &dc->dc_chaninfo);
-			regdomain_addchans(ci, &rd->bands_11a, reg,
-			    IEEE80211_CHAN_A | IEEE80211_CHAN_QUARTER,
-			    &dc->dc_chaninfo);
-		}
 		if (!LIST_EMPTY(&rd->bands_11na)) {
 			regdomain_addchans(ci, &rd->bands_11na, reg,
 			    IEEE80211_CHAN_A | IEEE80211_CHAN_HT20,
@@ -1945,7 +1998,8 @@ regdomain_makechannels(
 		qsort(ci->ic_chans, ci->ic_nchans, sizeof(ci->ic_chans[0]),
 		    regdomain_sort);
 	} else
-		*ci = dc->dc_chaninfo;
+		memcpy(ci, &dc->dc_chaninfo,
+		    IEEE80211_CHANINFO_SPACE(&dc->dc_chaninfo));
 }
 
 static void
@@ -3065,23 +3119,16 @@ get_chaninfo(const struct ieee80211_chan
 	buf[0] = '\0';
 	if (IEEE80211_IS_CHAN_FHSS(c))
 		strlcat(buf, " FHSS", bsize);
-	if (IEEE80211_IS_CHAN_A(c)) {
-		if (IEEE80211_IS_CHAN_HALF(c))
-			strlcat(buf, " 11a/10Mhz", bsize);
-		else if (IEEE80211_IS_CHAN_QUARTER(c))
-			strlcat(buf, " 11a/5Mhz", bsize);
-		else
-			strlcat(buf, " 11a", bsize);
-	}
-	if (IEEE80211_IS_CHAN_ANYG(c)) {
-		if (IEEE80211_IS_CHAN_HALF(c))
-			strlcat(buf, " 11g/10Mhz", bsize);
-		else if (IEEE80211_IS_CHAN_QUARTER(c))
-			strlcat(buf, " 11g/5Mhz", bsize);
-		else
-			strlcat(buf, " 11g", bsize);
-	} else if (IEEE80211_IS_CHAN_B(c))
+	if (IEEE80211_IS_CHAN_A(c))
+		strlcat(buf, " 11a", bsize);
+	else if (IEEE80211_IS_CHAN_ANYG(c))
+		strlcat(buf, " 11g", bsize);
+	else if (IEEE80211_IS_CHAN_B(c))
 		strlcat(buf, " 11b", bsize);
+	if (IEEE80211_IS_CHAN_HALF(c))
+		strlcat(buf, "/10Mhz", bsize);
+	if (IEEE80211_IS_CHAN_QUARTER(c))
+		strlcat(buf, "/5Mhz", bsize);
 	if (IEEE80211_IS_CHAN_TURBO(c))
 		strlcat(buf, " Turbo", bsize);
 	if (precise) {
@@ -3109,23 +3156,49 @@ print_chaninfo(const struct ieee80211_ch
 		get_chaninfo(c, verb, buf, sizeof(buf)));
 }
 
+static int
+chanpref(const struct ieee80211_channel *c)
+{
+	if (IEEE80211_IS_CHAN_HT40(c))
+		return 40;
+	if (IEEE80211_IS_CHAN_HT20(c))
+		return 30;
+	if (IEEE80211_IS_CHAN_HALF(c))
+		return 10;
+	if (IEEE80211_IS_CHAN_QUARTER(c))
+		return 5;
+	if (IEEE80211_IS_CHAN_TURBO(c))
+		return 25;
+	if (IEEE80211_IS_CHAN_A(c))
+		return 20;
+	if (IEEE80211_IS_CHAN_G(c))
+		return 20;
+	if (IEEE80211_IS_CHAN_B(c))
+		return 15;
+	if (IEEE80211_IS_CHAN_PUREG(c))
+		return 15;
+	return 0;
+}
+
 static void
 print_channels(int s, const struct ieee80211req_chaninfo *chans,
 	int allchans, int verb)
 {
-	struct ieee80211req_chaninfo achans;
+	struct ieee80211req_chaninfo *achans;
 	uint8_t reported[IEEE80211_CHAN_BYTES];
 	const struct ieee80211_channel *c;
 	int i, half;
 
-	memset(&achans, 0, sizeof(achans));
+	achans = malloc(IEEE80211_CHANINFO_SPACE(chans));
+	if (achans == NULL)
+		errx(1, "no space for active channel list");
+	achans->ic_nchans = 0;
 	memset(reported, 0, sizeof(reported));
 	if (!allchans) {
 		struct ieee80211req_chanlist active;
 
 		if (get80211(s, IEEE80211_IOC_CHANLIST, &active, sizeof(active)) < 0)
 			errx(1, "unable to get active channel list");
-		memset(&achans, 0, sizeof(achans));
 		for (i = 0; i < chans->ic_nchans; i++) {
 			c = &chans->ic_chans[i];
 			if (!isset(active.ic_channels, c->ic_ieee))
@@ -3138,9 +3211,9 @@ print_channels(int s, const struct ieee8
 			 */
 			if (isset(reported, c->ic_ieee) && !verb) {
 				/* XXX we assume duplicates are adjacent */
-				achans.ic_chans[achans.ic_nchans-1] = *c;
+				achans->ic_chans[achans->ic_nchans-1] = *c;
 			} else {
-				achans.ic_chans[achans.ic_nchans++] = *c;
+				achans->ic_chans[achans->ic_nchans++] = *c;
 				setbit(reported, c->ic_ieee);
 			}
 		}
@@ -3150,33 +3223,37 @@ print_channels(int s, const struct ieee8
 			/* suppress duplicates as above */
 			if (isset(reported, c->ic_ieee) && !verb) {
 				/* XXX we assume duplicates are adjacent */
-				achans.ic_chans[achans.ic_nchans-1] = *c;
+				struct ieee80211_channel *a =
+				    &achans->ic_chans[achans->ic_nchans-1];
+				if (chanpref(c) > chanpref(a))
+					*a = *c;
 			} else {
-				achans.ic_chans[achans.ic_nchans++] = *c;
+				achans->ic_chans[achans->ic_nchans++] = *c;
 				setbit(reported, c->ic_ieee);
 			}
 		}
 	}
-	half = achans.ic_nchans / 2;
-	if (achans.ic_nchans % 2)
+	half = achans->ic_nchans / 2;
+	if (achans->ic_nchans % 2)
 		half++;
 
-	for (i = 0; i < achans.ic_nchans / 2; i++) {
-		print_chaninfo(&achans.ic_chans[i], verb);
-		print_chaninfo(&achans.ic_chans[half+i], verb);
+	for (i = 0; i < achans->ic_nchans / 2; i++) {
+		print_chaninfo(&achans->ic_chans[i], verb);
+		print_chaninfo(&achans->ic_chans[half+i], verb);
 		printf("\n");
 	}
-	if (achans.ic_nchans % 2) {
-		print_chaninfo(&achans.ic_chans[i], verb);
+	if (achans->ic_nchans % 2) {
+		print_chaninfo(&achans->ic_chans[i], verb);
 		printf("\n");
 	}
+	free(achans);
 }
 
 static void
 list_channels(int s, int allchans)
 {
 	getchaninfo(s);
-	print_channels(s, &chaninfo, allchans, verbose);
+	print_channels(s, chaninfo, allchans, verbose);
 }
 
 static void
@@ -3201,48 +3278,52 @@ print_txpow_verbose(const struct ieee802
 static void
 list_txpow(int s)
 {
-	struct ieee80211req_chaninfo achans;
+	struct ieee80211req_chaninfo *achans;
 	uint8_t reported[IEEE80211_CHAN_BYTES];
 	struct ieee80211_channel *c, *prev;
 	int i, half;
 
 	getchaninfo(s);
-	memset(&achans, 0, sizeof(achans));
+	achans = malloc(IEEE80211_CHANINFO_SPACE(chaninfo));
+	if (achans == NULL)
+		errx(1, "no space for active channel list");
+	achans->ic_nchans = 0;
 	memset(reported, 0, sizeof(reported));
-	for (i = 0; i < chaninfo.ic_nchans; i++) {
-		c = &chaninfo.ic_chans[i];
+	for (i = 0; i < chaninfo->ic_nchans; i++) {
+		c = &chaninfo->ic_chans[i];
 		/* suppress duplicates as above */
 		if (isset(reported, c->ic_ieee) && !verbose) {
 			/* XXX we assume duplicates are adjacent */
-			prev = &achans.ic_chans[achans.ic_nchans-1];
+			prev = &achans->ic_chans[achans->ic_nchans-1];
 			/* display highest power on channel */
 			if (c->ic_maxpower > prev->ic_maxpower)
 				*prev = *c;
 		} else {
-			achans.ic_chans[achans.ic_nchans++] = *c;
+			achans->ic_chans[achans->ic_nchans++] = *c;
 			setbit(reported, c->ic_ieee);
 		}
 	}
 	if (!verbose) {
-		half = achans.ic_nchans / 2;
-		if (achans.ic_nchans % 2)
+		half = achans->ic_nchans / 2;
+		if (achans->ic_nchans % 2)
 			half++;
 
-		for (i = 0; i < achans.ic_nchans / 2; i++) {
-			print_txpow(&achans.ic_chans[i]);
-			print_txpow(&achans.ic_chans[half+i]);
+		for (i = 0; i < achans->ic_nchans / 2; i++) {
+			print_txpow(&achans->ic_chans[i]);
+			print_txpow(&achans->ic_chans[half+i]);
 			printf("\n");
 		}
-		if (achans.ic_nchans % 2) {
-			print_txpow(&achans.ic_chans[i]);
+		if (achans->ic_nchans % 2) {
+			print_txpow(&achans->ic_chans[i]);
 			printf("\n");
 		}
 	} else {
-		for (i = 0; i < achans.ic_nchans; i++) {
-			print_txpow_verbose(&achans.ic_chans[i]);
+		for (i = 0; i < achans->ic_nchans; i++) {
+			print_txpow_verbose(&achans->ic_chans[i]);
 			printf("\n");
 		}
 	}
+	free(achans);
 }
 
 static void
@@ -3256,29 +3337,34 @@ list_keys(int s)
 	"\21MONITOR\22DFS\30WPA1\31WPA2\32BURST\33WME\34WDS\36BGSCAN" \
 	"\37TXFRAG\40TDMA"
 
-#define	IEEE80211_CRYPTO_BITS \
-	"\20\1WEP\2TKIP\3AES\4AES_CCM\5TKIPMIC\6CKIP\12PMGT"
-
-#define	IEEE80211_HTCAP_BITS \
-	"\20\1LDPC\2CHWIDTH40\5GREENFIELD\6SHORTGI20\7SHORTGI40\10TXSTBC" \
-	"\21AMPDU\22AMSDU\23HT"
-
 static void
 list_capabilities(int s)
 {
-	struct ieee80211_devcaps_req dc;
+	struct ieee80211_devcaps_req *dc;
 
-	getdevcaps(s, &dc);
-	printb("drivercaps", dc.dc_drivercaps, IEEE80211_C_BITS);
-	if (dc.dc_cryptocaps != 0 || verbose) {
+	if (verbose)
+		dc = malloc(IEEE80211_DEVCAPS_SIZE(MAXCHAN));
+	else
+		dc = malloc(IEEE80211_DEVCAPS_SIZE(1));
+	if (dc == NULL)
+		errx(1, "no space for device capabilities");
+	dc->dc_chaninfo.ic_nchans = verbose ? MAXCHAN : 1;
+	getdevcaps(s, dc);
+	printb("drivercaps", dc->dc_drivercaps, IEEE80211_C_BITS);
+	if (dc->dc_cryptocaps != 0 || verbose) {
 		putchar('\n');
-		printb("cryptocaps", dc.dc_cryptocaps, IEEE80211_CRYPTO_BITS);
+		printb("cryptocaps", dc->dc_cryptocaps, IEEE80211_CRYPTO_BITS);
 	}
-	if (dc.dc_htcaps != 0 || verbose) {
+	if (dc->dc_htcaps != 0 || verbose) {
 		putchar('\n');
-		printb("htcaps", dc.dc_htcaps, IEEE80211_HTCAP_BITS);
+		printb("htcaps", dc->dc_htcaps, IEEE80211_HTCAP_BITS);
 	}
 	putchar('\n');
+	if (verbose) {
+		chaninfo = &dc->dc_chaninfo;	/* XXX */
+		print_channels(s, &dc->dc_chaninfo, 1/*allchans*/, verbose);
+	}
+	free(dc);
 }
 
 static int
@@ -3557,7 +3643,7 @@ list_regdomain(int s, int channelsalso)
 		spacer = ':';
 		print_regdomain(&regdomain, 1);
 		LINE_BREAK();
-		print_channels(s, &chaninfo, 1/*allchans*/, 1/*verbose*/);
+		print_channels(s, chaninfo, 1/*allchans*/, 1/*verbose*/);
 	} else
 		print_regdomain(&regdomain, verbose);
 }
@@ -4369,6 +4455,7 @@ get80211len(int s, int type, void *data,
 	(void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
 	ireq.i_type = type;
 	ireq.i_len = len;
+	assert(ireq.i_len == len);	/* NB: check for 16-bit truncation */
 	ireq.i_data = data;
 	if (ioctl(s, SIOCG80211, &ireq) < 0)
 		return -1;
@@ -4400,6 +4487,7 @@ set80211(int s, int type, int val, int l
 	ireq.i_type = type;
 	ireq.i_val = val;
 	ireq.i_len = len;
+	assert(ireq.i_len == len);	/* NB: check for 16-bit truncation */
 	ireq.i_data = data;
 	if (ioctl(s, SIOCS80211, &ireq) < 0)
 		err(1, "SIOCS80211");



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