diff options
author | sam <sam@FreeBSD.org> | 2007-11-02 05:24:57 +0000 |
---|---|---|
committer | sam <sam@FreeBSD.org> | 2007-11-02 05:24:57 +0000 |
commit | f4c243dde1ed70de7b75005ff9ac8295a7b1bf55 (patch) | |
tree | 393c5e94ea2b9e8e983c183456aa13144869a071 /sbin/ifconfig/ifieee80211.c | |
parent | 3728c98921a76588dc8a67def804e5192f613b6d (diff) | |
download | FreeBSD-src-f4c243dde1ed70de7b75005ff9ac8295a7b1bf55.zip FreeBSD-src-f4c243dde1ed70de7b75005ff9ac8295a7b1bf55.tar.gz |
sync with vap code base; updates for 11n support and some
general code cleanups
Reviewed by: thompsa, avatar
MFC after: 1 week
Diffstat (limited to 'sbin/ifconfig/ifieee80211.c')
-rw-r--r-- | sbin/ifconfig/ifieee80211.c | 1620 |
1 files changed, 1125 insertions, 495 deletions
diff --git a/sbin/ifconfig/ifieee80211.c b/sbin/ifconfig/ifieee80211.c index 1f09879..d024a71 100644 --- a/sbin/ifconfig/ifieee80211.c +++ b/sbin/ifconfig/ifieee80211.c @@ -91,9 +91,41 @@ #include <string.h> #include <unistd.h> #include <stdarg.h> +#include <stddef.h> /* NB: for offsetof */ #include "ifconfig.h" +#define MAXCOL 78 +static int col; +static char spacer; + +static void LINE_INIT(char c); +static void LINE_BREAK(void); +static void LINE_CHECK(const char *fmt, ...); + +/* XXX need max array size */ +static const int htrates[16] = { + 13, /* IFM_IEEE80211_MCS0 */ + 26, /* IFM_IEEE80211_MCS1 */ + 39, /* IFM_IEEE80211_MCS2 */ + 52, /* IFM_IEEE80211_MCS3 */ + 78, /* IFM_IEEE80211_MCS4 */ + 104, /* IFM_IEEE80211_MCS5 */ + 117, /* IFM_IEEE80211_MCS6 */ + 130, /* IFM_IEEE80211_MCS7 */ + 26, /* IFM_IEEE80211_MCS8 */ + 52, /* IFM_IEEE80211_MCS9 */ + 78, /* IFM_IEEE80211_MCS10 */ + 104, /* IFM_IEEE80211_MCS11 */ + 156, /* IFM_IEEE80211_MCS12 */ + 208, /* IFM_IEEE80211_MCS13 */ + 234, /* IFM_IEEE80211_MCS14 */ + 260, /* IFM_IEEE80211_MCS15 */ +}; + +static int get80211(int s, int type, void *data, int len); +static int get80211len(int s, int type, void *data, int len, int *plen); +static int get80211val(int s, int type, int *val); 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); @@ -101,6 +133,20 @@ static void print_string(const u_int8_t *buf, int len); static struct ieee80211req_chaninfo chaninfo; static struct ifmediareq *ifmr; +static struct ieee80211_channel curchan; +static int gotcurchan = 0; +static int htconf = 0; +static int gothtconf = 0; + +static void +gethtconf(int s) +{ + if (gothtconf) + return; + if (get80211val(s, IEEE80211_IOC_HTCONF, &htconf) < 0) + warn("unable to get HT configuration information"); + gothtconf = 1; +} /* * Collect channel info from the kernel. We use this (mostly) @@ -109,19 +155,13 @@ static struct ifmediareq *ifmr; 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) + if (get80211(s, IEEE80211_IOC_CHANINFO, &chaninfo, sizeof(chaninfo)) < 0) errx(1, "unable to get channel information"); ifmr = ifmedia_getstate(s); + gethtconf(s); } /* @@ -188,21 +228,25 @@ promote(int i) /* 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) { + if (chanmode != IFM_IEEE80211_11G && (htconf & 1)) { 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 (htconf & 2) { + 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) { + if (chanmode != IFM_IEEE80211_11A && (htconf & 1)) { 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); + if (htconf & 2) { + 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; } @@ -244,7 +288,24 @@ mapchan(struct ieee80211_channel *chan, int ieee, int flags) return; } } - errx(1, "unknown/undefined channel number %d", ieee); + errx(1, "unknown/undefined channel number %d flags 0x%x", ieee, flags); +} + +static const struct ieee80211_channel * +getcurchan(int s) +{ + if (gotcurchan) + return &curchan; + if (get80211(s, IEEE80211_IOC_CURCHAN, &curchan, sizeof(curchan)) < 0) { + int val; + /* fall back to legacy ioctl */ + if (get80211val(s, IEEE80211_IOC_CHANNEL, &val) < 0) + errx(-1, "cannot figure out current channel"); + getchaninfo(s); + mapchan(&curchan, val, 0); + } + gotcurchan = 1; + return &curchan; } static int @@ -258,8 +319,8 @@ ieee80211_mhz2ieee(int freq, int flags) static int isanyarg(const char *arg) { - return (strcmp(arg, "-") == 0 || - strcasecmp(arg, "any") == 0 || strcasecmp(arg, "off") == 0); + return (strncmp(arg, "-", 1) == 0 || + strncasecmp(arg, "any", 3) == 0 || strncasecmp(arg, "off", 3) == 0); } static void @@ -310,9 +371,8 @@ set80211stationname(const char *val, int d, int s, const struct afswtch *rafp) * checked against the channel table fetched from the kernel. */ static int -getchannelflags(const char *val) +getchannelflags(const char *val, int freq) { -#define CHAN_HT_DEFAULT IEEE80211_CHAN_HT40U #define _CHAN_HT 0x80000000 const char *cp; int flags; @@ -352,7 +412,7 @@ getchannelflags(const char *val) flags |= IEEE80211_CHAN_STURBO; break; default: - errx(-1, "%s: Invalid channel attribute %c", + errx(-1, "%s: Invalid channel attribute %c\n", val, *cp); } } @@ -378,11 +438,9 @@ getchannelflags(const char *val) 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); + errx(-1, "%s: Invalid channel width\n", val); } } /* @@ -404,11 +462,20 @@ getchannelflags(const char *val) * provide the default settings. */ flags &= ~_CHAN_HT; - if ((flags & IEEE80211_CHAN_HT) == 0) - flags |= CHAN_HT_DEFAULT; + if ((flags & IEEE80211_CHAN_HT) == 0) { + struct ieee80211_channel chan; + /* + * Consult the channel list to see if we can use + * HT40+ or HT40- (if both the map routines choose). + */ + if (freq > 255) + mapfreq(&chan, freq, 0); + else + mapchan(&chan, freq, 0); + flags |= (chan.ic_flags & IEEE80211_CHAN_HT); + } } return flags; -#undef CHAN_HT_DEFAULT #undef _CHAN_HT } @@ -419,10 +486,11 @@ set80211channel(const char *val, int d, int s, const struct afswtch *rafp) memset(&chan, 0, sizeof(chan)); if (!isanyarg(val)) { - int v = atoi(val); - int flags = getchannelflags(val); + int v, flags; getchaninfo(s); + v = atoi(val); + flags = getchannelflags(val, v); if (v > 255) { /* treat as frequency */ mapfreq(&chan, v, flags); } else { @@ -612,7 +680,7 @@ set80211protmode(const char *val, int d, int s, const struct afswtch *rafp) mode = IEEE80211_PROTMODE_OFF; } else if (strcasecmp(val, "cts") == 0) { mode = IEEE80211_PROTMODE_CTS; - } else if (strcasecmp(val, "rtscts") == 0) { + } else if (strncasecmp(val, "rtscts", 3) == 0) { mode = IEEE80211_PROTMODE_RTSCTS; } else { errx(1, "unknown protection mode"); @@ -622,9 +690,31 @@ set80211protmode(const char *val, int d, int s, const struct afswtch *rafp) } static void +set80211htprotmode(const char *val, int d, int s, const struct afswtch *rafp) +{ + int mode; + + if (strcasecmp(val, "off") == 0) { + mode = IEEE80211_PROTMODE_OFF; + } else if (strncasecmp(val, "rts", 3) == 0) { + mode = IEEE80211_PROTMODE_RTSCTS; + } else { + errx(1, "unknown protection mode"); + } + + set80211(s, IEEE80211_IOC_HTPROTMODE, mode, 0, NULL); +} + +static void set80211txpower(const char *val, int d, int s, const struct afswtch *rafp) { - set80211(s, IEEE80211_IOC_TXPOWER, atoi(val), 0, NULL); + double v = atof(val); + int txpow; + + txpow = (int) (2*v); + if (txpow != 2*v) + errx(-1, "invalid tx power (must be .5 dBm units)"); + set80211(s, IEEE80211_IOC_TXPOWER, txpow, 0, NULL); } #define IEEE80211_ROAMING_DEVICE 0 @@ -692,7 +782,7 @@ set80211chanlist(const char *val, int d, int s, const struct afswtch *rafp) memset(&chanlist, 0, sizeof(chanlist)); cp = temp; for (;;) { - int first, last, f; + int first, last, f, c; tp = strchr(cp, ','); if (tp != NULL) @@ -720,9 +810,10 @@ set80211chanlist(const char *val, int d, int s, const struct afswtch *rafp) } if (tp == NULL) break; - while (isspace(*tp)) + c = *tp; + while (isspace(c)) tp++; - if (!isdigit(*tp)) + if (!isdigit(c)) break; cp = tp; } @@ -1017,6 +1108,181 @@ set80211doth(const char *val, int d, int s, const struct afswtch *rafp) set80211(s, IEEE80211_IOC_DOTH, d, 0, NULL); } +static void +set80211shortgi(const char *val, int d, int s, const struct afswtch *rafp) +{ + set80211(s, IEEE80211_IOC_SHORTGI, + d ? (IEEE80211_HTCAP_SHORTGI20 | IEEE80211_HTCAP_SHORTGI40) : 0, + 0, NULL); +} + +static void +set80211ampdu(const char *val, int d, int s, const struct afswtch *rafp) +{ + int ampdu; + + if (get80211val(s, IEEE80211_IOC_AMPDU, &du) < 0) + errx(-1, "cannot get AMPDU setting"); + if (d < 0) { + d = -d; + ampdu &= ~d; + } else + ampdu |= d; + set80211(s, IEEE80211_IOC_AMPDU, ampdu, 0, NULL); +} + +static +DECL_CMD_FUNC(set80211ampdulimit, val, d) +{ + int v; + + switch (atoi(val)) { + case 8: + case 8*1024: + v = IEEE80211_HTCAP_MAXRXAMPDU_8K; + break; + case 16: + case 16*1024: + v = IEEE80211_HTCAP_MAXRXAMPDU_16K; + break; + case 32: + case 32*1024: + v = IEEE80211_HTCAP_MAXRXAMPDU_32K; + break; + case 64: + case 64*1024: + v = IEEE80211_HTCAP_MAXRXAMPDU_64K; + break; + default: + errx(-1, "invalid A-MPDU limit %s", val); + } + set80211(s, IEEE80211_IOC_AMPDU_LIMIT, v, 0, NULL); +} + +static +DECL_CMD_FUNC(set80211ampdudensity, val, d) +{ + int v; + + if (isanyarg(val)) + v = IEEE80211_HTCAP_MPDUDENSITY_NA; + else switch ((int)(atof(val)*4)) { + case 0: + v = IEEE80211_HTCAP_MPDUDENSITY_NA; + break; + case 1: + v = IEEE80211_HTCAP_MPDUDENSITY_025; + break; + case 2: + v = IEEE80211_HTCAP_MPDUDENSITY_05; + break; + case 4: + v = IEEE80211_HTCAP_MPDUDENSITY_1; + break; + case 8: + v = IEEE80211_HTCAP_MPDUDENSITY_2; + break; + case 16: + v = IEEE80211_HTCAP_MPDUDENSITY_4; + break; + case 32: + v = IEEE80211_HTCAP_MPDUDENSITY_8; + break; + case 64: + v = IEEE80211_HTCAP_MPDUDENSITY_16; + break; + default: + errx(-1, "invalid A-MPDU density %s", val); + } + set80211(s, IEEE80211_IOC_AMPDU_DENSITY, v, 0, NULL); +} + +static void +set80211amsdu(const char *val, int d, int s, const struct afswtch *rafp) +{ + int amsdu; + + if (get80211val(s, IEEE80211_IOC_AMSDU, &amsdu) < 0) + errx(-1, "cannot get AMSDU setting"); + if (d < 0) { + d = -d; + amsdu &= ~d; + } else + amsdu |= d; + set80211(s, IEEE80211_IOC_AMSDU, amsdu, 0, NULL); +} + +static +DECL_CMD_FUNC(set80211amsdulimit, val, d) +{ + set80211(s, IEEE80211_IOC_AMSDU_LIMIT, atoi(val), 0, NULL); +} + +static void +set80211puren(const char *val, int d, int s, const struct afswtch *rafp) +{ + set80211(s, IEEE80211_IOC_PUREN, d, 0, NULL); +} + +static void +set80211htcompat(const char *val, int d, int s, const struct afswtch *rafp) +{ + set80211(s, IEEE80211_IOC_HTCOMPAT, d, 0, NULL); +} + +static void +set80211htconf(const char *val, int d, int s, const struct afswtch *rafp) +{ + set80211(s, IEEE80211_IOC_HTCONF, d, 0, NULL); + htconf = d; +} + +static void +set80211inact(const char *val, int d, int s, const struct afswtch *rafp) +{ + set80211(s, IEEE80211_IOC_INACTIVITY, d, 0, NULL); +} + +static void +LINE_INIT(char c) +{ + spacer = c; + if (c == '\t') + col = 8; + else + col = 1; +} + +static void +LINE_BREAK(void) +{ + if (spacer != '\t') { + printf("\n"); + spacer = '\t'; + } + col = 8; /* 8-col tab */ +} + +static void +LINE_CHECK(const char *fmt, ...) +{ + char buf[80]; + va_list ap; + int n; + + va_start(ap, fmt); + n = vsnprintf(buf+1, sizeof(buf)-1, fmt, ap); + va_end(ap); + col += 1+n; + if (col > MAXCOL) { + LINE_BREAK(); + col += n; + } + buf[0] = spacer; + printf("%s", buf); + spacer = ' '; +} + static int getmaxrate(const uint8_t rates[15], uint8_t nrates) { @@ -1071,6 +1337,10 @@ getflags(int flags) #define IEEE80211_NODE_ERP 0x0004 /* ERP enabled */ #define IEEE80211_NODE_PWR_MGT 0x0010 /* power save mode enabled */ #define IEEE80211_NODE_HT 0x0040 /* HT enabled */ +#define IEEE80211_NODE_HTCOMPAT 0x0080 /* HT setup w/ vendor OUI's */ +#define IEEE80211_NODE_WPS 0x0100 /* WPS association */ +#define IEEE80211_NODE_TSN 0x0200 /* TSN association */ + static char flagstring[32]; char *cp = flagstring; @@ -1082,10 +1352,20 @@ getflags(int flags) *cp++ = 'E'; if (flags & IEEE80211_NODE_PWR_MGT) *cp++ = 'P'; - if (flags & IEEE80211_NODE_HT) + if (flags & IEEE80211_NODE_HT) { *cp++ = 'H'; + if (flags & IEEE80211_NODE_HTCOMPAT) + *cp++ = '+'; + } + if (flags & IEEE80211_NODE_WPS) + *cp++ = 'W'; + if (flags & IEEE80211_NODE_TSN) + *cp++ = 'T'; *cp = '\0'; return flagstring; +#undef IEEE80211_NODE_TSN +#undef IEEE80211_NODE_WPS +#undef IEEE80211_NODE_HTCOMPAT #undef IEEE80211_NODE_HT #undef IEEE80211_NODE_AUTH #undef IEEE80211_NODE_QOS @@ -1131,34 +1411,115 @@ printie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen) */ static void -printwmeie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) +printwmeparam(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" }; + const struct ieee80211_wme_param *wme = + (const struct ieee80211_wme_param *) ie; 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(">"); + if (!verbose) + return; + printf("<qosinfo 0x%x", wme->param_qosInfo); + ie += offsetof(struct ieee80211_wme_param, params_acParams); + for (i = 0; i < WME_NUM_AC; i++) { + const struct ieee80211_wme_acparams *ac = + &wme->params_acParams[i]; + + printf(" %s[%saifsn %u cwmin %u cwmax %u txop %u]" + , acnames[i] + , MS(ac->acp_aci_aifsn, WME_PARAM_ACM) ? "acm " : "" + , MS(ac->acp_aci_aifsn, WME_PARAM_AIFSN) + , MS(ac->acp_logcwminmax, WME_PARAM_LOGCWMIN) + , MS(ac->acp_logcwminmax, WME_PARAM_LOGCWMAX) + , LE_READ_2(&ac->acp_txop) + ); } + printf(">"); #undef MS } static void +printwmeinfo(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) +{ + printf("%s", tag); + if (verbose) { + const struct ieee80211_wme_info *wme = + (const struct ieee80211_wme_info *) ie; + printf("<version 0x%x info 0x%x>", + wme->wme_version, wme->wme_info); + } +} + +static void +printhtcap(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) +{ + printf("%s", tag); + if (verbose) { + const struct ieee80211_ie_htcap *htcap = + (const struct ieee80211_ie_htcap *) ie; + const char *sep; + int i, j; + + printf("<cap 0x%x param 0x%x", + LE_READ_2(&htcap->hc_cap), htcap->hc_param); + printf(" mcsset["); + sep = ""; + for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++) + if (isset(htcap->hc_mcsset, i)) { + for (j = i+1; j < IEEE80211_HTRATE_MAXSIZE; j++) + if (isclr(htcap->hc_mcsset, j)) + break; + j--; + if (i == j) + printf("%s%u", sep, i); + else + printf("%s%u-%u", sep, i, j); + i += j-i; + sep = ","; + } + printf("] extcap 0x%x txbf 0x%x antenna 0x%x>", + LE_READ_2(&htcap->hc_extcap), + LE_READ_4(&htcap->hc_txbf), + htcap->hc_antenna); + } +} + +static void +printhtinfo(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) +{ + printf("%s", tag); + if (verbose) { + const struct ieee80211_ie_htinfo *htinfo = + (const struct ieee80211_ie_htinfo *) ie; + const char *sep; + int i, j; + + printf("<ctl %u, %x,%x,%x,%x", htinfo->hi_ctrlchannel, + htinfo->hi_byte1, htinfo->hi_byte2, htinfo->hi_byte3, + LE_READ_2(&htinfo->hi_byte45)); + printf(" basicmcs["); + sep = ""; + for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++) + if (isset(htinfo->hi_basicmcsset, i)) { + for (j = i+1; j < IEEE80211_HTRATE_MAXSIZE; j++) + if (isclr(htinfo->hi_basicmcsset, j)) + break; + j--; + if (i == j) + printf("%s%u", sep, i); + else + printf("%s%u-%u", sep, i, j); + i += j-i; + sep = ","; + } + printf("]>"); + } +} + +static void printathie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) { @@ -1317,42 +1678,40 @@ rsn_keymgmt(const u_int8_t *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 */ + ie += 2, ielen -= 2; printf("<v%u", LE_READ_2(ie)); - ie += 2, len -= 2; + ie += 2, ielen -= 2; printf(" mc:%s", rsn_cipher(ie)); - ie += 4, len -= 4; + ie += 4, ielen -= 4; /* unicast ciphers */ n = LE_READ_2(ie); - ie += 2, len -= 2; + ie += 2, ielen -= 2; sep = " uc:"; for (; n > 0; n--) { printf("%s%s", sep, rsn_cipher(ie)); - ie += 4, len -= 4; + ie += 4, ielen -= 4; sep = "+"; } /* key management algorithms */ n = LE_READ_2(ie); - ie += 2, len -= 2; + ie += 2, ielen -= 2; sep = " km:"; for (; n > 0; n--) { printf("%s%s", sep, rsn_keymgmt(ie)); - ie += 4, len -= 4; + ie += 4, ielen -= 4; sep = "+"; } - if (len > 2) /* optional capabilities */ + if (ielen > 2) /* optional capabilities */ printf(", caps 0x%x", LE_READ_2(ie)); /* XXXPMKID */ printf(">"); @@ -1401,6 +1760,52 @@ copy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len) return maxlen; } +static void +printssid(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) +{ + char ssid[2*IEEE80211_NWID_LEN+1]; + + printf("%s<%.*s>", tag, copy_essid(ssid, maxlen, ie+2, ie[1]), ssid); +} + +static void +printrates(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) +{ + const char *sep; + int i; + + printf("%s", tag); + sep = "<"; + for (i = 2; i < ielen; i++) { + printf("%s%s%d", sep, + ie[i] & IEEE80211_RATE_BASIC ? "B" : "", + ie[i] & IEEE80211_RATE_VAL); + sep = ","; + } + printf(">"); +} + +static void +printcountry(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen) +{ + const struct ieee80211_country_ie *cie = + (const struct ieee80211_country_ie *) ie; + int i, nbands, schan, nchan; + + printf("%s<%c%c%c", tag, cie->cc[0], cie->cc[1], cie->cc[2]); + nbands = (cie->len - 3) / sizeof(cie->band[0]); + for (i = 0; i < nbands; i++) { + schan = cie->band[i].schan; + nchan = cie->band[i].nchan; + if (nchan != 1) + printf(" %u-%u,%u", schan, schan + nchan-1, + cie->band[i].maxtxpwr); + else + printf(" %u,%u", schan, cie->band[i].maxtxpwr); + } + printf(">"); +} + /* unaligned little endian access */ #define LE_READ_4(p) \ ((u_int32_t) \ @@ -1416,9 +1821,17 @@ iswpaoui(const u_int8_t *frm) } static int __inline -iswmeoui(const u_int8_t *frm) +iswmeinfo(const u_int8_t *frm) { - return frm[1] > 3 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI); + return frm[1] > 5 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) && + frm[6] == WME_INFO_OUI_SUBTYPE; +} + +static int __inline +iswmeparam(const u_int8_t *frm) +{ + return frm[1] > 5 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) && + frm[6] == WME_PARAM_OUI_SUBTYPE; } static int __inline @@ -1427,26 +1840,83 @@ isatherosoui(const u_int8_t *frm) return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI); } +static const char * +iename(int elemid) +{ + switch (elemid) { + case IEEE80211_ELEMID_FHPARMS: return " FHPARMS"; + case IEEE80211_ELEMID_CFPARMS: return " CFPARMS"; + case IEEE80211_ELEMID_TIM: return " TIM"; + case IEEE80211_ELEMID_IBSSPARMS:return " IBSSPARMS"; + case IEEE80211_ELEMID_CHALLENGE:return " CHALLENGE"; + case IEEE80211_ELEMID_PWRCNSTR: return " PWRCNSTR"; + case IEEE80211_ELEMID_PWRCAP: return " PWRCAP"; + case IEEE80211_ELEMID_TPCREQ: return " TPCREQ"; + case IEEE80211_ELEMID_TPCREP: return " TPCREP"; + case IEEE80211_ELEMID_SUPPCHAN: return " SUPPCHAN"; + case IEEE80211_ELEMID_CHANSWITCHANN:return " CSA"; + case IEEE80211_ELEMID_MEASREQ: return " MEASREQ"; + case IEEE80211_ELEMID_MEASREP: return " MEASREP"; + case IEEE80211_ELEMID_QUIET: return " QUIET"; + case IEEE80211_ELEMID_IBSSDFS: return " IBSSDFS"; + case IEEE80211_ELEMID_TPC: return " TPC"; + case IEEE80211_ELEMID_CCKM: return " CCKM"; + } + return " ???"; +} + static void printies(const u_int8_t *vp, int ielen, int maxcols) { while (ielen > 0) { switch (vp[0]) { + case IEEE80211_ELEMID_SSID: + if (verbose) + printssid(" SSID", vp, 2+vp[1], maxcols); + break; + case IEEE80211_ELEMID_RATES: + case IEEE80211_ELEMID_XRATES: + if (verbose) + printrates(vp[0] == IEEE80211_ELEMID_RATES ? + " RATES" : " XRATES", vp, 2+vp[1], maxcols); + break; + case IEEE80211_ELEMID_DSPARMS: + if (verbose) + printf(" DSPARMS<%u>", vp[2]); + break; + case IEEE80211_ELEMID_COUNTRY: + if (verbose) + printcountry(" COUNTRY", vp, 2+vp[1], maxcols); + break; + case IEEE80211_ELEMID_ERP: + if (verbose) + printf(" ERP<0x%x>", vp[2]); + break; case IEEE80211_ELEMID_VENDOR: if (iswpaoui(vp)) printwpaie(" WPA", vp, 2+vp[1], maxcols); - else if (iswmeoui(vp)) - printwmeie(" WME", vp, 2+vp[1], maxcols); + else if (iswmeinfo(vp)) + printwmeinfo(" WME", vp, 2+vp[1], maxcols); + else if (iswmeparam(vp)) + printwmeparam(" WME", vp, 2+vp[1], maxcols); else if (isatherosoui(vp)) printathie(" ATH", vp, 2+vp[1], maxcols); - else + else if (verbose) printie(" VEN", vp, 2+vp[1], maxcols); break; case IEEE80211_ELEMID_RSN: printrsnie(" RSN", vp, 2+vp[1], maxcols); break; + case IEEE80211_ELEMID_HTCAP: + printhtcap(" HTCAP", vp, 2+vp[1], maxcols); + break; + case IEEE80211_ELEMID_HTINFO: + if (verbose) + printhtinfo(" HTINFO", vp, 2+vp[1], maxcols); + break; default: - printie(" ???", vp, 2+vp[1], maxcols); + if (verbose) + printie(iename(vp[0]), vp, 2+vp[1], maxcols); break; } ielen -= 2+vp[1]; @@ -1458,19 +1928,12 @@ static void list_scan(int s) { uint8_t buf[24*1024]; - struct ieee80211req ireq; char ssid[IEEE80211_NWID_LEN+1]; - uint8_t *cp; + const uint8_t *cp; int len, ssidmax; - (void) memset(&ireq, 0, sizeof(ireq)); - (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); - ireq.i_type = IEEE80211_IOC_SCAN_RESULTS; - ireq.i_data = buf; - ireq.i_len = sizeof(buf); - if (ioctl(s, SIOCG80211, &ireq) < 0) + if (get80211len(s, IEEE80211_IOC_SCAN_RESULTS, buf, sizeof(buf), &len) < 0) errx(1, "unable to get scan results"); - len = ireq.i_len; if (len < sizeof(struct ieee80211req_scan_result)) return; @@ -1492,7 +1955,7 @@ list_scan(int s) const uint8_t *vp; sr = (const struct ieee80211req_scan_result *) cp; - vp = ((const u_int8_t *)sr) + sr->isr_ie_off; + vp = cp + sr->isr_ie_off; printf("%-*.*s %s %3d %3dM %3d:%-3d %3d %-4.4s" , ssidmax , copy_essid(ssid, ssidmax, vp, sr->isr_ssid_len) @@ -1556,6 +2019,53 @@ DECL_CMD_FUNC(set80211scan, val, d) static enum ieee80211_opmode get80211opmode(int s); +static int +gettxseq(const struct ieee80211req_sta_info *si) +{ +#define IEEE80211_NODE_QOS 0x0002 /* QoS enabled */ + + int i, txseq; + + if ((si->isi_state & IEEE80211_NODE_QOS) == 0) + return si->isi_txseqs[0]; + /* XXX not right but usually what folks want */ + txseq = 0; + for (i = 0; i < IEEE80211_TID_SIZE; i++) + if (si->isi_txseqs[i] > txseq) + txseq = si->isi_txseqs[i]; + return txseq; +#undef IEEE80211_NODE_QOS +} + +static int +getrxseq(const struct ieee80211req_sta_info *si) +{ +#define IEEE80211_NODE_QOS 0x0002 /* QoS enabled */ + + int i, rxseq; + + if ((si->isi_state & IEEE80211_NODE_QOS) == 0) + return si->isi_rxseqs[0]; + /* XXX not right but usually what folks want */ + rxseq = 0; + for (i = 0; i < IEEE80211_TID_SIZE; i++) + if (si->isi_rxseqs[i] > rxseq) + rxseq = si->isi_rxseqs[i]; + return rxseq; +#undef IEEE80211_NODE_QOS +} + +static int +gettxrate(int txrate, int chanflags) +{ + if (txrate & 0x80) { + txrate = htrates[txrate & 0xf]; + /* NB: could bump this more based on short gi */ + return chanflags & IEEE80211_CHAN_HT40 ? txrate : txrate / 2; + } else + return (txrate & IEEE80211_RATE_VAL) / 2; +} + static void list_stations(int s) { @@ -1564,29 +2074,20 @@ list_stations(int s) uint8_t buf[24*1024]; } u; enum ieee80211_opmode opmode = get80211opmode(s); - struct ieee80211req ireq; const uint8_t *cp; int len; - (void) memset(&ireq, 0, sizeof(ireq)); - (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); /* broadcast address =>'s get all stations */ (void) memset(u.req.is_u.macaddr, 0xff, IEEE80211_ADDR_LEN); if (opmode == IEEE80211_M_STA) { /* * Get information about the associated AP. */ - ireq.i_type = IEEE80211_IOC_BSSID; - ireq.i_data = u.req.is_u.macaddr; - ireq.i_len = IEEE80211_ADDR_LEN; - (void) ioctl(s, SIOCG80211, &ireq); - } - ireq.i_type = IEEE80211_IOC_STA_INFO; - ireq.i_data = &u; - ireq.i_len = sizeof(u); - if (ioctl(s, SIOCG80211, &ireq) < 0) + (void) get80211(s, IEEE80211_IOC_BSSID, + u.req.is_u.macaddr, IEEE80211_ADDR_LEN); + } + if (get80211len(s, IEEE80211_IOC_STA_INFO, &u, sizeof(u), &len) < 0) errx(1, "unable to get station information"); - len = ireq.i_len; if (len < sizeof(struct ieee80211req_sta_info)) return; @@ -1615,11 +2116,11 @@ list_stations(int s) , 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 + , gettxrate(si->isi_txrate, si->isi_flags) , si->isi_rssi/2. , si->isi_inact - , si->isi_txseqs[0] - , si->isi_rxseqs[0] + , gettxseq(si) + , getrxseq(si) , getcaps(si->isi_capinfo) , getflags(si->isi_state) ); @@ -1670,41 +2171,35 @@ get_chaninfo(const struct ieee80211_channel *c, int precise, } static void -print_chaninfo(const struct ieee80211_channel *c) +print_chaninfo(const struct ieee80211_channel *c, int verb) { 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) ? '*' : ' ', - get_chaninfo(c, verbose, buf, sizeof(buf))); + get_chaninfo(c, verb, buf, sizeof(buf))); } static void -list_channels(int s, int allchans) +print_channels(int s, const struct ieee80211req_chaninfo *chans, + int allchans, int verb) { struct ieee80211req_chaninfo achans; uint8_t reported[IEEE80211_CHAN_BYTES]; const struct ieee80211_channel *c; int i, half; - 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) + + 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 < chaninfo.ic_nchans; i++) { - c = &chaninfo.ic_chans[i]; + for (i = 0; i < chans->ic_nchans; i++) { + c = &chans->ic_chans[i]; if (!isset(active.ic_channels, c->ic_ieee)) continue; /* @@ -1713,7 +2208,7 @@ list_channels(int s, int allchans) * complete channel list which has separate * entries for 11g/11b and 11a/turbo. */ - if (isset(reported, c->ic_ieee) && !verbose) { + if (isset(reported, c->ic_ieee) && !verb) { /* XXX we assume duplicates are adjacent */ achans.ic_chans[achans.ic_nchans-1] = *c; } else { @@ -1722,10 +2217,10 @@ list_channels(int s, int allchans) } } } else { - for (i = 0; i < chaninfo.ic_nchans; i++) { - c = &chaninfo.ic_chans[i]; + for (i = 0; i < chans->ic_nchans; i++) { + c = &chans->ic_chans[i]; /* suppress duplicates as above */ - if (isset(reported, c->ic_ieee) && !verbose) { + if (isset(reported, c->ic_ieee) && !verb) { /* XXX we assume duplicates are adjacent */ achans.ic_chans[achans.ic_nchans-1] = *c; } else { @@ -1739,17 +2234,24 @@ list_channels(int s, int allchans) half++; for (i = 0; i < achans.ic_nchans / 2; i++) { - print_chaninfo(&achans.ic_chans[i]); - print_chaninfo(&achans.ic_chans[half+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]); + print_chaninfo(&achans.ic_chans[i], verb); printf("\n"); } } static void +list_channels(int s, int allchans) +{ + getchaninfo(s); + print_channels(s, &chaninfo, allchans, verbose); +} + +static void print_txpow(const struct ieee80211_channel *c) { printf("Channel %3u : %u Mhz %3.1f reg %2d ", @@ -1760,7 +2262,7 @@ print_txpow(const struct ieee80211_channel *c) static void print_txpow_verbose(const struct ieee80211_channel *c) { - print_chaninfo(c); + print_chaninfo(c, 1); 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 */ @@ -1841,61 +2343,87 @@ list_capabilities(int s) putchar('\n'); } -static void -list_wme(int s) +static int +get80211wme(int s, int param, int ac, int *val) { - static const char *acnames[] = { "AC_BE", "AC_BK", "AC_VI", "AC_VO" }; struct ieee80211req ireq; - int ac; (void) memset(&ireq, 0, sizeof(ireq)); (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); - ireq.i_len = 0; + ireq.i_type = param; + ireq.i_len = ac; + if (ioctl(s, SIOCG80211, &ireq) < 0) { + warn("cannot get WME parameter %d, ac %d%s", + param, ac & IEEE80211_WMEPARAM_VAL, + ac & IEEE80211_WMEPARAM_BSS ? " (BSS)" : ""); + return -1; + } + *val = ireq.i_val; + return 0; +} + +static void +list_wme(int s) +{ + static const char *acnames[] = { "AC_BE", "AC_BK", "AC_VI", "AC_VO" }; + int ac, val; + for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++) { again: - if (ireq.i_len & IEEE80211_WMEPARAM_BSS) + if (ac & IEEE80211_WMEPARAM_BSS) printf("\t%s", " "); else printf("\t%s", acnames[ac]); - ireq.i_len = (ireq.i_len & IEEE80211_WMEPARAM_BSS) | ac; - /* show WME BSS parameters */ - ireq.i_type = IEEE80211_IOC_WME_CWMIN; - if (ioctl(s, SIOCG80211, &ireq) != -1) - printf(" cwmin %2u", ireq.i_val); - ireq.i_type = IEEE80211_IOC_WME_CWMAX; - if (ioctl(s, SIOCG80211, &ireq) != -1) - printf(" cwmax %2u", ireq.i_val); - ireq.i_type = IEEE80211_IOC_WME_AIFS; - if (ioctl(s, SIOCG80211, &ireq) != -1) - printf(" aifs %2u", ireq.i_val); - ireq.i_type = IEEE80211_IOC_WME_TXOPLIMIT; - if (ioctl(s, SIOCG80211, &ireq) != -1) - printf(" txopLimit %3u", ireq.i_val); - ireq.i_type = IEEE80211_IOC_WME_ACM; - if (ioctl(s, SIOCG80211, &ireq) != -1) { - if (ireq.i_val) + if (get80211wme(s, IEEE80211_IOC_WME_CWMIN, ac, &val) != -1) + printf(" cwmin %2u", val); + if (get80211wme(s, IEEE80211_IOC_WME_CWMAX, ac, &val) != -1) + printf(" cwmax %2u", val); + if (get80211wme(s, IEEE80211_IOC_WME_AIFS, ac, &val) != -1) + printf(" aifs %2u", val); + if (get80211wme(s, IEEE80211_IOC_WME_TXOPLIMIT, ac, &val) != -1) + printf(" txopLimit %3u", val); + if (get80211wme(s, IEEE80211_IOC_WME_ACM, ac, &val) != -1) { + if (val) printf(" acm"); else if (verbose) printf(" -acm"); } /* !BSS only */ - if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) { - ireq.i_type = IEEE80211_IOC_WME_ACKPOLICY; - if (ioctl(s, SIOCG80211, &ireq) != -1) { - if (!ireq.i_val) + if ((ac & IEEE80211_WMEPARAM_BSS) == 0) { + if (get80211wme(s, IEEE80211_IOC_WME_ACKPOLICY, ac, &val) != -1) { + if (!val) printf(" -ack"); else if (verbose) printf(" ack"); } } printf("\n"); - if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) { - ireq.i_len |= IEEE80211_WMEPARAM_BSS; + if ((ac & IEEE80211_WMEPARAM_BSS) == 0) { + ac |= IEEE80211_WMEPARAM_BSS; goto again; } else - ireq.i_len &= ~IEEE80211_WMEPARAM_BSS; + ac &= ~IEEE80211_WMEPARAM_BSS; + } +} + +static void +printpolicy(int policy) +{ + switch (policy) { + case IEEE80211_MACCMD_POLICY_OPEN: + printf("policy: open\n"); + break; + case IEEE80211_MACCMD_POLICY_ALLOW: + printf("policy: allow\n"); + break; + case IEEE80211_MACCMD_POLICY_DENY: + printf("policy: deny\n"); + break; + default: + printf("policy: unknown (%u)\n", policy); + break; } } @@ -1904,7 +2432,8 @@ list_mac(int s) { struct ieee80211req ireq; struct ieee80211req_maclist *acllist; - int i, nacls, policy; + int i, nacls, policy, len; + uint8_t *data; char c; (void) memset(&ireq, 0, sizeof(ireq)); @@ -1919,41 +2448,39 @@ list_mac(int s) err(1, "unable to get mac policy"); } policy = ireq.i_val; - - ireq.i_val = IEEE80211_MACCMD_LIST; - ireq.i_len = 0; - if (ioctl(s, SIOCG80211, &ireq) < 0) - err(1, "unable to get mac acl list size"); - if (ireq.i_len == 0) /* NB: no acls */ - return; - - ireq.i_data = malloc(ireq.i_len); - if (ireq.i_data == NULL) - err(1, "out of memory for acl list"); - - if (ioctl(s, SIOCG80211, &ireq) < 0) - err(1, "unable to get mac acl list"); if (policy == IEEE80211_MACCMD_POLICY_OPEN) { - if (verbose) - printf("policy: open\n"); c = '*'; } else if (policy == IEEE80211_MACCMD_POLICY_ALLOW) { - if (verbose) - printf("policy: allow\n"); c = '+'; } else if (policy == IEEE80211_MACCMD_POLICY_DENY) { - if (verbose) - printf("policy: deny\n"); c = '-'; } else { printf("policy: unknown (%u)\n", policy); c = '?'; } - nacls = ireq.i_len / sizeof(*acllist); - acllist = (struct ieee80211req_maclist *) ireq.i_data; + if (verbose || c == '?') + printpolicy(policy); + + if (get80211len(s, IEEE80211_MACCMD_LIST, NULL, 0, &len) < 0) + err(1, "unable to get mac acl list size"); + if (len == 0) { /* NB: no acls */ + if (!(verbose || c == '?')) + printpolicy(policy); + return; + } + + data = malloc(len); + if (data == NULL) + err(1, "out of memory for acl list"); + + if (get80211(s, IEEE80211_MACCMD_LIST, data, len) < 0) + err(1, "unable to get mac acl list"); + nacls = len / sizeof(*acllist); + acllist = (struct ieee80211req_maclist *) data; for (i = 0; i < nacls; i++) printf("%c%s\n", c, ether_ntoa( (const struct ether_addr *) acllist[i].ml_macaddr)); + free(data); } static @@ -1961,6 +2488,8 @@ DECL_CMD_FUNC(set80211list, arg, d) { #define iseq(a,b) (strncasecmp(a,b,sizeof(b)-1) == 0) + LINE_INIT('\t'); + if (iseq(arg, "sta")) list_stations(s); else if (iseq(arg, "scan") || iseq(arg, "ap")) @@ -2039,40 +2568,6 @@ printcipher(int s, struct ieee80211req *ireq, int keylenop) } #endif -#define MAXCOL 78 -static int col; -static char spacer; - -static void -LINE_BREAK(void) -{ - if (spacer != '\t') { - printf("\n"); - spacer = '\t'; - } - col = 8; /* 8-col tab */ -} - -static void -LINE_CHECK(const char *fmt, ...) -{ - char buf[80]; - va_list ap; - int n; - - va_start(ap, fmt); - n = vsnprintf(buf+1, sizeof(buf)-1, fmt, ap); - va_end(ap); - col += 1+n; - if (col > MAXCOL) { - LINE_BREAK(); - col += n; - } - buf[0] = spacer; - printf("%s", buf); - spacer = ' '; -} - static void printkey(const struct ieee80211req_key *ik) { @@ -2141,144 +2636,164 @@ printkey(const struct ieee80211req_key *ik) } static void -ieee80211_status(int s) +printrate(const char *tag, int v, int defrate, int defmcs) +{ + if (v == 11) + LINE_CHECK("%s 5.5", tag); + else if (v & 0x80) { + if (v != defmcs) + LINE_CHECK("%s %d", tag, v &~ 0x80); + } else { + if (v != defrate) + LINE_CHECK("%s %d", tag, v/2); + } +} + +static int +getssid(int s, int ix, void *data, size_t len, int *plen) { - static const uint8_t zerobssid[IEEE80211_ADDR_LEN]; - enum ieee80211_opmode opmode = get80211opmode(s); - 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)); (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); - ireq.i_data = &data; + ireq.i_type = IEEE80211_IOC_SSID; + ireq.i_val = ix; + ireq.i_data = data; + ireq.i_len = len; + if (ioctl(s, SIOCG80211, &ireq) < 0) + return -1; + *plen = ireq.i_len; + return 0; +} - wpa = 0; /* unknown/not set */ - bgscan = 0; /* unknown/not set */ +static void +printrssi(const char *tag, int rssi) +{ + if (rssi & 1) + LINE_CHECK("%s %u.5", tag, rssi/2); + else + LINE_CHECK("%s %u", tag, rssi/2); +} - ireq.i_type = IEEE80211_IOC_SSID; - ireq.i_val = -1; - if (ioctl(s, SIOCG80211, &ireq) < 0) { +static void +ieee80211_status(int s) +{ + static const uint8_t zerobssid[IEEE80211_ADDR_LEN]; + enum ieee80211_opmode opmode = get80211opmode(s); + int i, num, wpa, wme, bgscan, bgscaninterval, val, len, wepmode; + uint8_t data[32]; + const struct ieee80211_channel *c; + + if (getssid(s, -1, data, sizeof(data), &len) < 0) { /* If we can't get the SSID, this isn't an 802.11 device. */ return; } - num = 0; - ireq.i_type = IEEE80211_IOC_NUMSSIDS; - if (ioctl(s, SIOCG80211, &ireq) >= 0) - num = ireq.i_val; + + /* + * Invalidate cached state so printing status for multiple + * if's doesn't reuse the first interfaces' cached state. + */ + gotcurchan = 0; + gothtconf = 0; + + if (get80211val(s, IEEE80211_IOC_NUMSSIDS, &num) < 0) + num = 0; printf("\tssid "); if (num > 1) { - ireq.i_type = IEEE80211_IOC_SSID; - for (ireq.i_val = 0; ireq.i_val < num; ireq.i_val++) { - if (ioctl(s, SIOCG80211, &ireq) >= 0 && ireq.i_len > 0) { - printf(" %d:", ireq.i_val + 1); - print_string(data, ireq.i_len); + for (i = 0; i < num; i++) { + if (getssid(s, i, data, sizeof(data), &len) >= 0 && len > 0) { + printf(" %d:", i + 1); + print_string(data, len); } } } else - print_string(data, ireq.i_len); + print_string(data, len); - 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; + c = getcurchan(s); 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"); - ireq.i_data = &data; /* reset data buffer */ - ireq.i_type = IEEE80211_IOC_BSSID; - ireq.i_len = IEEE80211_ADDR_LEN; - if (ioctl(s, SIOCG80211, &ireq) >= 0 && - (memcmp(ireq.i_data, zerobssid, sizeof(zerobssid)) != 0 || verbose)) - printf(" bssid %s", ether_ntoa(ireq.i_data)); + if (get80211(s, IEEE80211_IOC_BSSID, data, IEEE80211_ADDR_LEN) >= 0 && + (memcmp(data, zerobssid, sizeof(zerobssid)) != 0 || verbose)) + printf(" bssid %s", ether_ntoa((struct ether_addr *)data)); - ireq.i_type = IEEE80211_IOC_STATIONNAME; - if (ioctl(s, SIOCG80211, &ireq) != -1) { + if (get80211len(s, IEEE80211_IOC_STATIONNAME, data, sizeof(data), &len) != -1) { printf("\n\tstationname "); - print_string(data, ireq.i_len); + print_string(data, len); } spacer = ' '; /* force first break */ LINE_BREAK(); - ireq.i_type = IEEE80211_IOC_AUTHMODE; - if (ioctl(s, SIOCG80211, &ireq) != -1) { - switch (ireq.i_val) { - case IEEE80211_AUTH_NONE: - LINE_CHECK("authmode NONE"); - break; - case IEEE80211_AUTH_OPEN: - LINE_CHECK("authmode OPEN"); - break; - case IEEE80211_AUTH_SHARED: - LINE_CHECK("authmode SHARED"); - break; - case IEEE80211_AUTH_8021X: - LINE_CHECK("authmode 802.1x"); - break; - case IEEE80211_AUTH_WPA: - ireq.i_type = IEEE80211_IOC_WPA; - if (ioctl(s, SIOCG80211, &ireq) != -1) - wpa = ireq.i_val; - if (!wpa) - wpa = 1; /* default to WPA1 */ - switch (wpa) { - case 2: - LINE_CHECK("authmode WPA2/802.11i"); - break; - case 3: - LINE_CHECK("authmode WPA1+WPA2/802.11i"); - break; - default: - LINE_CHECK("authmode WPA"); - break; - } + wpa = 0; + if (get80211val(s, IEEE80211_IOC_AUTHMODE, &val) != -1) { + switch (val) { + case IEEE80211_AUTH_NONE: + LINE_CHECK("authmode NONE"); + break; + case IEEE80211_AUTH_OPEN: + LINE_CHECK("authmode OPEN"); + break; + case IEEE80211_AUTH_SHARED: + LINE_CHECK("authmode SHARED"); + break; + case IEEE80211_AUTH_8021X: + LINE_CHECK("authmode 802.1x"); + break; + case IEEE80211_AUTH_WPA: + if (get80211val(s, IEEE80211_IOC_WPA, &wpa) < 0) + wpa = 1; /* default to WPA1 */ + switch (wpa) { + case 2: + LINE_CHECK("authmode WPA2/802.11i"); break; - case IEEE80211_AUTH_AUTO: - LINE_CHECK("authmode AUTO"); + case 3: + LINE_CHECK("authmode WPA1+WPA2/802.11i"); break; default: - LINE_CHECK("authmode UNKNOWN (0x%x)", - ireq.i_val); + LINE_CHECK("authmode WPA"); break; + } + break; + case IEEE80211_AUTH_AUTO: + LINE_CHECK("authmode AUTO"); + break; + default: + LINE_CHECK("authmode UNKNOWN (0x%x)", val); + break; + } + } + + if (wpa || verbose) { + if (ioctl(s, IEEE80211_IOC_COUNTERMEASURES, &val) != -1) { + if (val) + LINE_CHECK("countermeasures"); + else if (verbose) + LINE_CHECK("-countermeasures"); } } - ireq.i_type = IEEE80211_IOC_WEP; - if (ioctl(s, SIOCG80211, &ireq) != -1 && - ireq.i_val != IEEE80211_WEP_NOSUP) { - int firstkey, wepmode; + if (get80211val(s, IEEE80211_IOC_WEP, &wepmode) != -1 && + wepmode != IEEE80211_WEP_NOSUP) { + int firstkey; - wepmode = ireq.i_val; switch (wepmode) { - case IEEE80211_WEP_OFF: - LINE_CHECK("privacy OFF"); - break; - case IEEE80211_WEP_ON: - LINE_CHECK("privacy ON"); - break; - case IEEE80211_WEP_MIXED: - LINE_CHECK("privacy MIXED"); - break; - default: - LINE_CHECK("privacy UNKNOWN (0x%x)", wepmode); - break; + case IEEE80211_WEP_OFF: + LINE_CHECK("privacy OFF"); + break; + case IEEE80211_WEP_ON: + LINE_CHECK("privacy ON"); + break; + case IEEE80211_WEP_MIXED: + LINE_CHECK("privacy MIXED"); + break; + default: + LINE_CHECK("privacy UNKNOWN (0x%x)", wepmode); + break; } /* @@ -2286,22 +2801,19 @@ ieee80211_status(int s) * to print WEP status. */ - ireq.i_type = IEEE80211_IOC_WEPTXKEY; - if (ioctl(s, SIOCG80211, &ireq) < 0) { + if (get80211val(s, IEEE80211_IOC_WEPTXKEY, &val) < 0) { warn("WEP support, but no tx key!"); goto end; } - if (ireq.i_val != -1) - LINE_CHECK("deftxkey %d", ireq.i_val+1); + if (val != -1) + LINE_CHECK("deftxkey %d", val+1); else if (wepmode != IEEE80211_WEP_OFF || verbose) LINE_CHECK("deftxkey UNDEF"); - ireq.i_type = IEEE80211_IOC_NUMWEPKEYS; - if (ioctl(s, SIOCG80211, &ireq) < 0) { + if (get80211val(s, IEEE80211_IOC_NUMWEPKEYS, &num) < 0) { warn("WEP support, but no NUMWEPKEYS support!"); goto end; } - num = ireq.i_val; firstkey = 1; for (i = 0; i < num; i++) { @@ -2309,10 +2821,7 @@ ieee80211_status(int s) memset(&ik, 0, sizeof(ik)); ik.ik_keyix = i; - ireq.i_type = IEEE80211_IOC_WPAKEY; - ireq.i_data = &ik; - ireq.i_len = sizeof(ik); - if (ioctl(s, SIOCG80211, &ireq) < 0) { + if (get80211(s, IEEE80211_IOC_WPAKEY, &ik, sizeof(ik)) < 0) { warn("WEP support, but can get keys!"); goto end; } @@ -2323,86 +2832,73 @@ ieee80211_status(int s) firstkey = 0; } } - ireq.i_data = &data; /* reset data buffer */ +end: + ; } - ireq.i_type = IEEE80211_IOC_POWERSAVE; - if (ioctl(s, SIOCG80211, &ireq) != -1 && - ireq.i_val != IEEE80211_POWERSAVE_NOSUP ) { - if (ireq.i_val != IEEE80211_POWERSAVE_OFF || verbose) { - switch (ireq.i_val) { - case IEEE80211_POWERSAVE_OFF: - LINE_CHECK("powersavemode OFF"); - break; - case IEEE80211_POWERSAVE_CAM: - LINE_CHECK("powersavemode CAM"); - break; - case IEEE80211_POWERSAVE_PSP: - LINE_CHECK("powersavemode PSP"); - break; - case IEEE80211_POWERSAVE_PSP_CAM: - LINE_CHECK("powersavemode PSP-CAM"); - break; + if (get80211val(s, IEEE80211_IOC_POWERSAVE, &val) != -1 && + val != IEEE80211_POWERSAVE_NOSUP ) { + if (val != IEEE80211_POWERSAVE_OFF || verbose) { + switch (val) { + case IEEE80211_POWERSAVE_OFF: + LINE_CHECK("powersavemode OFF"); + break; + case IEEE80211_POWERSAVE_CAM: + LINE_CHECK("powersavemode CAM"); + break; + case IEEE80211_POWERSAVE_PSP: + LINE_CHECK("powersavemode PSP"); + break; + case IEEE80211_POWERSAVE_PSP_CAM: + LINE_CHECK("powersavemode PSP-CAM"); + break; } - ireq.i_type = IEEE80211_IOC_POWERSAVESLEEP; - if (ioctl(s, SIOCG80211, &ireq) != -1) - LINE_CHECK("powersavesleep %d", ireq.i_val); + if (get80211val(s, IEEE80211_IOC_POWERSAVESLEEP, &val) != -1) + LINE_CHECK("powersavesleep %d", val); } } - ireq.i_type = IEEE80211_IOC_TXPOWMAX; - if (ioctl(s, SIOCG80211, &ireq) != -1) - LINE_CHECK("txpowmax %d", ireq.i_val); - + if (get80211val(s, IEEE80211_IOC_TXPOWER, &val) != -1) { + if (val & 1) + LINE_CHECK("txpower %d.5", val/2); + else + LINE_CHECK("txpower %d", val/2); + } if (verbose) { - ireq.i_type = IEEE80211_IOC_TXPOWER; - if (ioctl(s, SIOCG80211, &ireq) != -1) - LINE_CHECK("txpower %d", ireq.i_val); + if (get80211val(s, IEEE80211_IOC_TXPOWMAX, &val) != -1) + LINE_CHECK("txpowmax %.1f", val/2.); } - ireq.i_type = IEEE80211_IOC_RTSTHRESHOLD; - if (ioctl(s, SIOCG80211, &ireq) != -1) { - if (ireq.i_val != IEEE80211_RTS_MAX || verbose) - LINE_CHECK("rtsthreshold %d", ireq.i_val); + if (get80211val(s, IEEE80211_IOC_RTSTHRESHOLD, &val) != -1) { + if (val != IEEE80211_RTS_MAX || verbose) + LINE_CHECK("rtsthreshold %d", 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); + if (get80211val(s, IEEE80211_IOC_FRAGTHRESHOLD, &val) != -1) { + if (val != IEEE80211_FRAG_MAX || verbose) + LINE_CHECK("fragthreshold %d", 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) { - if (ireq.i_val == 11) - LINE_CHECK("mcastrate 5.5"); - else - LINE_CHECK("mcastrate %d", ireq.i_val/2); + if (opmode == IEEE80211_M_STA || verbose) { + if (get80211val(s, IEEE80211_IOC_BMISSTHRESHOLD, &val) != -1) { + if (val != IEEE80211_HWBMISS_MAX || verbose) + LINE_CHECK("bmiss %d", val); } } - ireq.i_type = IEEE80211_IOC_BGSCAN_INTERVAL; - if (ioctl(s, SIOCG80211, &ireq) != -1) - bgscaninterval = ireq.i_val; - else - bgscaninterval = -1; + if (get80211val(s, IEEE80211_IOC_MCAST_RATE, &val) != -1) + printrate("mcastrate", val, 2*1, 0/*XXX*/); - ireq.i_type = IEEE80211_IOC_SCANVALID; - if (ioctl(s, SIOCG80211, &ireq) != -1) { - if (ireq.i_val != bgscaninterval || verbose) - LINE_CHECK("scanvalid %u", ireq.i_val); + bgscaninterval = -1; + (void) get80211val(s, IEEE80211_IOC_BGSCAN_INTERVAL, &bgscaninterval); + + if (get80211val(s, IEEE80211_IOC_SCANVALID, &val) != -1) { + if (val != bgscaninterval || verbose) + LINE_CHECK("scanvalid %u", val); } - ireq.i_type = IEEE80211_IOC_BGSCAN; - if (ioctl(s, SIOCG80211, &ireq) != -1) { - bgscan = ireq.i_val; - if (ireq.i_val) + bgscan = 0; + if (get80211val(s, IEEE80211_IOC_BGSCAN, &bgscan) != -1) { + if (bgscan) LINE_CHECK("bgscan"); else if (verbose) LINE_CHECK("-bgscan"); @@ -2410,66 +2906,178 @@ ieee80211_status(int s) 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 (get80211val(s, IEEE80211_IOC_BGSCAN_IDLE, &val) != -1) + LINE_CHECK("bgscanidle %u", 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 (get80211val(s, IEEE80211_IOC_ROAM_RSSI_11A, &val) != -1) + printrssi("roam:rssi11a", val); + if (get80211val(s, IEEE80211_IOC_ROAM_RATE_11A, &val) != -1) + printrate("roam:rate11a", val, -1, -1); } 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 (get80211val(s, IEEE80211_IOC_ROAM_RSSI_11B, &val) != -1) + printrssi("roam:rssi11b", val); + if (get80211val(s, IEEE80211_IOC_ROAM_RATE_11B, &val) != -1) + printrate("roam:rate11b", val, -1, -1); } 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 (get80211val(s, IEEE80211_IOC_ROAM_RSSI_11G, &val) != -1) + printrssi("roam:rssi11g", val); + if (get80211val(s, IEEE80211_IOC_ROAM_RATE_11G, &val) != -1) + printrate("roam:rate11g", val, -1, -1); } } if (IEEE80211_IS_CHAN_ANYG(c) || verbose) { - ireq.i_type = IEEE80211_IOC_PUREG; - if (ioctl(s, SIOCG80211, &ireq) != -1) { - if (ireq.i_val) + if (get80211val(s, IEEE80211_IOC_PUREG, &val) != -1) { + if (val) LINE_CHECK("pureg"); else if (verbose) LINE_CHECK("-pureg"); } - ireq.i_type = IEEE80211_IOC_PROTMODE; - if (ioctl(s, SIOCG80211, &ireq) != -1) { - switch (ireq.i_val) { - case IEEE80211_PROTMODE_OFF: - LINE_CHECK("protmode OFF"); - break; - case IEEE80211_PROTMODE_CTS: - LINE_CHECK("protmode CTS"); - break; - case IEEE80211_PROTMODE_RTSCTS: - LINE_CHECK("protmode RTSCTS"); - break; - default: - LINE_CHECK("protmode UNKNOWN (0x%x)", - ireq.i_val); - break; + if (get80211val(s, IEEE80211_IOC_PROTMODE, &val) != -1) { + switch (val) { + case IEEE80211_PROTMODE_OFF: + LINE_CHECK("protmode OFF"); + break; + case IEEE80211_PROTMODE_CTS: + LINE_CHECK("protmode CTS"); + break; + case IEEE80211_PROTMODE_RTSCTS: + LINE_CHECK("protmode RTSCTS"); + break; + default: + LINE_CHECK("protmode UNKNOWN (0x%x)", val); + break; + } + } + } + + if (IEEE80211_IS_CHAN_HT(c) || verbose) { + gethtconf(s); + switch (htconf & 3) { + case 0: + case 2: + LINE_CHECK("-ht"); + break; + case 1: + LINE_CHECK("ht20"); + break; + case 3: + if (verbose) + LINE_CHECK("ht"); + break; + } + if (get80211val(s, IEEE80211_IOC_HTCOMPAT, &val) != -1) { + if (!val) + LINE_CHECK("-htcompat"); + else if (verbose) + LINE_CHECK("htcompat"); + } + if (get80211val(s, IEEE80211_IOC_AMPDU, &val) != -1) { + switch (val) { + case 0: + LINE_CHECK("-ampdu"); + break; + case 1: + LINE_CHECK("ampdutx -ampdurx"); + break; + case 2: + LINE_CHECK("-ampdutx ampdurx"); + break; + case 3: + if (verbose) + LINE_CHECK("ampdu"); + break; + } + } + if (get80211val(s, IEEE80211_IOC_AMPDU_LIMIT, &val) != -1) { + switch (val) { + case IEEE80211_HTCAP_MAXRXAMPDU_8K: + LINE_CHECK("ampdulimit 8k"); + break; + case IEEE80211_HTCAP_MAXRXAMPDU_16K: + LINE_CHECK("ampdulimit 16k"); + break; + case IEEE80211_HTCAP_MAXRXAMPDU_32K: + LINE_CHECK("ampdulimit 32k"); + break; + case IEEE80211_HTCAP_MAXRXAMPDU_64K: + LINE_CHECK("ampdulimit 64k"); + break; + } + } + if (get80211val(s, IEEE80211_IOC_AMPDU_DENSITY, &val) != -1) { + switch (val) { + case IEEE80211_HTCAP_MPDUDENSITY_NA: + if (verbose) + LINE_CHECK("ampdudensity -"); + break; + case IEEE80211_HTCAP_MPDUDENSITY_025: + LINE_CHECK("ampdudensity .25"); + break; + case IEEE80211_HTCAP_MPDUDENSITY_05: + LINE_CHECK("ampdudensity .5"); + break; + case IEEE80211_HTCAP_MPDUDENSITY_1: + LINE_CHECK("ampdudensity 1"); + break; + case IEEE80211_HTCAP_MPDUDENSITY_2: + LINE_CHECK("ampdudensity 2"); + break; + case IEEE80211_HTCAP_MPDUDENSITY_4: + LINE_CHECK("ampdudensity 4"); + break; + case IEEE80211_HTCAP_MPDUDENSITY_8: + LINE_CHECK("ampdudensity 8"); + break; + case IEEE80211_HTCAP_MPDUDENSITY_16: + LINE_CHECK("ampdudensity 16"); + break; } } + if (get80211val(s, IEEE80211_IOC_AMSDU, &val) != -1) { + switch (val) { + case 0: + LINE_CHECK("-amsdu"); + break; + case 1: + LINE_CHECK("amsdutx -amsdurx"); + break; + case 2: + LINE_CHECK("-amsdutx amsdurx"); + break; + case 3: + if (verbose) + LINE_CHECK("amsdu"); + break; + } + } + /* XXX amsdu limit */ + /* XXX 20/40 */ + if (get80211val(s, IEEE80211_IOC_SHORTGI, &val) != -1) { + if (val) + LINE_CHECK("shortgi"); + else if (verbose) + LINE_CHECK("-shortgi"); + } + if (get80211val(s, IEEE80211_IOC_HTPROTMODE, &val) != -1) { + if (val == IEEE80211_PROTMODE_OFF) + LINE_CHECK("htprotmode OFF"); + else if (val != IEEE80211_PROTMODE_RTSCTS) + LINE_CHECK("htprotmode UNKNOWN (0x%x)", val); + else if (verbose) + LINE_CHECK("htprotmode RTSCTS"); + } + if (get80211val(s, IEEE80211_IOC_PUREN, &val) != -1) { + if (val) + LINE_CHECK("puren"); + else if (verbose) + LINE_CHECK("-puren"); + } } - ireq.i_type = IEEE80211_IOC_WME; - if (ioctl(s, SIOCG80211, &ireq) != -1) { - wme = ireq.i_val; + if (get80211val(s, IEEE80211_IOC_WME, &wme) != -1) { if (wme) LINE_CHECK("wme"); else if (verbose) @@ -2477,62 +3085,58 @@ ieee80211_status(int s) } else wme = 0; - ireq.i_type = IEEE80211_IOC_BURST; - if (ioctl(s, SIOCG80211, &ireq) != -1) { - if (ireq.i_val) + if (get80211val(s, IEEE80211_IOC_BURST, &val) != -1) { + if (val) LINE_CHECK("burst"); else if (verbose) LINE_CHECK("-burst"); } - ireq.i_type = IEEE80211_IOC_FF; - if (ioctl(s, SIOCG80211, &ireq) != -1) { - if (ireq.i_val) + if (get80211val(s, IEEE80211_IOC_FF, &val) != -1) { + if (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) + if (get80211val(s, IEEE80211_IOC_TURBOP, &val) != -1) { + if (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) { - if (ireq.i_val) + if (get80211val(s, IEEE80211_IOC_HIDESSID, &val) != -1) { + if (val) LINE_CHECK("hidessid"); else if (verbose) LINE_CHECK("-hidessid"); } - - ireq.i_type = IEEE80211_IOC_APBRIDGE; - if (ioctl(s, SIOCG80211, &ireq) != -1) { - if (!ireq.i_val) + if (get80211val(s, IEEE80211_IOC_APBRIDGE, &val) != -1) { + if (!val) LINE_CHECK("-apbridge"); else if (verbose) LINE_CHECK("apbridge"); } + if (get80211val(s, IEEE80211_IOC_DTIM_PERIOD, &val) != -1) + LINE_CHECK("dtimperiod %u", val); - 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) + if (get80211val(s, IEEE80211_IOC_DOTH, &val) != -1) { + if (!val) LINE_CHECK("-doth"); else if (verbose) LINE_CHECK("doth"); } + if (get80211val(s, IEEE80211_IOC_INACTIVITY, &val) != -1) { + if (!val) + LINE_CHECK("-inact"); + else if (verbose) + LINE_CHECK("inact"); + } } else { - ireq.i_type = IEEE80211_IOC_ROAMING; - if (ioctl(s, SIOCG80211, &ireq) != -1) { - if (ireq.i_val != IEEE80211_ROAMING_AUTO || verbose) { - switch (ireq.i_val) { + if (get80211val(s, IEEE80211_IOC_ROAMING, &val) != -1) { + if (val != IEEE80211_ROAMING_AUTO || verbose) { + switch (val) { case IEEE80211_ROAMING_DEVICE: LINE_CHECK("roaming DEVICE"); break; @@ -2544,70 +3148,66 @@ ieee80211_status(int s) break; default: LINE_CHECK("roaming UNKNOWN (0x%x)", - ireq.i_val); + val); break; } } } } - ireq.i_type = IEEE80211_IOC_BEACON_INTERVAL; - if (ioctl(s, SIOCG80211, &ireq) != -1) { - if (ireq.i_val) - LINE_CHECK("bintval %u", ireq.i_val); - else if (verbose) - LINE_CHECK("bintval %u", ireq.i_val); + if (get80211val(s, IEEE80211_IOC_BEACON_INTERVAL, &val) != -1) { + /* XXX default define not visible */ + if (val != 100 || verbose) + LINE_CHECK("bintval %u", val); } if (wme && verbose) { LINE_BREAK(); list_wme(s); } + LINE_BREAK(); +} - if (wpa) { - ireq.i_type = IEEE80211_IOC_COUNTERMEASURES; - if (ioctl(s, SIOCG80211, &ireq) != -1) { - if (ireq.i_val) - LINE_CHECK("countermeasures"); - else if (verbose) - LINE_CHECK("-countermeasures"); - } -#if 0 - /* XXX not interesting with WPA done in user space */ - ireq.i_type = IEEE80211_IOC_KEYMGTALGS; - if (ioctl(s, SIOCG80211, &ireq) != -1) { - } +static int +get80211(int s, int type, void *data, int len) +{ + struct ieee80211req ireq; - ireq.i_type = IEEE80211_IOC_MCASTCIPHER; - if (ioctl(s, SIOCG80211, &ireq) != -1) { - LINE_CHECK("mcastcipher "); - printcipher(s, &ireq, IEEE80211_IOC_MCASTKEYLEN); - spacer = ' '; - } + (void) memset(&ireq, 0, sizeof(ireq)); + (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); + ireq.i_type = type; + ireq.i_data = data; + ireq.i_len = len; + return ioctl(s, SIOCG80211, &ireq); +} - ireq.i_type = IEEE80211_IOC_UCASTCIPHER; - if (ioctl(s, SIOCG80211, &ireq) != -1) { - LINE_CHECK("ucastcipher "); - printcipher(s, &ireq, IEEE80211_IOC_UCASTKEYLEN); - } +static int +get80211len(int s, int type, void *data, int len, int *plen) +{ + struct ieee80211req ireq; - if (wpa & 2) { - ireq.i_type = IEEE80211_IOC_RSNCAPS; - if (ioctl(s, SIOCG80211, &ireq) != -1) { - LINE_CHECK("RSN caps 0x%x", ireq.i_val); - spacer = ' '; - } - } + (void) memset(&ireq, 0, sizeof(ireq)); + (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); + ireq.i_type = type; + ireq.i_len = len; + ireq.i_data = data; + if (ioctl(s, SIOCG80211, &ireq) < 0) + return -1; + *plen = ireq.i_len; + return 0; +} - ireq.i_type = IEEE80211_IOC_UCASTCIPHERS; - if (ioctl(s, SIOCG80211, &ireq) != -1) { - } -#endif - LINE_BREAK(); - } - LINE_BREAK(); +static int +get80211val(int s, int type, int *val) +{ + struct ieee80211req ireq; -end: - return; + (void) memset(&ireq, 0, sizeof(ireq)); + (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name)); + ireq.i_type = type; + if (ioctl(s, SIOCG80211, &ireq) < 0) + return -1; + *val = ireq.i_val; + return 0; } static void @@ -2786,8 +3386,38 @@ static struct cmd ieee80211_cmds[] = { DEF_CMD("-burst", 0, set80211burst), DEF_CMD_ARG("bmiss", set80211bmissthreshold), DEF_CMD_ARG("bmissthreshold", set80211bmissthreshold), + DEF_CMD("shortgi", 1, set80211shortgi), + DEF_CMD("-shortgi", 0, set80211shortgi), + DEF_CMD("ampdurx", 2, set80211ampdu), + DEF_CMD("-ampdurx", -2, set80211ampdu), + DEF_CMD("ampdutx", 1, set80211ampdu), + DEF_CMD("-ampdutx", -1, set80211ampdu), + DEF_CMD("ampdu", 3, set80211ampdu), /* NB: tx+rx */ + DEF_CMD("-ampdu", -3, set80211ampdu), + DEF_CMD_ARG("ampdulimit", set80211ampdulimit), + DEF_CMD_ARG("ampdudensity", set80211ampdudensity), + DEF_CMD("amsdurx", 2, set80211amsdu), + DEF_CMD("-amsdurx", -2, set80211amsdu), + DEF_CMD("amsdutx", 1, set80211amsdu), + DEF_CMD("-amsdutx", -1, set80211amsdu), + DEF_CMD("amsdu", 3, set80211amsdu), /* NB: tx+rx */ + DEF_CMD("-amsdu", -3, set80211amsdu), + DEF_CMD_ARG("amsdulimit", set80211amsdulimit), + DEF_CMD("puren", 1, set80211puren), + DEF_CMD("-puren", 0, set80211puren), DEF_CMD("doth", 1, set80211doth), DEF_CMD("-doth", 0, set80211doth), + DEF_CMD("htcompat", 1, set80211htcompat), + DEF_CMD("-htcompat", 0, set80211htcompat), + DEF_CMD("inact", 1, set80211inact), + DEF_CMD("-inact", 0, set80211inact), + DEF_CMD_ARG("htprotmode", set80211htprotmode), + DEF_CMD("ht20", 1, set80211htconf), + DEF_CMD("-ht20", 0, set80211htconf), + DEF_CMD("ht40", 3, set80211htconf), /* NB: 20+40 */ + DEF_CMD("-ht40", 0, set80211htconf), + DEF_CMD("ht", 3, set80211htconf), /* NB: 20+40 */ + DEF_CMD("-ht", 0, set80211htconf), }; static struct afswtch af_ieee80211 = { .af_name = "af_ieee80211", |