svn commit: r298812 - head/sys/net80211

Andriy Voskoboinyk avos at FreeBSD.org
Fri Apr 29 21:18:15 UTC 2016


Author: avos
Date: Fri Apr 29 21:18:14 2016
New Revision: 298812
URL: https://svnweb.freebsd.org/changeset/base/298812

Log:
  net80211: provide a set of ieee80211_add_channel*() functions
  
  This change adds few methods for net80211 channel table setup:
  
  - ieee80211_add_channel()
  - ieee80211_add_channel_ht40()
  (primarily for drivers, that parse EEPROM to get channel list -
  they will allow to hide implementation details).
  
  - ieee80211_add_channel_list_2ghz()
  - ieee80211_add_channel_list_5ghz()
  (mostly as a replacement for ieee80211_init_channels() - they will allow
  to specify non-default channel list; may be used in ic_getradiocaps()).
  
  Tested with wpi(4) (add_channel) and rum(4) (add_channel_list_2ghz).
  
  Reviewed by:	adrian
  Differential Revision:	https://reviews.freebsd.org/D6124

Modified:
  head/sys/net80211/ieee80211.c
  head/sys/net80211/ieee80211_regdomain.c
  head/sys/net80211/ieee80211_var.h

Modified: head/sys/net80211/ieee80211.c
==============================================================================
--- head/sys/net80211/ieee80211.c	Fri Apr 29 21:11:31 2016	(r298811)
+++ head/sys/net80211/ieee80211.c	Fri Apr 29 21:18:14 2016	(r298812)
@@ -970,6 +970,261 @@ ieee80211_ieee2mhz(u_int chan, u_int fla
 	}
 }
 
+static __inline void
+set_extchan(struct ieee80211_channel *c)
+{
+
+	/*
+	 * IEEE Std 802.11-2012, page 1738, subclause 20.3.15.4:
+	 * "the secondary channel number shall be 'N + [1,-1] * 4'
+	 */
+	if (c->ic_flags & IEEE80211_CHAN_HT40U)
+		c->ic_extieee = c->ic_ieee + 4;
+	else if (c->ic_flags & IEEE80211_CHAN_HT40D)
+		c->ic_extieee = c->ic_ieee - 4;
+	else
+		c->ic_extieee = 0;
+}
+
+static int
+addchan(struct ieee80211_channel chans[], int maxchans, int *nchans,
+    uint8_t ieee, uint16_t freq, int8_t maxregpower, uint32_t flags)
+{
+	struct ieee80211_channel *c;
+
+	if (*nchans >= maxchans)
+		return (ENOBUFS);
+
+	c = &chans[(*nchans)++];
+	c->ic_ieee = ieee;
+	c->ic_freq = freq != 0 ? freq : ieee80211_ieee2mhz(ieee, flags);
+	c->ic_maxregpower = maxregpower;
+	c->ic_maxpower = 2 * maxregpower;
+	c->ic_flags = flags;
+	set_extchan(c);
+
+	return (0);
+}
+
+static int
+copychan_prev(struct ieee80211_channel chans[], int maxchans, int *nchans,
+    uint32_t flags)
+{
+	struct ieee80211_channel *c;
+
+	KASSERT(*nchans > 0, ("channel list is empty\n"));
+
+	if (*nchans >= maxchans)
+		return (ENOBUFS);
+
+	c = &chans[(*nchans)++];
+	c[0] = c[-1];
+	c->ic_flags = flags;
+	set_extchan(c);
+
+	return (0);
+}
+
+static void
+getflags_2ghz(const uint8_t bands[], uint32_t flags[], int ht40)
+{
+	int nmodes;
+
+	nmodes = 0;
+	if (isset(bands, IEEE80211_MODE_11B))
+		flags[nmodes++] = IEEE80211_CHAN_B;
+	if (isset(bands, IEEE80211_MODE_11G))
+		flags[nmodes++] = IEEE80211_CHAN_G;
+	if (isset(bands, IEEE80211_MODE_11NG))
+		flags[nmodes++] = IEEE80211_CHAN_G | IEEE80211_CHAN_HT20;
+	if (ht40) {
+		flags[nmodes++] = IEEE80211_CHAN_G | IEEE80211_CHAN_HT40U;
+		flags[nmodes++] = IEEE80211_CHAN_G | IEEE80211_CHAN_HT40D;
+	}
+	flags[nmodes] = 0;
+}
+
+static void
+getflags_5ghz(const uint8_t bands[], uint32_t flags[], int ht40)
+{
+	int nmodes;
+
+	nmodes = 0;
+	if (isset(bands, IEEE80211_MODE_11A))
+		flags[nmodes++] = IEEE80211_CHAN_A;
+	if (isset(bands, IEEE80211_MODE_11NA))
+		flags[nmodes++] = IEEE80211_CHAN_A | IEEE80211_CHAN_HT20;
+	if (ht40) {
+		flags[nmodes++] = IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U;
+		flags[nmodes++] = IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D;
+	}
+	flags[nmodes] = 0;
+}
+
+static void
+getflags(const uint8_t bands[], uint32_t flags[], int ht40)
+{
+
+	flags[0] = 0;
+	if (isset(bands, IEEE80211_MODE_11A) ||
+	    isset(bands, IEEE80211_MODE_11NA)) {
+		if (isset(bands, IEEE80211_MODE_11B) ||
+		    isset(bands, IEEE80211_MODE_11G) ||
+		    isset(bands, IEEE80211_MODE_11NG))
+			return;
+
+		getflags_5ghz(bands, flags, ht40);
+	} else
+		getflags_2ghz(bands, flags, ht40);
+}
+
+/*
+ * Add one 20 MHz channel into specified channel list.
+ */
+int
+ieee80211_add_channel(struct ieee80211_channel chans[], int maxchans,
+    int *nchans, uint8_t ieee, uint16_t freq, int8_t maxregpower,
+    uint32_t chan_flags, const uint8_t bands[])
+{
+	uint32_t flags[IEEE80211_MODE_MAX];
+	int i, error;
+
+	getflags(bands, flags, 0);
+	KASSERT(flags[0] != 0, ("%s: no correct mode provided\n", __func__));
+
+	error = addchan(chans, maxchans, nchans, ieee, freq, maxregpower,
+	    flags[0] | chan_flags);
+	for (i = 1; flags[i] != 0 && error == 0; i++) {
+		error = copychan_prev(chans, maxchans, nchans,
+		    flags[i] | chan_flags);
+	}
+
+	return (error);
+}
+
+static struct ieee80211_channel *
+findchannel(struct ieee80211_channel chans[], int nchans, uint16_t freq,
+    uint32_t flags)
+{
+	struct ieee80211_channel *c;
+	int i;
+
+	flags &= IEEE80211_CHAN_ALLTURBO;
+	/* brute force search */
+	for (i = 0; i < nchans; i++) {
+		c = &chans[i];
+		if (c->ic_freq == freq &&
+		    (c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags)
+			return c;
+	}
+	return NULL;
+}
+
+/*
+ * Add 40 MHz channel pair into specified channel list.
+ */
+int
+ieee80211_add_channel_ht40(struct ieee80211_channel chans[], int maxchans,
+    int *nchans, uint8_t ieee, int8_t maxregpower, uint32_t flags)
+{
+	struct ieee80211_channel *cent, *extc;
+	uint16_t freq;
+	int error;
+
+	freq = ieee80211_ieee2mhz(ieee, flags);
+
+	/*
+	 * Each entry defines an HT40 channel pair; find the
+	 * center channel, then the extension channel above.
+	 */
+	flags |= IEEE80211_CHAN_HT20;
+	cent = findchannel(chans, *nchans, freq, flags);
+	if (cent == NULL)
+		return (EINVAL);
+
+	extc = findchannel(chans, *nchans, freq + 20, flags);
+	if (extc == NULL)
+		return (ENOENT);
+
+	flags &= ~IEEE80211_CHAN_HT;
+	error = addchan(chans, maxchans, nchans, cent->ic_ieee, cent->ic_freq,
+	    maxregpower, flags | IEEE80211_CHAN_HT40U);
+	if (error != 0)
+		return (error);
+
+	error = addchan(chans, maxchans, nchans, extc->ic_ieee, extc->ic_freq,
+	    maxregpower, flags | IEEE80211_CHAN_HT40D);
+
+	return (error);
+}
+
+/*
+ * Adds channels into specified channel list (ieee[] array must be sorted).
+ * Channels are already sorted.
+ */
+static int
+add_chanlist(struct ieee80211_channel chans[], int maxchans, int *nchans,
+    const uint8_t ieee[], int nieee, uint32_t flags[])
+{
+	uint16_t freq;
+	int i, j, error;
+
+	for (i = 0; i < nieee; i++) {
+		freq = ieee80211_ieee2mhz(ieee[i], flags[0]);
+		for (j = 0; flags[j] != 0; j++) {
+			if (flags[j] & IEEE80211_CHAN_HT40D)
+				if (i == 0 || ieee[i] < ieee[0] + 4 ||
+				    freq - 20 !=
+				    ieee80211_ieee2mhz(ieee[i] - 4, flags[j]))
+					continue;
+			if (flags[j] & IEEE80211_CHAN_HT40U)
+				if (i == nieee - 1 ||
+				    ieee[i] + 4 > ieee[nieee - 1] ||
+				    freq + 20 !=
+				    ieee80211_ieee2mhz(ieee[i] + 4, flags[j]))
+					continue;
+
+			if (j == 0) {
+				error = addchan(chans, maxchans, nchans,
+				    ieee[i], freq, 0, flags[j]);
+			} else {
+				error = copychan_prev(chans, maxchans, nchans,
+				    flags[j]);
+			}
+			if (error != 0)
+				return (error);
+		}
+	}
+
+	return (error);
+}
+
+int
+ieee80211_add_channel_list_2ghz(struct ieee80211_channel chans[], int maxchans,
+    int *nchans, const uint8_t ieee[], int nieee, const uint8_t bands[],
+    int ht40)
+{
+	uint32_t flags[IEEE80211_MODE_MAX];
+
+	getflags_2ghz(bands, flags, ht40);
+	KASSERT(flags[0] != 0, ("%s: no correct mode provided\n", __func__));
+
+	return (add_chanlist(chans, maxchans, nchans, ieee, nieee, flags));
+}
+
+int
+ieee80211_add_channel_list_5ghz(struct ieee80211_channel chans[], int maxchans,
+    int *nchans, const uint8_t ieee[], int nieee, const uint8_t bands[],
+    int ht40)
+{
+	uint32_t flags[IEEE80211_MODE_MAX];
+
+	getflags_5ghz(bands, flags, ht40);
+	KASSERT(flags[0] != 0, ("%s: no correct mode provided\n", __func__));
+
+	return (add_chanlist(chans, maxchans, nchans, ieee, nieee, flags));
+}
+
 /*
  * Locate a channel given a frequency+flags.  We cache
  * the previous lookup to optimize switching between two
@@ -979,7 +1234,6 @@ struct ieee80211_channel *
 ieee80211_find_channel(struct ieee80211com *ic, int freq, int flags)
 {
 	struct ieee80211_channel *c;
-	int i;
 
 	flags &= IEEE80211_CHAN_ALLTURBO;
 	c = ic->ic_prevchan;
@@ -987,13 +1241,7 @@ ieee80211_find_channel(struct ieee80211c
 	    (c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags)
 		return c;
 	/* brute force search */
-	for (i = 0; i < ic->ic_nchans; i++) {
-		c = &ic->ic_channels[i];
-		if (c->ic_freq == freq &&
-		    (c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags)
-			return c;
-	}
-	return NULL;
+	return (findchannel(ic->ic_channels, ic->ic_nchans, freq, flags));
 }
 
 /*

Modified: head/sys/net80211/ieee80211_regdomain.c
==============================================================================
--- head/sys/net80211/ieee80211_regdomain.c	Fri Apr 29 21:11:31 2016	(r298811)
+++ head/sys/net80211/ieee80211_regdomain.c	Fri Apr 29 21:18:14 2016	(r298812)
@@ -98,22 +98,14 @@ ieee80211_regdomain_vdetach(struct ieee8
 {
 }
 
-static void
-addchan(struct ieee80211com *ic, int ieee, int flags)
-{
-	struct ieee80211_channel *c;
-
-	c = &ic->ic_channels[ic->ic_nchans++];
-	c->ic_freq = ieee80211_ieee2mhz(ieee, flags);
-	c->ic_ieee = ieee;
-	c->ic_flags = flags;
-	if (flags & IEEE80211_CHAN_HT40U)
-		c->ic_extieee = ieee + 4;
-	else if (flags & IEEE80211_CHAN_HT40D)
-		c->ic_extieee = ieee - 4;
-	else
-		c->ic_extieee = 0;
-}
+static const uint8_t def_chan_2ghz[] =
+    { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 };
+static const uint8_t def_chan_5ghz_band1[] =
+    { 36, 40, 44, 48, 52, 56, 60, 64 };
+static const uint8_t def_chan_5ghz_band2[] =
+    { 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 };
+static const uint8_t def_chan_5ghz_band3[] =
+    { 149, 153, 157, 161 };
 
 /*
  * Setup the channel list for the specified regulatory domain,
@@ -125,82 +117,34 @@ int
 ieee80211_init_channels(struct ieee80211com *ic,
 	const struct ieee80211_regdomain *rd, const uint8_t bands[])
 {
-	int i;
+	struct ieee80211_channel *chans = ic->ic_channels;
+	int *nchans = &ic->ic_nchans;
+	int ht40;
 
 	/* XXX just do something for now */
-	ic->ic_nchans = 0;
+	ht40 = !!(ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40);
+	*nchans = 0;
 	if (isset(bands, IEEE80211_MODE_11B) ||
 	    isset(bands, IEEE80211_MODE_11G) ||
 	    isset(bands, IEEE80211_MODE_11NG)) {
-		int maxchan = 11;
-		if (rd != NULL && rd->ecm)
-			maxchan = 14;
-		for (i = 1; i <= maxchan; i++) {
-			if (isset(bands, IEEE80211_MODE_11B))
-				addchan(ic, i, IEEE80211_CHAN_B);
-			if (isset(bands, IEEE80211_MODE_11G))
-				addchan(ic, i, IEEE80211_CHAN_G);
-			if (isset(bands, IEEE80211_MODE_11NG)) {
-				addchan(ic, i,
-				    IEEE80211_CHAN_G | IEEE80211_CHAN_HT20);
-			}
-			if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) == 0)
-				continue;
-			if (i <= 7) {
-				addchan(ic, i,
-				    IEEE80211_CHAN_G | IEEE80211_CHAN_HT40U);
-				addchan(ic, i + 4,
-				    IEEE80211_CHAN_G | IEEE80211_CHAN_HT40D);
-			}
-		}
+		int nchan = nitems(def_chan_2ghz);
+		if (!(rd != NULL && rd->ecm))
+			nchan -= 3;
+
+		ieee80211_add_channel_list_2ghz(chans, IEEE80211_CHAN_MAX,
+		    nchans, def_chan_2ghz, nchan, bands, ht40);
 	}
 	if (isset(bands, IEEE80211_MODE_11A) ||
 	    isset(bands, IEEE80211_MODE_11NA)) {
-		for (i = 36; i <= 64; i += 4) {
-			addchan(ic, i, IEEE80211_CHAN_A);
-			if (isset(bands, IEEE80211_MODE_11NA)) {
-				addchan(ic, i,
-				    IEEE80211_CHAN_A | IEEE80211_CHAN_HT20);
-			}
-			if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) == 0)
-				continue;
-			if ((i % 8) == 4) {
-				addchan(ic, i,
-				    IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U);
-				addchan(ic, i + 4,
-				    IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D);
-			}
-		}
-		for (i = 100; i <= 140; i += 4) {
-			addchan(ic, i, IEEE80211_CHAN_A);
-			if (isset(bands, IEEE80211_MODE_11NA)) {
-				addchan(ic, i,
-				    IEEE80211_CHAN_A | IEEE80211_CHAN_HT20);
-			}
-			if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) == 0)
-				continue;
-			if ((i % 8) == 4 && i != 140) {
-				addchan(ic, i,
-				    IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U);
-				addchan(ic, i + 4,
-				    IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D);
-			}
-		}
-		for (i = 149; i <= 161; i += 4) {
-			addchan(ic, i, IEEE80211_CHAN_A);
-			if (isset(bands, IEEE80211_MODE_11NA)) {
-				addchan(ic, i,
-				    IEEE80211_CHAN_A | IEEE80211_CHAN_HT20);
-			}
-			if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) == 0)
-				continue;
-			if ((i % 8) == 5) {
-				addchan(ic, i,
-				    IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U);
-				addchan(ic, i + 4,
-				    IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D);
-			}
-		}
+		ieee80211_add_channel_list_5ghz(chans, IEEE80211_CHAN_MAX,
+		    nchans, def_chan_5ghz_band1, nitems(def_chan_5ghz_band1),
+		    bands, ht40);
+		ieee80211_add_channel_list_5ghz(chans, IEEE80211_CHAN_MAX,
+		    nchans, def_chan_5ghz_band2, nitems(def_chan_5ghz_band2),
+		    bands, ht40);
+		ieee80211_add_channel_list_5ghz(chans, IEEE80211_CHAN_MAX,
+		    nchans, def_chan_5ghz_band3, nitems(def_chan_5ghz_band3),
+		    bands, ht40);
 	}
 	if (rd != NULL)
 		ic->ic_regdomain = *rd;

Modified: head/sys/net80211/ieee80211_var.h
==============================================================================
--- head/sys/net80211/ieee80211_var.h	Fri Apr 29 21:11:31 2016	(r298811)
+++ head/sys/net80211/ieee80211_var.h	Fri Apr 29 21:18:14 2016	(r298812)
@@ -723,6 +723,14 @@ int	ieee80211_mhz2ieee(u_int, u_int);
 int	ieee80211_chan2ieee(struct ieee80211com *,
 		const struct ieee80211_channel *);
 u_int	ieee80211_ieee2mhz(u_int, u_int);
+int	ieee80211_add_channel(struct ieee80211_channel[], int, int *,
+	    uint8_t, uint16_t, int8_t, uint32_t, const uint8_t[]);
+int	ieee80211_add_channel_ht40(struct ieee80211_channel[], int, int *,
+	    uint8_t, int8_t, uint32_t);
+int	ieee80211_add_channel_list_2ghz(struct ieee80211_channel[], int, int *,
+	    const uint8_t[], int, const uint8_t[], int);
+int	ieee80211_add_channel_list_5ghz(struct ieee80211_channel[], int, int *,
+	    const uint8_t[], int, const uint8_t[], int);
 struct ieee80211_channel *ieee80211_find_channel(struct ieee80211com *,
 		int freq, int flags);
 struct ieee80211_channel *ieee80211_find_channel_byieee(struct ieee80211com *,


More information about the svn-src-all mailing list