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 *,
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to