summaryrefslogtreecommitdiffstats
path: root/sbin
diff options
context:
space:
mode:
authorsam <sam@FreeBSD.org>2007-06-11 03:56:33 +0000
committersam <sam@FreeBSD.org>2007-06-11 03:56:33 +0000
commit3271b465acb86d1da777c15e67a67ea952a8ddb8 (patch)
tree3f4d188c2835a1c8b666ae901a5cbc04c97e52f9 /sbin
parent6a8b18f11591df29764d02a686661d87559bf7f6 (diff)
downloadFreeBSD-src-3271b465acb86d1da777c15e67a67ea952a8ddb8.zip
FreeBSD-src-3271b465acb86d1da777c15e67a67ea952a8ddb8.tar.gz
Update for revised 802.11 support:
o revised channel handling support; ifconfig now queries the kernel to find the list of available channels and handles channel promotion; channel attributes can be specified as part of the channel; e.g. 36:a for channel 36 in 11a (as opposed to turbo A or HT A) o use channel list to map between freq and IEEE channel #; this eliminates all knowledge of how the mapping is done and fixes handling of cases where channels overlap in the IEEE channel # space but are distinct in the frequency+attributes space (e.g. PSB) o add new knobs: bgscan, ff (Atheors fast frames), dturbo (Atheros Dynamic Turbo mode), bgscanidle, bgscanintvl, scanvalid, roam:rssi11a, roam:rssi11b, roam:rssi11g, roam:rate11a, roam:rate11b, roam:rate11g (roaming parameters), burst, doth (forthcoming 11h support) o print contents of WME, ATH, WPA, RSN, information elements with -v option o print signal strength in dBm o print noise floor in dBm o add list txpow to print tx power caps/channel o change default channel display in status to be more informative
Diffstat (limited to 'sbin')
-rw-r--r--sbin/ifconfig/ifconfig.847
-rw-r--r--sbin/ifconfig/ifconfig.h6
-rw-r--r--sbin/ifconfig/ifieee80211.c1065
-rw-r--r--sbin/ifconfig/ifmedia.c12
4 files changed, 959 insertions, 171 deletions
diff --git a/sbin/ifconfig/ifconfig.8 b/sbin/ifconfig/ifconfig.8
index 9222ec6..5613518 100644
--- a/sbin/ifconfig/ifconfig.8
+++ b/sbin/ifconfig/ifconfig.8
@@ -597,7 +597,7 @@ Set the interval at which beacon frames are sent when operating in
ad-hoc or ap mode.
The
.Ar interval
-parameter is specified in TU's (1/1024 msecs).
+parameter is specified in TU's (1024 usecs).
By default beacon frames are transmitted every 100 TU's.
.It Cm bmissthreshold Ar count
Set the number of consecutive missed beacons at which the station
@@ -664,6 +664,48 @@ Some
adaptors ignore this setting unless you are in ad-hoc mode.
Alternatively the frequency, in megahertz, may be specified
instead of the channel number.
+.Pp
+When there are several ways to use a channel the channel
+number/frequency may be appended with attributes to clarify.
+For example, if a device is capable of operating on channel 6
+with 802.11n and 802.11g then one can specify that g-only use
+should be used by specifying ``6:g''.
+Similarly the channel width can be specified by appending it
+with ``/''; e.g. ``6/40'' specifies a 40MHz wide channel,
+These attributes can be combined as in: ``6:ht/40''.
+The full set of flags specified following a `:'' are:
+.Cm a
+(802.11a),
+.Cm b
+(802.11b),
+.Cm d
+(Atheros Dynamic Turbo mode),
+.Cm g
+(802.11g),
+.Cm h
+or
+.Cm n
+(802.11n aka HT),
+.Cm s
+(Atheros Static Turbo mode),
+and
+.Cm t
+(Atheros Dynamic Turbo mode, or appendeded to ``st'' and ``dt'').
+The full set of channel widths following a '/' are:
+.Cm 5
+(5MHz aka quarter-rate channel),
+.Cm 10
+(10MHz aka half-rate channel),
+.Cm 20
+(20MHz mostly for use in specifying ht20),
+and
+.Cm 40
+(40MHz mostly for use in specifying ht40),
+In addition,
+a 40MHz HT channel specification may include the location
+of the extension channel by appending ``+'' or ``-'' for above and below,
+respectively; e.g. ``2437:ht/40+'' specifies 40MHz wide HT operation
+with the center channel at frequency 2437 and the extension channel above.
.It Cm deftxkey Ar index
Set the default key to use for transmission.
Typically this is only set when using WEP encryption.
@@ -815,7 +857,8 @@ Use
.Fl powersave
to disable powersave operation.
.It Cm powersavesleep Ar sleep
-Set the desired max powersave sleep time in milliseconds.
+Set the desired max powersave sleep time in TU's (1024 usecs).
+By default the max powersave sleep time is 100 TU's.
.It Cm protmode Ar technique
For interfaces operating in 802.11g, use the specified
.Ar technique
diff --git a/sbin/ifconfig/ifconfig.h b/sbin/ifconfig/ifconfig.h
index ef7cec5..d14d240 100644
--- a/sbin/ifconfig/ifconfig.h
+++ b/sbin/ifconfig/ifconfig.h
@@ -140,3 +140,9 @@ void ifmaybeload(const char *name);
typedef void clone_callback_func(int, struct ifreq *);
void clone_setcallback(clone_callback_func *);
+
+/*
+ * XXX expose this so modules that neeed to know of any pending
+ * operations on ifmedia can avoid cmd line ordering confusion.
+ */
+struct ifmediareq *ifmedia_getstate(int s);
diff --git a/sbin/ifconfig/ifieee80211.c b/sbin/ifconfig/ifieee80211.c
index a3e531c..f09e733 100644
--- a/sbin/ifconfig/ifieee80211.c
+++ b/sbin/ifconfig/ifieee80211.c
@@ -94,11 +94,167 @@
#include "ifconfig.h"
-static void set80211(int s, int type, int val, int len, u_int8_t *data);
+static void set80211(int s, int type, int val, int len, void *data);
static const char *get_string(const char *val, const char *sep,
u_int8_t *buf, int *lenp);
static void print_string(const u_int8_t *buf, int len);
+static struct ieee80211req_chaninfo chaninfo;
+static struct ifmediareq *ifmr;
+
+/*
+ * Collect channel info from the kernel. We use this (mostly)
+ * to handle mapping between frequency and IEEE channel number.
+ */
+static void
+getchaninfo(int s)
+{
+ struct ieee80211req ireq;
+
+ if (chaninfo.ic_nchans != 0)
+ return;
+ (void) memset(&ireq, 0, sizeof(ireq));
+ (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+ ireq.i_type = IEEE80211_IOC_CHANINFO;
+ ireq.i_data = &chaninfo;
+ ireq.i_len = sizeof(chaninfo);
+ if (ioctl(s, SIOCG80211, &ireq) < 0)
+ errx(1, "unable to get channel information");
+
+ ifmr = ifmedia_getstate(s);
+}
+
+/*
+ * Given the channel at index i with attributes from,
+ * check if there is a channel with attributes to in
+ * the channel table. With suitable attributes this
+ * allows the caller to look for promotion; e.g. from
+ * 11b > 11g.
+ */
+static int
+canpromote(int i, int from, int to)
+{
+ 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)
+ 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];
+ if (j != i &&
+ tc->ic_freq == fc->ic_freq && (tc->ic_flags & to) == to)
+ return j;
+ }
+ return i;
+}
+
+/*
+ * Handle channel promotion. When a channel is specified with
+ * only a frequency we want to promote it to the ``best'' channel
+ * available. The channel list has separate entries for 11b, 11g,
+ * 11a, and 11n[ga] channels so specifying a frequency w/o any
+ * attributes requires we upgrade, e.g. from 11b -> 11g. This
+ * gets complicated when the channel is specified on the same
+ * command line with a media request that constrains the available
+ * channe list (e.g. mode 11a); we want to honor that to avoid
+ * confusing behaviour.
+ */
+static int
+promote(int i)
+{
+ /*
+ * Query the current mode of the interface in case it's
+ * constrained (e.g. to 11a). We must do this carefully
+ * as there may be a pending ifmedia request in which case
+ * asking the kernel will give us the wrong answer. This
+ * is an unfortunate side-effect of the way ifconfig is
+ * structure for modularity (yech).
+ *
+ * NB: ifmr is actually setup in getchaninfo (above); we
+ * assume it's called coincident with to this call so
+ * we have a ``current setting''; otherwise we must pass
+ * the socket descriptor down to here so we can make
+ * the ifmedia_getstate call ourselves.
+ */
+ int chanmode = ifmr != NULL ? IFM_MODE(ifmr->ifm_current) : IFM_AUTO;
+
+ /* when ambiguous promote to ``best'' */
+ /* NB: we abitrarily pick HT40+ over HT40- */
+ if (chanmode != IFM_IEEE80211_11B)
+ i = canpromote(i, IEEE80211_CHAN_B, IEEE80211_CHAN_G);
+ if (chanmode != IFM_IEEE80211_11G) {
+ i = canpromote(i, IEEE80211_CHAN_G,
+ IEEE80211_CHAN_G | IEEE80211_CHAN_HT20);
+ i = canpromote(i, IEEE80211_CHAN_G,
+ IEEE80211_CHAN_G | IEEE80211_CHAN_HT40D);
+ i = canpromote(i, IEEE80211_CHAN_G,
+ IEEE80211_CHAN_G | IEEE80211_CHAN_HT40U);
+ }
+ if (chanmode != IFM_IEEE80211_11A) {
+ i = canpromote(i, IEEE80211_CHAN_A,
+ IEEE80211_CHAN_A | IEEE80211_CHAN_HT20);
+ i = canpromote(i, IEEE80211_CHAN_A,
+ IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D);
+ i = canpromote(i, IEEE80211_CHAN_A,
+ IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U);
+ }
+ return i;
+}
+
+static void
+mapfreq(struct ieee80211_channel *chan, int freq, int flags)
+{
+ int 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)];
+ }
+ *chan = *c;
+ return;
+ }
+ }
+ errx(1, "unknown/undefined frequency %u/0x%x", freq, flags);
+}
+
+static void
+mapchan(struct ieee80211_channel *chan, int ieee, int flags)
+{
+ int 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)];
+ }
+ *chan = *c;
+ return;
+ }
+ }
+ errx(1, "unknown/undefined channel number %d", ieee);
+}
+
+static int
+ieee80211_mhz2ieee(int freq, int flags)
+{
+ struct ieee80211_channel chan;
+ mapfreq(&chan, freq, flags);
+ return chan.ic_ieee;
+}
+
static int
isanyarg(const char *arg)
{
@@ -142,73 +298,140 @@ set80211stationname(const char *val, int d, int s, const struct afswtch *rafp)
}
/*
- * Convert IEEE channel number to MHz frequency.
- */
-static u_int
-ieee80211_ieee2mhz(u_int chan)
-{
- if (chan == 14)
- return 2484;
- if (chan < 14) /* 0-13 */
- return 2407 + chan*5;
- if (chan < 27) /* 15-26 */
- return 2512 + ((chan-15)*20);
- return 5000 + (chan*5);
-}
-
-static __inline int
-mapgsm(u_int freq, u_int flags)
-{
- freq *= 10;
- if (flags & IEEE80211_CHAN_QUARTER)
- freq += 5;
- else if (flags & IEEE80211_CHAN_HALF)
- freq += 10;
- else
- freq += 20;
- /* NB: there is no 907/20 wide but leave room */
- return (freq - 906*10) / 5;
-}
-
-static __inline int
-mappsb(u_int freq, u_int flags)
-{
- return 37 + ((freq * 10) + ((freq % 5) == 2 ? 5 : 0) - 49400) / 5;
-}
-
-/*
- * Convert MHz frequency to IEEE channel number.
- */
-static u_int
-ieee80211_mhz2ieee(u_int freq, u_int flags)
-{
- if ((flags & IEEE80211_CHAN_GSM) || (907 <= freq && freq <= 922))
- return mapgsm(freq, flags);
- if (freq == 2484)
- return 14;
- if (freq < 2484)
- return (freq - 2407) / 5;
- if (freq < 5000) {
- if (flags & (IEEE80211_CHAN_HALF|IEEE80211_CHAN_QUARTER))
- return mappsb(freq, flags);
- else if (freq > 4900)
- return (freq - 4000) / 5;
- else
- return 15 + ((freq - 2512) / 20);
+ * Parse a channel specification for attributes/flags.
+ * The syntax is:
+ * freq/xx channel width (5,10,20,40,40+,40-)
+ * freq:mode channel mode (a,b,g,h,n,t,s,d)
+ *
+ * These can be combined in either order; e.g. 2437:ng/40.
+ * Modes are case insensitive.
+ *
+ * The result is not validated here; it's assumed to be
+ * checked against the channel table fetched from the kernel.
+ */
+static int
+getchannelflags(const char *val)
+{
+#define CHAN_HT_DEFAULT IEEE80211_CHAN_HT40U
+#define _CHAN_HT 0x80000000
+ const char *cp;
+ int flags;
+
+ flags = 0;
+
+ cp = strchr(val, ':');
+ if (cp != NULL) {
+ for (cp++; isalpha((int) *cp); cp++) {
+ /* accept mixed case */
+ int c = *cp;
+ if (isupper(c))
+ c = tolower(c);
+ switch (c) {
+ case 'a': /* 802.11a */
+ flags |= IEEE80211_CHAN_A;
+ break;
+ case 'b': /* 802.11b */
+ flags |= IEEE80211_CHAN_B;
+ break;
+ case 'g': /* 802.11g */
+ flags |= IEEE80211_CHAN_G;
+ break;
+ case 'h': /* ht = 802.11n */
+ case 'n': /* 802.11n */
+ flags |= _CHAN_HT; /* NB: private */
+ break;
+ case 'd': /* dt = Atheros Dynamic Turbo */
+ flags |= IEEE80211_CHAN_TURBO;
+ break;
+ case 't': /* ht, dt, st, t */
+ /* dt and unadorned t specify Dynamic Turbo */
+ if ((flags & (IEEE80211_CHAN_STURBO|_CHAN_HT)) == 0)
+ flags |= IEEE80211_CHAN_TURBO;
+ break;
+ case 's': /* st = Atheros Static Turbo */
+ flags |= IEEE80211_CHAN_STURBO;
+ break;
+ default:
+ errx(-1, "%s: Invalid channel attribute %c",
+ val, *cp);
+ }
+ }
+ }
+ cp = strchr(val, '/');
+ if (cp != NULL) {
+ char *ep;
+ u_long cw = strtoul(cp+1, &ep, 10);
+
+ switch (cw) {
+ case 5:
+ flags |= IEEE80211_CHAN_QUARTER;
+ break;
+ case 10:
+ flags |= IEEE80211_CHAN_HALF;
+ break;
+ case 20:
+ /* NB: this may be removed below */
+ flags |= IEEE80211_CHAN_HT20;
+ break;
+ case 40:
+ if (ep != NULL && *ep == '+')
+ flags |= IEEE80211_CHAN_HT40U;
+ else if (ep != NULL && *ep == '-')
+ flags |= IEEE80211_CHAN_HT40D;
+ else /* NB: pick something */
+ flags |= CHAN_HT_DEFAULT;
+ break;
+ default:
+ errx(-1, "%s: Invalid channel width", val);
+ }
+ }
+ /*
+ * Cleanup specifications.
+ */
+ if ((flags & _CHAN_HT) == 0) {
+ /*
+ * If user specified freq/20 or freq/40 quietly remove
+ * HT cw attributes depending on channel use. To give
+ * an explicit 20/40 width for an HT channel you must
+ * indicate it is an HT channel since all HT channels
+ * are also usable for legacy operation; e.g. freq:n/40.
+ */
+ flags &= ~IEEE80211_CHAN_HT;
+ } else {
+ /*
+ * Remove private indicator that this is an HT channel
+ * and if no explicit channel width has been given
+ * provide the default settings.
+ */
+ flags &= ~_CHAN_HT;
+ if ((flags & IEEE80211_CHAN_HT) == 0)
+ flags |= CHAN_HT_DEFAULT;
}
- return (freq - 5000) / 5;
+ return flags;
+#undef CHAN_HT_DEFAULT
+#undef _CHAN_HT
}
static void
set80211channel(const char *val, int d, int s, const struct afswtch *rafp)
{
+ struct ieee80211_channel chan;
+
+ memset(&chan, 0, sizeof(chan));
if (!isanyarg(val)) {
int v = atoi(val);
- if (v > 255) /* treat as frequency */
- v = ieee80211_mhz2ieee(v, 0);
- set80211(s, IEEE80211_IOC_CHANNEL, v, 0, NULL);
- } else
- set80211(s, IEEE80211_IOC_CHANNEL, IEEE80211_CHAN_ANY, 0, NULL);
+ int flags = getchannelflags(val);
+
+ getchaninfo(s);
+ if (v > 255) { /* treat as frequency */
+ mapfreq(&chan, v, flags);
+ } else {
+ mapchan(&chan, v, flags);
+ }
+ } else {
+ chan.ic_freq = IEEE80211_CHAN_ANY;
+ }
+ set80211(s, IEEE80211_IOC_CURCHAN, 0, sizeof(chan), &chan);
}
static void
@@ -444,6 +667,18 @@ set80211apbridge(const char *val, int d, int s, const struct afswtch *rafp)
}
static void
+set80211fastframes(const char *val, int d, int s, const struct afswtch *rafp)
+{
+ set80211(s, IEEE80211_IOC_FF, d, 0, NULL);
+}
+
+static void
+set80211dturbo(const char *val, int d, int s, const struct afswtch *rafp)
+{
+ set80211(s, IEEE80211_IOC_TURBOP, d, 0, NULL);
+}
+
+static void
set80211chanlist(const char *val, int d, int s, const struct afswtch *rafp)
{
struct ieee80211req_chanlist chanlist;
@@ -491,8 +726,7 @@ set80211chanlist(const char *val, int d, int s, const struct afswtch *rafp)
break;
cp = tp;
}
- set80211(s, IEEE80211_IOC_CHANLIST, 0,
- sizeof(chanlist), (uint8_t *) &chanlist);
+ set80211(s, IEEE80211_IOC_CHANLIST, 0, sizeof(chanlist), &chanlist);
#undef MAXCHAN
}
@@ -676,7 +910,7 @@ DECL_CMD_FUNC(set80211kickmac, val, d)
mlme.im_op = IEEE80211_MLME_DEAUTH;
mlme.im_reason = IEEE80211_REASON_AUTH_EXPIRE;
memcpy(mlme.im_macaddr, LLADDR(&sdl), IEEE80211_ADDR_LEN);
- set80211(s, IEEE80211_IOC_MLME, 0, sizeof(mlme), (u_int8_t *) &mlme);
+ set80211(s, IEEE80211_IOC_MLME, 0, sizeof(mlme), &mlme);
}
static
@@ -692,15 +926,69 @@ set80211pureg(const char *val, int d, int s, const struct afswtch *rafp)
}
static void
-set80211burst(const char *val, int d, int s, const struct afswtch *rafp)
+set80211bgscan(const char *val, int d, int s, const struct afswtch *rafp)
{
- set80211(s, IEEE80211_IOC_BURST, d, 0, NULL);
+ set80211(s, IEEE80211_IOC_BGSCAN, d, 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211bgscanidle, val, d)
+{
+ set80211(s, IEEE80211_IOC_BGSCAN_IDLE, atoi(val), 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211bgscanintvl, val, d)
+{
+ set80211(s, IEEE80211_IOC_BGSCAN_INTERVAL, atoi(val), 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211scanvalid, val, d)
+{
+ set80211(s, IEEE80211_IOC_SCANVALID, atoi(val), 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211roamrssi11a, val, d)
+{
+ set80211(s, IEEE80211_IOC_ROAM_RSSI_11A, atoi(val), 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211roamrssi11b, val, d)
+{
+ set80211(s, IEEE80211_IOC_ROAM_RSSI_11B, atoi(val), 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211roamrssi11g, val, d)
+{
+ set80211(s, IEEE80211_IOC_ROAM_RSSI_11G, atoi(val), 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211roamrate11a, val, d)
+{
+ set80211(s, IEEE80211_IOC_ROAM_RATE_11A, 2*atoi(val), 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211roamrate11b, val, d)
+{
+ set80211(s, IEEE80211_IOC_ROAM_RATE_11B, 2*atoi(val), 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211roamrate11g, val, d)
+{
+ set80211(s, IEEE80211_IOC_ROAM_RATE_11G, 2*atoi(val), 0, NULL);
}
static
DECL_CMD_FUNC(set80211mcastrate, val, d)
{
- set80211(s, IEEE80211_IOC_MCAST_RATE, (int) 2*atof(val), 0, NULL);
+ set80211(s, IEEE80211_IOC_MCAST_RATE, 2*atoi(val), 0, NULL);
}
static
@@ -717,8 +1005,20 @@ DECL_CMD_FUNC(set80211bmissthreshold, val, d)
isundefarg(val) ? IEEE80211_HWBMISS_MAX : atoi(val), 0, NULL);
}
+static void
+set80211burst(const char *val, int d, int s, const struct afswtch *rafp)
+{
+ set80211(s, IEEE80211_IOC_BURST, d, 0, NULL);
+}
+
+static void
+set80211doth(const char *val, int d, int s, const struct afswtch *rafp)
+{
+ set80211(s, IEEE80211_IOC_DOTH, d, 0, NULL);
+}
+
static int
-getmaxrate(uint8_t rates[15], uint8_t nrates)
+getmaxrate(const uint8_t rates[15], uint8_t nrates)
{
int i, maxrate = -1;
@@ -770,6 +1070,7 @@ getflags(int flags)
#define IEEE80211_NODE_QOS 0x0002 /* QoS enabled */
#define IEEE80211_NODE_ERP 0x0004 /* ERP enabled */
#define IEEE80211_NODE_PWR_MGT 0x0010 /* power save mode enabled */
+#define IEEE80211_NODE_HT 0x0040 /* HT enabled */
static char flagstring[32];
char *cp = flagstring;
@@ -781,8 +1082,11 @@ getflags(int flags)
*cp++ = 'E';
if (flags & IEEE80211_NODE_PWR_MGT)
*cp++ = 'P';
+ if (flags & IEEE80211_NODE_HT)
+ *cp++ = 'H';
*cp = '\0';
return flagstring;
+#undef IEEE80211_NODE_HT
#undef IEEE80211_NODE_AUTH
#undef IEEE80211_NODE_QOS
#undef IEEE80211_NODE_ERP
@@ -809,6 +1113,252 @@ printie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen)
}
}
+#define LE_READ_2(p) \
+ ((u_int16_t) \
+ ((((const u_int8_t *)(p))[0] ) | \
+ (((const u_int8_t *)(p))[1] << 8)))
+#define LE_READ_4(p) \
+ ((u_int32_t) \
+ ((((const u_int8_t *)(p))[0] ) | \
+ (((const u_int8_t *)(p))[1] << 8) | \
+ (((const u_int8_t *)(p))[2] << 16) | \
+ (((const u_int8_t *)(p))[3] << 24)))
+
+/*
+ * NB: The decoding routines assume a properly formatted ie
+ * which should be safe as the kernel only retains them
+ * if they parse ok.
+ */
+
+static void
+printwmeie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
+{
+#define MS(_v, _f) (((_v) & _f) >> _f##_S)
+ static const char *acnames[] = { "BE", "BK", "VO", "VI" };
+ int i;
+
+ printf("%s", tag);
+ if (verbose) {
+ printf("<qosinfo 0x%x", ie[
+ __offsetof(struct ieee80211_wme_param, param_qosInfo)]);
+ ie += __offsetof(struct ieee80211_wme_param, params_acParams);
+ for (i = 0; i < WME_NUM_AC; i++) {
+ printf(" %s[%saifsn %u cwmin %u cwmax %u txop %u]"
+ , acnames[i]
+ , MS(ie[0], WME_PARAM_ACM) ? "acm " : ""
+ , MS(ie[0], WME_PARAM_AIFSN)
+ , MS(ie[1], WME_PARAM_LOGCWMIN)
+ , MS(ie[1], WME_PARAM_LOGCWMAX)
+ , LE_READ_2(ie+2)
+ );
+ ie += 4;
+ }
+ printf(">");
+ }
+#undef MS
+}
+
+static void
+printathie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
+{
+
+ printf("%s", tag);
+ if (verbose) {
+ const struct ieee80211_ath_ie *ath =
+ (const struct ieee80211_ath_ie *)ie;
+
+ printf("<");
+ if (ath->ath_capability & ATHEROS_CAP_TURBO_PRIME)
+ printf("DTURBO,");
+ if (ath->ath_capability & ATHEROS_CAP_COMPRESSION)
+ printf("COMP,");
+ if (ath->ath_capability & ATHEROS_CAP_FAST_FRAME)
+ printf("FF,");
+ if (ath->ath_capability & ATHEROS_CAP_XR)
+ printf("XR,");
+ if (ath->ath_capability & ATHEROS_CAP_AR)
+ printf("AR,");
+ if (ath->ath_capability & ATHEROS_CAP_BURST)
+ printf("BURST,");
+ if (ath->ath_capability & ATHEROS_CAP_WME)
+ printf("WME,");
+ if (ath->ath_capability & ATHEROS_CAP_BOOST)
+ printf("BOOST,");
+ printf("0x%x>", LE_READ_2(ath->ath_defkeyix));
+ }
+}
+
+static const char *
+wpa_cipher(const u_int8_t *sel)
+{
+#define WPA_SEL(x) (((x)<<24)|WPA_OUI)
+ u_int32_t w = LE_READ_4(sel);
+
+ switch (w) {
+ case WPA_SEL(WPA_CSE_NULL):
+ return "NONE";
+ case WPA_SEL(WPA_CSE_WEP40):
+ return "WEP40";
+ case WPA_SEL(WPA_CSE_WEP104):
+ return "WEP104";
+ case WPA_SEL(WPA_CSE_TKIP):
+ return "TKIP";
+ case WPA_SEL(WPA_CSE_CCMP):
+ return "AES-CCMP";
+ }
+ return "?"; /* NB: so 1<< is discarded */
+#undef WPA_SEL
+}
+
+static const char *
+wpa_keymgmt(const u_int8_t *sel)
+{
+#define WPA_SEL(x) (((x)<<24)|WPA_OUI)
+ u_int32_t w = LE_READ_4(sel);
+
+ switch (w) {
+ case WPA_SEL(WPA_ASE_8021X_UNSPEC):
+ return "8021X-UNSPEC";
+ case WPA_SEL(WPA_ASE_8021X_PSK):
+ return "8021X-PSK";
+ case WPA_SEL(WPA_ASE_NONE):
+ return "NONE";
+ }
+ return "?";
+#undef WPA_SEL
+}
+
+static void
+printwpaie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
+{
+ u_int8_t len = ie[1];
+
+ printf("%s", tag);
+ if (verbose) {
+ const char *sep;
+ int n;
+
+ ie += 6, len -= 4; /* NB: len is payload only */
+
+ printf("<v%u", LE_READ_2(ie));
+ ie += 2, len -= 2;
+
+ printf(" mc:%s", wpa_cipher(ie));
+ ie += 4, len -= 4;
+
+ /* unicast ciphers */
+ n = LE_READ_2(ie);
+ ie += 2, len -= 2;
+ sep = " uc:";
+ for (; n > 0; n--) {
+ printf("%s%s", sep, wpa_cipher(ie));
+ ie += 4, len -= 4;
+ sep = "+";
+ }
+
+ /* key management algorithms */
+ n = LE_READ_2(ie);
+ ie += 2, len -= 2;
+ sep = " km:";
+ for (; n > 0; n--) {
+ printf("%s%s", sep, wpa_keymgmt(ie));
+ ie += 4, len -= 4;
+ sep = "+";
+ }
+
+ if (len > 2) /* optional capabilities */
+ printf(", caps 0x%x", LE_READ_2(ie));
+ printf(">");
+ }
+}
+
+static const char *
+rsn_cipher(const u_int8_t *sel)
+{
+#define RSN_SEL(x) (((x)<<24)|RSN_OUI)
+ u_int32_t w = LE_READ_4(sel);
+
+ switch (w) {
+ case RSN_SEL(RSN_CSE_NULL):
+ return "NONE";
+ case RSN_SEL(RSN_CSE_WEP40):
+ return "WEP40";
+ case RSN_SEL(RSN_CSE_WEP104):
+ return "WEP104";
+ case RSN_SEL(RSN_CSE_TKIP):
+ return "TKIP";
+ case RSN_SEL(RSN_CSE_CCMP):
+ return "AES-CCMP";
+ case RSN_SEL(RSN_CSE_WRAP):
+ return "AES-OCB";
+ }
+ return "?";
+#undef WPA_SEL
+}
+
+static const char *
+rsn_keymgmt(const u_int8_t *sel)
+{
+#define RSN_SEL(x) (((x)<<24)|RSN_OUI)
+ u_int32_t w = LE_READ_4(sel);
+
+ switch (w) {
+ case RSN_SEL(RSN_ASE_8021X_UNSPEC):
+ return "8021X-UNSPEC";
+ case RSN_SEL(RSN_ASE_8021X_PSK):
+ return "8021X-PSK";
+ case RSN_SEL(RSN_ASE_NONE):
+ return "NONE";
+ }
+ return "?";
+#undef RSN_SEL
+}
+
+static void
+printrsnie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
+{
+ u_int8_t len = ie[1];
+
+ printf("%s", tag);
+ if (verbose) {
+ const char *sep;
+ int n;
+
+ ie += 6, len -= 4; /* NB: len is payload only */
+
+ printf("<v%u", LE_READ_2(ie));
+ ie += 2, len -= 2;
+
+ printf(" mc:%s", rsn_cipher(ie));
+ ie += 4, len -= 4;
+
+ /* unicast ciphers */
+ n = LE_READ_2(ie);
+ ie += 2, len -= 2;
+ sep = " uc:";
+ for (; n > 0; n--) {
+ printf("%s%s", sep, rsn_cipher(ie));
+ ie += 4, len -= 4;
+ sep = "+";
+ }
+
+ /* key management algorithms */
+ n = LE_READ_2(ie);
+ ie += 2, len -= 2;
+ sep = " km:";
+ for (; n > 0; n--) {
+ printf("%s%s", sep, rsn_keymgmt(ie));
+ ie += 4, len -= 4;
+ sep = "+";
+ }
+
+ if (len > 2) /* optional capabilities */
+ printf(", caps 0x%x", LE_READ_2(ie));
+ /* XXXPMKID */
+ printf(">");
+ }
+}
+
/*
* Copy the ssid string contents into buf, truncating to fit. If the
* ssid is entirely printable then just copy intact. Otherwise convert
@@ -884,16 +1434,16 @@ printies(const u_int8_t *vp, int ielen, int maxcols)
switch (vp[0]) {
case IEEE80211_ELEMID_VENDOR:
if (iswpaoui(vp))
- printie(" WPA", vp, 2+vp[1], maxcols);
+ printwpaie(" WPA", vp, 2+vp[1], maxcols);
else if (iswmeoui(vp))
- printie(" WME", vp, 2+vp[1], maxcols);
+ printwmeie(" WME", vp, 2+vp[1], maxcols);
else if (isatherosoui(vp))
- printie(" ATH", vp, 2+vp[1], maxcols);
+ printathie(" ATH", vp, 2+vp[1], maxcols);
else
printie(" VEN", vp, 2+vp[1], maxcols);
break;
case IEEE80211_ELEMID_RSN:
- printie(" RSN", vp, 2+vp[1], maxcols);
+ printrsnie(" RSN", vp, 2+vp[1], maxcols);
break;
default:
printie(" ???", vp, 2+vp[1], maxcols);
@@ -924,35 +1474,37 @@ list_scan(int s)
if (len < sizeof(struct ieee80211req_scan_result))
return;
+ getchaninfo(s);
+
ssidmax = verbose ? IEEE80211_NWID_LEN : 14;
- printf("%-*.*s %-17.17s %4s %4s %-5s %3s %4s\n"
+ printf("%-*.*s %-17.17s %4s %4s %-7s %3s %4s\n"
, ssidmax, ssidmax, "SSID"
, "BSSID"
, "CHAN"
, "RATE"
- , "S:N"
+ , " S:N"
, "INT"
, "CAPS"
);
cp = buf;
do {
- struct ieee80211req_scan_result *sr;
- uint8_t *vp;
+ const struct ieee80211req_scan_result *sr;
+ const uint8_t *vp;
- sr = (struct ieee80211req_scan_result *) cp;
- vp = (u_int8_t *)(sr+1);
- printf("%-*.*s %s %3d %3dM %2d:%-2d %3d %-4.4s"
+ sr = (const struct ieee80211req_scan_result *) cp;
+ vp = ((const u_int8_t *)sr) + sr->isr_ie_off;
+ printf("%-*.*s %s %3d %3dM %3d:%-3d %3d %-4.4s"
, ssidmax
, copy_essid(ssid, ssidmax, vp, sr->isr_ssid_len)
, ssid
, ether_ntoa((const struct ether_addr *) sr->isr_bssid)
, ieee80211_mhz2ieee(sr->isr_freq, sr->isr_flags)
, getmaxrate(sr->isr_rates, sr->isr_nrates)
- , sr->isr_rssi, sr->isr_noise
+ , (sr->isr_rssi/2)+sr->isr_noise, sr->isr_noise
, sr->isr_intval
, getcaps(sr->isr_capinfo)
);
- printies(vp + sr->isr_ssid_len, sr->isr_ie_len, 24);;
+ printies(vp + sr->isr_ssid_len, sr->isr_ie_len, 24);
printf("\n");
cp += sr->isr_len, len -= sr->isr_len;
} while (len >= sizeof(struct ieee80211req_scan_result));
@@ -1013,7 +1565,7 @@ list_stations(int s)
} u;
enum ieee80211_opmode opmode = get80211opmode(s);
struct ieee80211req ireq;
- uint8_t *cp;
+ const uint8_t *cp;
int len;
(void) memset(&ireq, 0, sizeof(ireq));
@@ -1038,6 +1590,8 @@ list_stations(int s)
if (len < sizeof(struct ieee80211req_sta_info))
return;
+ getchaninfo(s);
+
printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %4s\n"
, "ADDR"
, "AID"
@@ -1050,101 +1604,140 @@ list_stations(int s)
, "CAPS"
, "FLAG"
);
- cp = (uint8_t *) u.req.info;
+ cp = (const uint8_t *) u.req.info;
do {
- struct ieee80211req_sta_info *si;
- uint8_t *vp;
+ const struct ieee80211req_sta_info *si;
- si = (struct ieee80211req_sta_info *) cp;
+ si = (const struct ieee80211req_sta_info *) cp;
if (si->isi_len < sizeof(*si))
break;
- vp = (u_int8_t *)(si+1);
- printf("%s %4u %4d %3dM %4d %4d %6d %6d %-4.4s %-4.4s"
+ printf("%s %4u %4d %3dM %3.1f %4d %6d %6d %-4.4s %-4.4s"
, ether_ntoa((const struct ether_addr*) si->isi_macaddr)
, IEEE80211_AID(si->isi_associd)
, ieee80211_mhz2ieee(si->isi_freq, si->isi_flags)
, (si->isi_rates[si->isi_txrate] & IEEE80211_RATE_VAL)/2
- , si->isi_rssi
+ , si->isi_rssi/2.
, si->isi_inact
, si->isi_txseqs[0]
, si->isi_rxseqs[0]
, getcaps(si->isi_capinfo)
, getflags(si->isi_state)
);
- printies(vp, si->isi_ie_len, 24);
+ printies(cp + si->isi_ie_off, si->isi_ie_len, 24);
printf("\n");
cp += si->isi_len, len -= si->isi_len;
} while (len >= sizeof(struct ieee80211req_sta_info));
}
-static void
-print_chaninfo(const struct ieee80211_channel *c)
+static const char *
+get_chaninfo(const struct ieee80211_channel *c, int precise,
+ char buf[], size_t bsize)
{
- char buf[14];
-
buf[0] = '\0';
if (IEEE80211_IS_CHAN_FHSS(c))
- strlcat(buf, " FHSS", sizeof(buf));
+ strlcat(buf, " FHSS", bsize);
if (IEEE80211_IS_CHAN_A(c)) {
if (IEEE80211_IS_CHAN_HALF(c))
- strlcat(buf, " 11a/10Mhz", sizeof(buf));
+ strlcat(buf, " 11a/10Mhz", bsize);
else if (IEEE80211_IS_CHAN_QUARTER(c))
- strlcat(buf, " 11a/5Mhz", sizeof(buf));
+ strlcat(buf, " 11a/5Mhz", bsize);
else
- strlcat(buf, " 11a", sizeof(buf));
+ strlcat(buf, " 11a", bsize);
}
if (IEEE80211_IS_CHAN_ANYG(c)) {
if (IEEE80211_IS_CHAN_HALF(c))
- strlcat(buf, " 11g/10Mhz", sizeof(buf));
+ strlcat(buf, " 11g/10Mhz", bsize);
else if (IEEE80211_IS_CHAN_QUARTER(c))
- strlcat(buf, " 11g/5Mhz", sizeof(buf));
+ strlcat(buf, " 11g/5Mhz", bsize);
else
- strlcat(buf, " 11g", sizeof(buf));
+ strlcat(buf, " 11g", bsize);
} else if (IEEE80211_IS_CHAN_B(c))
- strlcat(buf, " 11b", sizeof(buf));
- if (IEEE80211_IS_CHAN_T(c))
- strlcat(buf, " Turbo", sizeof(buf));
+ strlcat(buf, " 11b", bsize);
+ if (IEEE80211_IS_CHAN_TURBO(c))
+ strlcat(buf, " Turbo", bsize);
+ if (precise) {
+ 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))
+ strlcat(buf, " ht", bsize);
+ }
+ return buf;
+}
+
+static void
+print_chaninfo(const struct ieee80211_channel *c)
+{
+ char buf[14];
+
printf("Channel %3u : %u%c Mhz%-14.14s",
ieee80211_mhz2ieee(c->ic_freq, c->ic_flags), c->ic_freq,
- IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ', buf);
+ IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ',
+ get_chaninfo(c, verbose, buf, sizeof(buf)));
}
static void
list_channels(int s, int allchans)
{
- struct ieee80211req ireq;
- struct ieee80211req_chaninfo chans;
struct ieee80211req_chaninfo achans;
+ uint8_t reported[IEEE80211_CHAN_BYTES];
const struct ieee80211_channel *c;
- int i, half, ieee;
+ int i, half;
- (void) memset(&ireq, 0, sizeof(ireq));
- (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
- ireq.i_type = IEEE80211_IOC_CHANINFO;
- ireq.i_data = &chans;
- ireq.i_len = sizeof(chans);
- if (ioctl(s, SIOCG80211, &ireq) < 0)
- errx(1, "unable to get channel information");
+ getchaninfo(s);
+ memset(&achans, 0, sizeof(achans));
+ memset(reported, 0, sizeof(reported));
if (!allchans) {
struct ieee80211req_chanlist active;
+ struct ieee80211req ireq;
+ (void) memset(&ireq, 0, sizeof(ireq));
+ (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
ireq.i_type = IEEE80211_IOC_CHANLIST;
ireq.i_data = &active;
ireq.i_len = sizeof(active);
if (ioctl(s, SIOCG80211, &ireq) < 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];
- ieee = ieee80211_mhz2ieee(c->ic_freq, c->ic_flags);
- if (isset(active.ic_channels, ieee) || allchans)
+ for (i = 0; i < chaninfo.ic_nchans; i++) {
+ c = &chaninfo.ic_chans[i];
+ if (!isset(active.ic_channels, c->ic_ieee))
+ continue;
+ /*
+ * Suppress compatible duplicates unless
+ * verbose. The kernel gives us it's
+ * complete channel list which has separate
+ * entries for 11g/11b and 11a/turbo.
+ */
+ if (isset(reported, c->ic_ieee) && !verbose) {
+ /* XXX we assume duplicates are adjacent */
+ achans.ic_chans[achans.ic_nchans-1] = *c;
+ } else {
achans.ic_chans[achans.ic_nchans++] = *c;
+ setbit(reported, c->ic_ieee);
+ }
}
- } else
- achans = chans;
+ } else {
+ 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 */
+ achans.ic_chans[achans.ic_nchans-1] = *c;
+ } else {
+ achans.ic_chans[achans.ic_nchans++] = *c;
+ setbit(reported, c->ic_ieee);
+ }
+ }
+ }
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]);
print_chaninfo(&achans.ic_chans[half+i]);
@@ -1157,14 +1750,80 @@ list_channels(int s, int allchans)
}
static void
+print_txpow(const struct ieee80211_channel *c)
+{
+ printf("Channel %3u : %u Mhz %3.1f reg %2d ",
+ c->ic_ieee, c->ic_freq,
+ c->ic_maxpower/2., c->ic_maxregpower);
+}
+
+static void
+print_txpow_verbose(const struct ieee80211_channel *c)
+{
+ print_chaninfo(c);
+ printf("min %4.1f dBm max %3.1f dBm reg %2d dBm",
+ c->ic_minpower/2., c->ic_maxpower/2., c->ic_maxregpower);
+ /* indicate where regulatory cap limits power use */
+ if (c->ic_maxpower > 2*c->ic_maxregpower)
+ printf(" <");
+}
+
+static void
+list_txpow(int s)
+{
+ 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));
+ memset(reported, 0, sizeof(reported));
+ 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];
+ /* display highest power on channel */
+ if (c->ic_maxpower > prev->ic_maxpower)
+ *prev = *c;
+ } else {
+ 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++;
+
+ 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]);
+ printf("\n");
+ }
+ } else {
+ for (i = 0; i < achans.ic_nchans; i++) {
+ print_txpow_verbose(&achans.ic_chans[i]);
+ printf("\n");
+ }
+ }
+}
+
+static void
list_keys(int s)
{
}
#define IEEE80211_C_BITS \
-"\020\1WEP\2TKIP\3AES\4AES_CCM\6CKIP\11IBSS\12PMGT\13HOSTAP\14AHDEMO" \
+"\020\1WEP\2TKIP\3AES\4AES_CCM\6CKIP\7FF\10TURBOP\11IBSS\12PMGT\13HOSTAP\14AHDEMO" \
"\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE\21MONITOR\22TKIPMIC\30WPA1" \
-"\31WPA2\32BURST\33WME"
+"\31WPA2\32BURST\33WME\34WDS\36BGSCAN\37TXFRAG"
static void
list_capabilities(int s)
@@ -1318,6 +1977,8 @@ DECL_CMD_FUNC(set80211list, arg, d)
list_wme(s);
else if (iseq(arg, "mac"))
list_mac(s);
+ else if (iseq(arg, "txpow"))
+ list_txpow(s);
else
errx(1, "Don't know how to list %s for %s", arg, name);
#undef iseq
@@ -1342,31 +2003,6 @@ get80211opmode(int s)
return IEEE80211_M_STA;
}
-static const struct ieee80211_channel *
-getchaninfo(int s, int chan)
-{
- struct ieee80211req ireq;
- static struct ieee80211req_chaninfo chans;
- static struct ieee80211_channel undef;
- const struct ieee80211_channel *c;
- int i, freq;
-
- (void) memset(&ireq, 0, sizeof(ireq));
- (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
- ireq.i_type = IEEE80211_IOC_CHANINFO;
- ireq.i_data = &chans;
- ireq.i_len = sizeof(chans);
- if (ioctl(s, SIOCG80211, &ireq) < 0)
- errx(1, "unable to get channel information");
- freq = ieee80211_ieee2mhz(chan);
- for (i = 0; i < chans.ic_nchans; i++) {
- c = &chans.ic_chans[i];
- if (c->ic_freq == freq)
- return c;
- }
- return &undef;
-}
-
#if 0
static void
printcipher(int s, struct ieee80211req *ireq, int keylenop)
@@ -1509,9 +2145,10 @@ ieee80211_status(int s)
{
static const uint8_t zerobssid[IEEE80211_ADDR_LEN];
enum ieee80211_opmode opmode = get80211opmode(s);
- int i, num, wpa, wme;
+ int i, num, wpa, wme, bgscan, bgscaninterval;
struct ieee80211req ireq;
u_int8_t data[32];
+ struct ieee80211_channel chan;
const struct ieee80211_channel *c;
(void) memset(&ireq, 0, sizeof(ireq));
@@ -1519,6 +2156,7 @@ ieee80211_status(int s)
ireq.i_data = &data;
wpa = 0; /* unknown/not set */
+ bgscan = 0; /* unknown/not set */
ireq.i_type = IEEE80211_IOC_SSID;
ireq.i_val = -1;
@@ -1542,14 +2180,24 @@ ieee80211_status(int s)
} else
print_string(data, ireq.i_len);
- ireq.i_type = IEEE80211_IOC_CHANNEL;
- if (ioctl(s, SIOCG80211, &ireq) < 0)
- goto end;
- c = getchaninfo(s, ireq.i_val);
- if (ireq.i_val != -1) {
- printf(" channel %d", ireq.i_val);
- if (verbose)
- printf(" (%u)", c->ic_freq);
+ ireq.i_data = &chan;
+ ireq.i_len = sizeof(chan);
+ ireq.i_type = IEEE80211_IOC_CURCHAN;
+ if (ioctl(s, SIOCG80211, &ireq) < 0) {
+ /* fall back to legacy ioctl */
+ ireq.i_data = NULL;
+ ireq.i_len = 0;
+ ireq.i_type = IEEE80211_IOC_CHANNEL;
+ if (ioctl(s, SIOCG80211, &ireq) < 0)
+ goto end;
+ getchaninfo(s);
+ mapchan(&chan, ireq.i_val, 0);
+ }
+ c = &chan;
+ if (c->ic_freq != IEEE80211_CHAN_ANY) {
+ char buf[14];
+ printf(" channel %d (%u Mhz%s)", c->ic_ieee, c->ic_freq,
+ get_chaninfo(c, 1, buf, sizeof(buf)));
} else if (verbose)
printf(" channel UNDEF");
@@ -1716,6 +2364,17 @@ ieee80211_status(int s)
LINE_CHECK("rtsthreshold %d", ireq.i_val);
}
+ ireq.i_type = IEEE80211_IOC_FRAGTHRESHOLD;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ if (ireq.i_val != IEEE80211_FRAG_MAX || verbose)
+ LINE_CHECK("fragthreshold %d", ireq.i_val);
+ }
+ ireq.i_type = IEEE80211_IOC_BMISSTHRESHOLD;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ if (ireq.i_val != IEEE80211_HWBMISS_MAX || verbose)
+ LINE_CHECK("bmiss %d", ireq.i_val);
+ }
+
ireq.i_type = IEEE80211_IOC_MCAST_RATE;
if (ioctl(s, SIOCG80211, &ireq) != -1) {
if (ireq.i_val != 2*1 || verbose) {
@@ -1726,16 +2385,56 @@ ieee80211_status(int s)
}
}
- ireq.i_type = IEEE80211_IOC_FRAGTHRESHOLD;
+ ireq.i_type = IEEE80211_IOC_BGSCAN_INTERVAL;
+ if (ioctl(s, SIOCG80211, &ireq) != -1)
+ bgscaninterval = ireq.i_val;
+ else
+ bgscaninterval = -1;
+
+ ireq.i_type = IEEE80211_IOC_SCANVALID;
if (ioctl(s, SIOCG80211, &ireq) != -1) {
- if (ireq.i_val != IEEE80211_FRAG_MAX || verbose)
- LINE_CHECK("fragthreshold %d", ireq.i_val);
+ if (ireq.i_val != bgscaninterval || verbose)
+ LINE_CHECK("scanvalid %u", ireq.i_val);
}
- ireq.i_type = IEEE80211_IOC_BMISSTHRESHOLD;
+ ireq.i_type = IEEE80211_IOC_BGSCAN;
if (ioctl(s, SIOCG80211, &ireq) != -1) {
- if (ireq.i_val != IEEE80211_HWBMISS_MAX || verbose)
- LINE_CHECK("bmiss %d", ireq.i_val);
+ bgscan = ireq.i_val;
+ if (ireq.i_val)
+ LINE_CHECK("bgscan");
+ else if (verbose)
+ LINE_CHECK("-bgscan");
+ }
+ if (bgscan || verbose) {
+ if (bgscaninterval != -1)
+ LINE_CHECK("bgscanintvl %u", bgscaninterval);
+ ireq.i_type = IEEE80211_IOC_BGSCAN_IDLE;
+ if (ioctl(s, SIOCG80211, &ireq) != -1)
+ LINE_CHECK("bgscanidle %u", ireq.i_val);
+ if (IEEE80211_IS_CHAN_A(c) || verbose) {
+ ireq.i_type = IEEE80211_IOC_ROAM_RSSI_11A;
+ if (ioctl(s, SIOCG80211, &ireq) != -1)
+ LINE_CHECK("roam:rssi11a %d", ireq.i_val);
+ ireq.i_type = IEEE80211_IOC_ROAM_RATE_11A;
+ if (ioctl(s, SIOCG80211, &ireq) != -1)
+ LINE_CHECK("roam:rate11a %u", ireq.i_val/2);
+ }
+ if (IEEE80211_IS_CHAN_B(c) || verbose) {
+ ireq.i_type = IEEE80211_IOC_ROAM_RSSI_11B;
+ if (ioctl(s, SIOCG80211, &ireq) != -1)
+ LINE_CHECK("roam:rssi11b %d", ireq.i_val);
+ ireq.i_type = IEEE80211_IOC_ROAM_RATE_11B;
+ if (ioctl(s, SIOCG80211, &ireq) != -1)
+ LINE_CHECK("roam:rate11b %u", ireq.i_val/2);
+ }
+ if (IEEE80211_IS_CHAN_ANYG(c) || verbose) {
+ ireq.i_type = IEEE80211_IOC_ROAM_RSSI_11G;
+ if (ioctl(s, SIOCG80211, &ireq) != -1)
+ LINE_CHECK("roam:rssi11g %d", ireq.i_val);
+ ireq.i_type = IEEE80211_IOC_ROAM_RATE_11G;
+ if (ioctl(s, SIOCG80211, &ireq) != -1)
+ LINE_CHECK("roam:rate11g %u", ireq.i_val/2);
+ }
}
if (IEEE80211_IS_CHAN_ANYG(c) || verbose) {
@@ -1784,6 +2483,21 @@ ieee80211_status(int s)
LINE_CHECK("-burst");
}
+ ireq.i_type = IEEE80211_IOC_FF;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ if (ireq.i_val)
+ LINE_CHECK("ff");
+ else if (verbose)
+ LINE_CHECK("-ff");
+ }
+ ireq.i_type = IEEE80211_IOC_TURBOP;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ if (ireq.i_val)
+ LINE_CHECK("dturbo");
+ else if (verbose)
+ LINE_CHECK("-dturbo");
+ }
+
if (opmode == IEEE80211_M_HOSTAP) {
ireq.i_type = IEEE80211_IOC_HIDESSID;
if (ioctl(s, SIOCG80211, &ireq) != -1) {
@@ -1804,6 +2518,14 @@ ieee80211_status(int s)
ireq.i_type = IEEE80211_IOC_DTIM_PERIOD;
if (ioctl(s, SIOCG80211, &ireq) != -1)
LINE_CHECK("dtimperiod %u", ireq.i_val);
+
+ ireq.i_type = IEEE80211_IOC_DOTH;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ if (!ireq.i_val)
+ LINE_CHECK("-doth");
+ else if (verbose)
+ LINE_CHECK("doth");
+ }
} else {
ireq.i_type = IEEE80211_IOC_ROAMING;
if (ioctl(s, SIOCG80211, &ireq) != -1) {
@@ -1887,7 +2609,7 @@ end:
}
static void
-set80211(int s, int type, int val, int len, u_int8_t *data)
+set80211(int s, int type, int val, int len, void *data)
{
struct ieee80211req ireq;
@@ -2041,12 +2763,29 @@ static struct cmd ieee80211_cmds[] = {
DEF_CMD_ARG("mac:kick", set80211kickmac),
DEF_CMD("pureg", 1, set80211pureg),
DEF_CMD("-pureg", 0, set80211pureg),
+ DEF_CMD("ff", 1, set80211fastframes),
+ DEF_CMD("-ff", 0, set80211fastframes),
+ DEF_CMD("dturbo", 1, set80211dturbo),
+ DEF_CMD("-dturbo", 0, set80211dturbo),
+ DEF_CMD("bgscan", 1, set80211bgscan),
+ DEF_CMD("-bgscan", 0, set80211bgscan),
+ DEF_CMD_ARG("bgscanidle", set80211bgscanidle),
+ DEF_CMD_ARG("bgscanintvl", set80211bgscanintvl),
+ DEF_CMD_ARG("scanvalid", set80211scanvalid),
+ DEF_CMD_ARG("roam:rssi11a", set80211roamrssi11a),
+ DEF_CMD_ARG("roam:rssi11b", set80211roamrssi11b),
+ DEF_CMD_ARG("roam:rssi11g", set80211roamrssi11g),
+ DEF_CMD_ARG("roam:rate11a", set80211roamrate11a),
+ DEF_CMD_ARG("roam:rate11b", set80211roamrate11b),
+ DEF_CMD_ARG("roam:rate11g", set80211roamrate11g),
DEF_CMD_ARG("mcastrate", set80211mcastrate),
DEF_CMD_ARG("fragthreshold", set80211fragthreshold),
DEF_CMD("burst", 1, set80211burst),
DEF_CMD("-burst", 0, set80211burst),
DEF_CMD_ARG("bmiss", set80211bmissthreshold),
DEF_CMD_ARG("bmissthreshold", set80211bmissthreshold),
+ DEF_CMD("doth", 1, set80211doth),
+ DEF_CMD("-doth", 0, set80211doth),
};
static struct afswtch af_ieee80211 = {
.af_name = "af_ieee80211",
diff --git a/sbin/ifconfig/ifmedia.c b/sbin/ifconfig/ifmedia.c
index a3d3036..947b961 100644
--- a/sbin/ifconfig/ifmedia.c
+++ b/sbin/ifconfig/ifmedia.c
@@ -184,8 +184,8 @@ media_status(int s)
free(media_list);
}
-static struct ifmediareq *
-getifmediastate(int s)
+struct ifmediareq *
+ifmedia_getstate(int s)
{
static struct ifmediareq *ifmr = NULL;
int *mwords;
@@ -249,7 +249,7 @@ setmedia(const char *val, int d, int s, const struct afswtch *afp)
struct ifmediareq *ifmr;
int subtype;
- ifmr = getifmediastate(s);
+ ifmr = ifmedia_getstate(s);
/*
* We are primarily concerned with the top-level type.
@@ -294,7 +294,7 @@ domediaopt(const char *val, int clear, int s)
struct ifmediareq *ifmr;
int options;
- ifmr = getifmediastate(s);
+ ifmr = ifmedia_getstate(s);
options = get_media_options(IFM_TYPE(ifmr->ifm_ulist[0]), val);
@@ -319,7 +319,7 @@ setmediainst(const char *val, int d, int s, const struct afswtch *afp)
struct ifmediareq *ifmr;
int inst;
- ifmr = getifmediastate(s);
+ ifmr = ifmedia_getstate(s);
inst = atoi(val);
if (inst < 0 || inst > IFM_INST_MAX)
@@ -338,7 +338,7 @@ setmediamode(const char *val, int d, int s, const struct afswtch *afp)
struct ifmediareq *ifmr;
int mode;
- ifmr = getifmediastate(s);
+ ifmr = ifmedia_getstate(s);
mode = get_media_mode(IFM_TYPE(ifmr->ifm_ulist[0]), val);
OpenPOWER on IntegriCloud