summaryrefslogtreecommitdiffstats
path: root/sbin/ifconfig/ifieee80211.c
diff options
context:
space:
mode:
authorsam <sam@FreeBSD.org>2004-12-08 19:18:07 +0000
committersam <sam@FreeBSD.org>2004-12-08 19:18:07 +0000
commit68cd8761a723205e9d0dbd54067af7db9f163492 (patch)
tree65f511158298939a14f40a9fccf4ecc68b18c48a /sbin/ifconfig/ifieee80211.c
parentf947a8cc1cf9e160deab254a7ff4be233c0f56d3 (diff)
downloadFreeBSD-src-68cd8761a723205e9d0dbd54067af7db9f163492.zip
FreeBSD-src-68cd8761a723205e9d0dbd54067af7db9f163492.tar.gz
Overhaul to cleanup some of the tangled logic that's grown over the years.
o break per-address family support out into separate files o modularize per-address family and functional operations using a registration mechanism; this permits configuration according to which files you include (but beware that order of the files is important to insure backwards compatibility) o many cleanups to eliminate incestuous behaviour, global variables, and poor coding practices (still much more to fix) The original motivation of this work was to support dynamic addition of functionality based on the interface so we can eliminate the various little control programs and so that vendors can distribute ifconfig plugins that support their in-kernel code. That work is still to be completed. o Update 802.11 support for all the new net80211 functionality; some of these operations (e.g. list *) may be better suited in a different program
Diffstat (limited to 'sbin/ifconfig/ifieee80211.c')
-rw-r--r--sbin/ifconfig/ifieee80211.c1444
1 files changed, 1315 insertions, 129 deletions
diff --git a/sbin/ifconfig/ifieee80211.c b/sbin/ifconfig/ifieee80211.c
index 1e83e80..d7800d4 100644
--- a/sbin/ifconfig/ifieee80211.c
+++ b/sbin/ifconfig/ifieee80211.c
@@ -74,7 +74,9 @@
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_types.h>
+#include <net/if_media.h>
#include <net/route.h>
+
#include <net80211/ieee80211.h>
#include <net80211/ieee80211_crypto.h>
#include <net80211/ieee80211_ioctl.h>
@@ -95,7 +97,14 @@ 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);
-void
+static int
+isanyarg(const char *arg)
+{
+ return (strcmp(arg, "-") == 0 ||
+ strcasecmp(arg, "any") == 0 || strcasecmp(arg, "off") == 0);
+}
+
+static void
set80211ssid(const char *val, int d, int s, const struct afswtch *rafp)
{
int ssid;
@@ -116,7 +125,7 @@ set80211ssid(const char *val, int d, int s, const struct afswtch *rafp)
set80211(s, IEEE80211_IOC_SSID, ssid, len, data);
}
-void
+static void
set80211stationname(const char *val, int d, int s, const struct afswtch *rafp)
{
int len;
@@ -129,16 +138,49 @@ set80211stationname(const char *val, int d, int s, const struct afswtch *rafp)
set80211(s, IEEE80211_IOC_STATIONNAME, 0, len, data);
}
-void
+/*
+ * 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);
+}
+
+/*
+ * Convert MHz frequency to IEEE channel number.
+ */
+static u_int
+ieee80211_mhz2ieee(u_int freq)
+{
+ if (freq == 2484)
+ return 14;
+ if (freq < 2484)
+ return (freq - 2407) / 5;
+ if (freq < 5000)
+ return 15 + ((freq - 2512) / 20);
+ return (freq - 5000) / 5;
+}
+
+static void
set80211channel(const char *val, int d, int s, const struct afswtch *rafp)
{
- if (strcmp(val, "-") == 0)
+ if (!isanyarg(val)) {
+ int v = atoi(val);
+ if (v > 255) /* treat as frequency */
+ v = ieee80211_mhz2ieee(v);
+ set80211(s, IEEE80211_IOC_CHANNEL, v, 0, NULL);
+ } else
set80211(s, IEEE80211_IOC_CHANNEL, IEEE80211_CHAN_ANY, 0, NULL);
- else
- set80211(s, IEEE80211_IOC_CHANNEL, atoi(val), 0, NULL);
}
-void
+static void
set80211authmode(const char *val, int d, int s, const struct afswtch *rafp)
{
int mode;
@@ -149,6 +191,10 @@ set80211authmode(const char *val, int d, int s, const struct afswtch *rafp)
mode = IEEE80211_AUTH_OPEN;
} else if (strcasecmp(val, "shared") == 0) {
mode = IEEE80211_AUTH_SHARED;
+ } else if (strcasecmp(val, "8021x") == 0) {
+ mode = IEEE80211_AUTH_8021X;
+ } else if (strcasecmp(val, "wpa") == 0) {
+ mode = IEEE80211_AUTH_WPA;
} else {
err(1, "unknown authmode");
}
@@ -156,7 +202,7 @@ set80211authmode(const char *val, int d, int s, const struct afswtch *rafp)
set80211(s, IEEE80211_IOC_AUTHMODE, mode, 0, NULL);
}
-void
+static void
set80211powersavemode(const char *val, int d, int s, const struct afswtch *rafp)
{
int mode;
@@ -178,7 +224,7 @@ set80211powersavemode(const char *val, int d, int s, const struct afswtch *rafp)
set80211(s, IEEE80211_IOC_POWERSAVE, mode, 0, NULL);
}
-void
+static void
set80211powersave(const char *val, int d, int s, const struct afswtch *rafp)
{
if (d == 0)
@@ -189,13 +235,13 @@ set80211powersave(const char *val, int d, int s, const struct afswtch *rafp)
0, NULL);
}
-void
+static void
set80211powersavesleep(const char *val, int d, int s, const struct afswtch *rafp)
{
set80211(s, IEEE80211_IOC_POWERSAVESLEEP, atoi(val), 0, NULL);
}
-void
+static void
set80211wepmode(const char *val, int d, int s, const struct afswtch *rafp)
{
int mode;
@@ -213,19 +259,19 @@ set80211wepmode(const char *val, int d, int s, const struct afswtch *rafp)
set80211(s, IEEE80211_IOC_WEP, mode, 0, NULL);
}
-void
+static void
set80211wep(const char *val, int d, int s, const struct afswtch *rafp)
{
set80211(s, IEEE80211_IOC_WEP, d, 0, NULL);
}
-void
+static void
set80211weptxkey(const char *val, int d, int s, const struct afswtch *rafp)
{
set80211(s, IEEE80211_IOC_WEPTXKEY, atoi(val)-1, 0, NULL);
}
-void
+static void
set80211wepkey(const char *val, int d, int s, const struct afswtch *rafp)
{
int key = 0;
@@ -249,7 +295,7 @@ set80211wepkey(const char *val, int d, int s, const struct afswtch *rafp)
* iterface is too inflexable, but it's there so we'll support it since
* it's not all that hard.
*/
-void
+static void
set80211nwkey(const char *val, int d, int s, const struct afswtch *rafp)
{
int txkey;
@@ -285,13 +331,13 @@ set80211nwkey(const char *val, int d, int s, const struct afswtch *rafp)
set80211(s, IEEE80211_IOC_WEPTXKEY, txkey, 0, NULL);
}
-void
+static void
set80211rtsthreshold(const char *val, int d, int s, const struct afswtch *rafp)
{
set80211(s, IEEE80211_IOC_RTSTHRESHOLD, atoi(val), 0, NULL);
}
-void
+static void
set80211protmode(const char *val, int d, int s, const struct afswtch *rafp)
{
int mode;
@@ -309,159 +355,1048 @@ set80211protmode(const char *val, int d, int s, const struct afswtch *rafp)
set80211(s, IEEE80211_IOC_PROTMODE, mode, 0, NULL);
}
-void
+static void
set80211txpower(const char *val, int d, int s, const struct afswtch *rafp)
{
set80211(s, IEEE80211_IOC_TXPOWER, atoi(val), 0, NULL);
}
-void
-ieee80211_status (int s, struct rt_addrinfo *info __unused)
+#define IEEE80211_ROAMING_DEVICE 0
+#define IEEE80211_ROAMING_AUTO 1
+#define IEEE80211_ROAMING_MANUAL 2
+
+static void
+set80211roaming(const char *val, int d, int s, const struct afswtch *rafp)
{
- int i;
- int num;
- struct ieee80211req ireq;
- u_int8_t data[32];
- char spacer;
+ int mode;
+
+ if (strcasecmp(val, "device") == 0) {
+ mode = IEEE80211_ROAMING_DEVICE;
+ } else if (strcasecmp(val, "auto") == 0) {
+ mode = IEEE80211_ROAMING_AUTO;
+ } else if (strcasecmp(val, "manual") == 0) {
+ mode = IEEE80211_ROAMING_MANUAL;
+ } else {
+ err(1, "unknown roaming mode");
+ }
+ set80211(s, IEEE80211_IOC_ROAMING, mode, 0, NULL);
+}
+
+static void
+set80211wme(const char *val, int d, int s, const struct afswtch *rafp)
+{
+ set80211(s, IEEE80211_IOC_WME, d, 0, NULL);
+}
+
+static void
+set80211hidessid(const char *val, int d, int s, const struct afswtch *rafp)
+{
+ set80211(s, IEEE80211_IOC_HIDESSID, d, 0, NULL);
+}
+
+static void
+set80211apbridge(const char *val, int d, int s, const struct afswtch *rafp)
+{
+ set80211(s, IEEE80211_IOC_APBRIDGE, d, 0, NULL);
+}
+
+static void
+set80211chanlist(const char *val, int d, int s, const struct afswtch *rafp)
+{
+ struct ieee80211req_chanlist chanlist;
+#define MAXCHAN (sizeof(chanlist.ic_channels)*NBBY)
+ char *temp, *cp, *tp;
+
+ temp = malloc(strlen(val) + 1);
+ if (temp == NULL)
+ errx(1, "malloc failed");
+ strcpy(temp, val);
+ memset(&chanlist, 0, sizeof(chanlist));
+ cp = temp;
+ for (;;) {
+ int first, last, f;
+
+ tp = strchr(cp, ',');
+ if (tp != NULL)
+ *tp++ = '\0';
+ switch (sscanf(cp, "%u-%u", &first, &last)) {
+ case 1:
+ if (first > MAXCHAN)
+ errx(-1, "channel %u out of range, max %u",
+ first, MAXCHAN);
+ setbit(chanlist.ic_channels, first);
+ break;
+ case 2:
+ if (first > MAXCHAN)
+ errx(-1, "channel %u out of range, max %u",
+ first, MAXCHAN);
+ if (last > MAXCHAN)
+ errx(-1, "channel %u out of range, max %u",
+ last, MAXCHAN);
+ if (first > last)
+ errx(-1, "void channel range, %u > %u",
+ first, last);
+ for (f = first; f <= last; f++)
+ setbit(chanlist.ic_channels, f);
+ break;
+ }
+ if (tp == NULL)
+ break;
+ while (isspace(*tp))
+ tp++;
+ if (!isdigit(*tp))
+ break;
+ cp = tp;
+ }
+ set80211(s, IEEE80211_IOC_CHANLIST, 0,
+ sizeof(chanlist), (uint8_t *) &chanlist);
+#undef MAXCHAN
+}
+
+static void
+set80211bssid(const char *val, int d, int s, const struct afswtch *rafp)
+{
+
+ if (!isanyarg(val)) {
+ char *temp;
+ struct sockaddr_dl sdl;
+
+ temp = malloc(strlen(val) + 1);
+ if (temp == NULL)
+ errx(1, "malloc failed");
+ temp[0] = ':';
+ strcpy(temp + 1, val);
+ sdl.sdl_len = sizeof(sdl);
+ link_addr(temp, &sdl);
+ free(temp);
+ if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
+ errx(1, "malformed link-level address");
+ set80211(s, IEEE80211_IOC_BSSID, 0,
+ IEEE80211_ADDR_LEN, LLADDR(&sdl));
+ } else {
+ uint8_t zerobssid[IEEE80211_ADDR_LEN];
+ memset(zerobssid, 0, sizeof(zerobssid));
+ set80211(s, IEEE80211_IOC_BSSID, 0,
+ IEEE80211_ADDR_LEN, zerobssid);
+ }
+}
+
+static int
+getac(const char *ac)
+{
+ if (strcasecmp(ac, "ac_be") == 0 || strcasecmp(ac, "be") == 0)
+ return WME_AC_BE;
+ if (strcasecmp(ac, "ac_bk") == 0 || strcasecmp(ac, "bk") == 0)
+ return WME_AC_BK;
+ if (strcasecmp(ac, "ac_vi") == 0 || strcasecmp(ac, "vi") == 0)
+ return WME_AC_VI;
+ if (strcasecmp(ac, "ac_vo") == 0 || strcasecmp(ac, "vo") == 0)
+ return WME_AC_VO;
+ errx(1, "unknown wme access class %s", ac);
+}
+
+static
+DECL_CMD_FUNC2(set80211cwmin, ac, val)
+{
+ set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val), getac(ac), NULL);
+}
+
+static
+DECL_CMD_FUNC2(set80211cwmax, ac, val)
+{
+ set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val), getac(ac), NULL);
+}
+
+static
+DECL_CMD_FUNC2(set80211aifs, ac, val)
+{
+ set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val), getac(ac), NULL);
+}
+
+static
+DECL_CMD_FUNC2(set80211txoplimit, ac, val)
+{
+ set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val), getac(ac), NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211acm, val, d)
+{
+ set80211(s, IEEE80211_IOC_WME_ACM, d, WME_AC_BE, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211ackpolicy, val, d)
+{
+ set80211(s, IEEE80211_IOC_WME_ACKPOLICY, d, WME_AC_BE, NULL);
+}
+
+static
+DECL_CMD_FUNC2(set80211bsscwmin, ac, val)
+{
+ set80211(s, IEEE80211_IOC_WME_CWMIN, atoi(val),
+ getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
+}
+
+static
+DECL_CMD_FUNC2(set80211bsscwmax, ac, val)
+{
+ set80211(s, IEEE80211_IOC_WME_CWMAX, atoi(val),
+ getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
+}
+
+static
+DECL_CMD_FUNC2(set80211bssaifs, ac, val)
+{
+ set80211(s, IEEE80211_IOC_WME_AIFS, atoi(val),
+ getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
+}
+
+static
+DECL_CMD_FUNC2(set80211bsstxoplimit, ac, val)
+{
+ set80211(s, IEEE80211_IOC_WME_TXOPLIMIT, atoi(val),
+ getac(ac)|IEEE80211_WMEPARAM_BSS, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211dtimperiod, val, d)
+{
+ set80211(s, IEEE80211_IOC_DTIM_PERIOD, atoi(val), 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211bintval, val, d)
+{
+ set80211(s, IEEE80211_IOC_BEACON_INTERVAL, atoi(val), 0, NULL);
+}
+
+static void
+set80211macmac(int s, int op, const char *val)
+{
+ char *temp;
+ struct sockaddr_dl sdl;
+
+ temp = malloc(strlen(val) + 1);
+ if (temp == NULL)
+ errx(1, "malloc failed");
+ temp[0] = ':';
+ strcpy(temp + 1, val);
+ sdl.sdl_len = sizeof(sdl);
+ link_addr(temp, &sdl);
+ free(temp);
+ if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
+ errx(1, "malformed link-level address");
+ set80211(s, op, 0, IEEE80211_ADDR_LEN, LLADDR(&sdl));
+}
+
+static
+DECL_CMD_FUNC(set80211addmac, val, d)
+{
+ set80211macmac(s, IEEE80211_IOC_ADDMAC, val);
+}
+
+static
+DECL_CMD_FUNC(set80211delmac, val, d)
+{
+ set80211macmac(s, IEEE80211_IOC_DELMAC, val);
+}
+
+static
+DECL_CMD_FUNC(set80211maccmd, val, d)
+{
+ set80211(s, IEEE80211_IOC_MACCMD, d, 0, NULL);
+}
+
+static int
+getmaxrate(uint8_t rates[15], uint8_t nrates)
+{
+ int i, maxrate = -1;
+
+ for (i = 0; i < nrates; i++) {
+ int rate = rates[i] & IEEE80211_RATE_VAL;
+ if (rate > maxrate)
+ maxrate = rate;
+ }
+ return maxrate / 2;
+}
+
+static const char *
+getcaps(int capinfo)
+{
+ static char capstring[32];
+ char *cp = capstring;
+
+ if (capinfo & IEEE80211_CAPINFO_ESS)
+ *cp++ = 'E';
+ if (capinfo & IEEE80211_CAPINFO_IBSS)
+ *cp++ = 'I';
+ if (capinfo & IEEE80211_CAPINFO_CF_POLLABLE)
+ *cp++ = 'c';
+ if (capinfo & IEEE80211_CAPINFO_CF_POLLREQ)
+ *cp++ = 'C';
+ if (capinfo & IEEE80211_CAPINFO_PRIVACY)
+ *cp++ = 'P';
+ if (capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)
+ *cp++ = 'S';
+ if (capinfo & IEEE80211_CAPINFO_PBCC)
+ *cp++ = 'B';
+ if (capinfo & IEEE80211_CAPINFO_CHNL_AGILITY)
+ *cp++ = 'A';
+ if (capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)
+ *cp++ = 's';
+ if (capinfo & IEEE80211_CAPINFO_RSN)
+ *cp++ = 'R';
+ if (capinfo & IEEE80211_CAPINFO_DSSSOFDM)
+ *cp++ = 'D';
+ *cp = '\0';
+ return capstring;
+}
+
+static void
+printie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen)
+{
+ printf("%s", tag);
+ if (verbose) {
+ maxlen -= strlen(tag)+2;
+ if (2*ielen > maxlen)
+ maxlen--;
+ printf("<");
+ for (; ielen > 0; ie++, ielen--) {
+ if (maxlen-- <= 0)
+ break;
+ printf("%02x", *ie);
+ }
+ if (ielen != 0)
+ printf("-");
+ printf(">");
+ }
+}
+
+/*
+ * Copy the ssid string contents into buf, truncating to fit. If the
+ * ssid is entirely printable then just copy intact. Otherwise convert
+ * to hexadecimal. If the result is truncated then replace the last
+ * three characters with "...".
+ */
+static size_t
+copy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len)
+{
+ const u_int8_t *p;
+ size_t maxlen;
+ int i;
+
+ if (essid_len > bufsize)
+ maxlen = bufsize;
+ else
+ maxlen = essid_len;
+ /* determine printable or not */
+ for (i = 0, p = essid; i < maxlen; i++, p++) {
+ if (*p < ' ' || *p > 0x7e)
+ break;
+ }
+ if (i != maxlen) { /* not printable, print as hex */
+ if (bufsize < 3)
+ return 0;
+ strlcpy(buf, "0x", bufsize);
+ bufsize -= 2;
+ p = essid;
+ for (i = 0; i < maxlen && bufsize >= 2; i++) {
+ sprintf(&buf[2+2*i], "%02x", *p++);
+ bufsize -= 2;
+ }
+ maxlen = 2+2*i;
+ } else { /* printable, truncate as needed */
+ memcpy(buf, essid, maxlen);
+ }
+ if (maxlen != essid_len)
+ memcpy(buf+maxlen-3, "...", 3);
+ return maxlen;
+}
+
+/* unalligned little endian access */
+#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)))
+
+static int __inline
+iswpaoui(const u_int8_t *frm)
+{
+ return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
+}
+
+static int __inline
+iswmeoui(const u_int8_t *frm)
+{
+ return frm[1] > 3 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI);
+}
+
+static int __inline
+isatherosoui(const u_int8_t *frm)
+{
+ return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI);
+}
+
+static void
+printies(const u_int8_t *vp, int ielen, int maxcols)
+{
+ while (ielen > 0) {
+ switch (vp[0]) {
+ case IEEE80211_ELEMID_VENDOR:
+ if (iswpaoui(vp))
+ printie(" WPA", vp, 2+vp[1], maxcols);
+ else if (iswmeoui(vp))
+ printie(" WME", 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);
+ break;
+ default:
+ printie(" ???", vp, 2+vp[1], maxcols);
+ break;
+ }
+ ielen -= 2+vp[1];
+ vp += 2+vp[1];
+ }
+}
+
+static void
+list_scan(int s)
+{
+ uint8_t buf[24*1024];
+ struct ieee80211req ireq;
+ char ssid[14];
+ uint8_t *cp;
+ int len;
+
+ (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)
+ errx(1, "unable to get scan results");
+ len = ireq.i_len;
+ if (len < sizeof(struct ieee80211req_scan_result))
+ return;
+
+ printf("%-14.14s %-17.17s %4s %4s %-5s %3s %4s\n"
+ , "SSID"
+ , "BSSID"
+ , "CHAN"
+ , "RATE"
+ , "S:N"
+ , "INT"
+ , "CAPS"
+ );
+ cp = buf;
+ do {
+ struct ieee80211req_scan_result *sr;
+ uint8_t *vp;
+
+ sr = (struct ieee80211req_scan_result *) cp;
+ vp = (u_int8_t *)(sr+1);
+ printf("%-14.*s %s %3d %3dM %2d:%-2d %3d %-4.4s"
+ , copy_essid(ssid, sizeof(ssid), vp, sr->isr_ssid_len)
+ , ssid
+ , ether_ntoa((const struct ether_addr *) sr->isr_bssid)
+ , ieee80211_mhz2ieee(sr->isr_freq)
+ , getmaxrate(sr->isr_rates, sr->isr_nrates)
+ , sr->isr_rssi, sr->isr_noise
+ , sr->isr_intval
+ , getcaps(sr->isr_capinfo)
+ );
+ 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));
+}
+
+#include <net80211/ieee80211_freebsd.h>
+
+static void
+scan_and_wait(int s)
+{
+ struct ieee80211req ireq;
+ int sroute;
+
+ sroute = socket(PF_ROUTE, SOCK_RAW, 0);
+ if (sroute < 0) {
+ perror("socket(PF_ROUTE,SOCK_RAW)");
+ return;
+ }
+ (void) memset(&ireq, 0, sizeof(ireq));
+ (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+ ireq.i_type = IEEE80211_IOC_SCAN_REQ;
+ /* NB: only root can trigger a scan so ignore errors */
+ if (ioctl(s, SIOCS80211, &ireq) >= 0) {
+ char buf[2048];
+ struct if_announcemsghdr *ifan;
+ struct rt_msghdr *rtm;
+
+ do {
+ if (read(sroute, buf, sizeof(buf)) < 0) {
+ perror("read(PF_ROUTE)");
+ break;
+ }
+ rtm = (struct rt_msghdr *) buf;
+ if (rtm->rtm_version != RTM_VERSION)
+ break;
+ ifan = (struct if_announcemsghdr *) rtm;
+ } while (rtm->rtm_type != RTM_IEEE80211 ||
+ ifan->ifan_what != RTM_IEEE80211_SCAN);
+ }
+ close(sroute);
+}
+
+static
+DECL_CMD_FUNC(set80211scan, val, d)
+{
+ scan_and_wait(s);
+ list_scan(s);
+}
+
+static void
+list_stations(int s)
+{
+ uint8_t buf[24*1024];
+ struct ieee80211req ireq;
+ uint8_t *cp;
+ int len;
+
+ (void) memset(&ireq, 0, sizeof(ireq));
+ (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+ ireq.i_type = IEEE80211_IOC_STA_INFO;
+ ireq.i_data = buf;
+ ireq.i_len = sizeof(buf);
+ if (ioctl(s, SIOCG80211, &ireq) < 0)
+ errx(1, "unable to get station information");
+ len = ireq.i_len;
+ if (len < sizeof(struct ieee80211req_sta_info))
+ return;
+
+ printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %3s\n"
+ , "ADDR"
+ , "AID"
+ , "CHAN"
+ , "RATE"
+ , "RSSI"
+ , "IDLE"
+ , "TXSEQ"
+ , "RXSEQ"
+ , "CAPS"
+ , "ERP"
+ );
+ cp = buf;
+ do {
+ struct ieee80211req_sta_info *si;
+ uint8_t *vp;
+
+ si = (struct ieee80211req_sta_info *) cp;
+ vp = (u_int8_t *)(si+1);
+ printf("%s %4u %4d %3dM %4d %4d %6d %6d %-4.4s %3x"
+ , ether_ntoa((const struct ether_addr*) si->isi_macaddr)
+ , IEEE80211_AID(si->isi_associd)
+ , ieee80211_mhz2ieee(si->isi_freq)
+ , (si->isi_rates[si->isi_txrate] & IEEE80211_RATE_VAL)/2
+ , si->isi_rssi
+ , si->isi_inact
+ , si->isi_txseqs[0]
+ , si->isi_rxseqs[0]
+ , getcaps(si->isi_capinfo)
+ , si->isi_erp
+ );
+ printies(vp, 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)
+{
+#define IEEE80211_IS_CHAN_PASSIVE(_c) \
+ (((_c)->ic_flags & IEEE80211_CHAN_PASSIVE))
+ char buf[14];
+
+ buf[0] = '\0';
+ if (IEEE80211_IS_CHAN_FHSS(c))
+ strlcat(buf, " FHSS", sizeof(buf));
+ if (IEEE80211_IS_CHAN_A(c))
+ strlcat(buf, " 11a", sizeof(buf));
+ /* XXX 11g schizophrenia */
+ if (IEEE80211_IS_CHAN_G(c) ||
+ IEEE80211_IS_CHAN_PUREG(c))
+ strlcat(buf, " 11g", sizeof(buf));
+ else if (IEEE80211_IS_CHAN_B(c))
+ strlcat(buf, " 11b", sizeof(buf));
+ if (IEEE80211_IS_CHAN_T(c))
+ strlcat(buf, " Turbo", sizeof(buf));
+ printf("Channel %3u : %u%c Mhz%-14.14s",
+ ieee80211_mhz2ieee(c->ic_freq), c->ic_freq,
+ IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ', buf);
+#undef IEEE80211_IS_CHAN_PASSIVE
+}
+
+static void
+list_channels(int s, int allchans)
+{
+ struct ieee80211req ireq;
+ struct ieee80211req_chaninfo chans;
+ struct ieee80211req_chaninfo achans;
+ const struct ieee80211_channel *c;
+ 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");
+ if (!allchans) {
+ struct ieee80211req_chanlist active;
+
+ 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];
+ if (isset(active.ic_channels, ieee80211_mhz2ieee(c->ic_freq)) || allchans)
+ achans.ic_chans[achans.ic_nchans++] = *c;
+ }
+ } else
+ achans = chans;
+ 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]);
+ printf("\n");
+ }
+ if (achans.ic_nchans % 2) {
+ print_chaninfo(&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" \
+"\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE\21MONITOR\22TKIPMIC\30WPA1" \
+"\31WPA2\32BURST\33WME"
+
+static void
+list_capabilities(int s)
+{
+ struct ieee80211req ireq;
+ u_int32_t caps;
+
+ (void) memset(&ireq, 0, sizeof(ireq));
+ (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+ ireq.i_type = IEEE80211_IOC_DRIVER_CAPS;
+ if (ioctl(s, SIOCG80211, &ireq) < 0)
+ errx(1, "unable to get driver capabilities");
+ caps = (((u_int16_t) ireq.i_val) << 16) | ((u_int16_t) ireq.i_len);
+ printb(name, caps, IEEE80211_C_BITS);
+ putchar('\n');
+}
+
+static void
+list_wme(int s)
+{
+ 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;
+ for (ac = WME_AC_BE; ac <= WME_AC_VO; ac++) {
+again:
+ if (ireq.i_len & 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)
+ 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)
+ printf(" -ack");
+ else if (verbose)
+ printf(" ack");
+ }
+ }
+ printf("\n");
+ if ((ireq.i_len & IEEE80211_WMEPARAM_BSS) == 0) {
+ ireq.i_len |= IEEE80211_WMEPARAM_BSS;
+ goto again;
+ } else
+ ireq.i_len &= ~IEEE80211_WMEPARAM_BSS;
+ }
+}
+
+static
+DECL_CMD_FUNC(set80211list, arg, d)
+{
+#define iseq(a,b) (strncasecmp(a,b,sizeof(b)-1) == 0)
+
+ if (iseq(arg, "sta"))
+ list_stations(s);
+ else if (iseq(arg, "scan") || iseq(arg, "ap"))
+ list_scan(s);
+ else if (iseq(arg, "chan") || iseq(arg, "freq"))
+ list_channels(s, 1);
+ else if (iseq(arg, "active"))
+ list_channels(s, 0);
+ else if (iseq(arg, "keys"))
+ list_keys(s);
+ else if (iseq(arg, "caps"))
+ list_capabilities(s);
+ else if (iseq(arg, "wme"))
+ list_wme(s);
+ else
+ errx(1, "Don't know how to list %s for %s", arg, name);
+#undef iseq
+}
+
+static enum ieee80211_opmode
+get80211opmode(int s)
+{
+ struct ifmediareq ifmr;
+
+ (void) memset(&ifmr, 0, sizeof(ifmr));
+ (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
+
+ if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) {
+ if (ifmr.ifm_current & IFM_IEEE80211_ADHOC)
+ return IEEE80211_M_IBSS; /* XXX ahdemo */
+ if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP)
+ return IEEE80211_M_HOSTAP;
+ if (ifmr.ifm_current & IFM_IEEE80211_MONITOR)
+ return IEEE80211_M_MONITOR;
+ }
+ 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)
+{
+ switch (ireq->i_val) {
+ case IEEE80211_CIPHER_WEP:
+ ireq->i_type = keylenop;
+ if (ioctl(s, SIOCG80211, ireq) != -1)
+ printf("WEP-%s",
+ ireq->i_len <= 5 ? "40" :
+ ireq->i_len <= 13 ? "104" : "128");
+ else
+ printf("WEP");
+ break;
+ case IEEE80211_CIPHER_TKIP:
+ printf("TKIP");
+ break;
+ case IEEE80211_CIPHER_AES_OCB:
+ printf("AES-OCB");
+ break;
+ case IEEE80211_CIPHER_AES_CCM:
+ printf("AES-CCM");
+ break;
+ case IEEE80211_CIPHER_CKIP:
+ printf("CKIP");
+ break;
+ case IEEE80211_CIPHER_NONE:
+ printf("NONE");
+ break;
+ default:
+ printf("UNKNOWN (0x%x)", ireq->i_val);
+ break;
+ }
+}
+#endif
+
+#define MAXCOL 78
+int col;
+char spacer;
+
+#define LINE_BREAK() do { \
+ if (spacer != '\t') { \
+ printf("\n"); \
+ spacer = '\t'; \
+ } \
+ col = 8; /* 8-col tab */ \
+} while (0)
+#define LINE_CHECK(fmt, ...) do { \
+ col += sizeof(fmt)-2; \
+ if (col > MAXCOL) { \
+ LINE_BREAK(); \
+ col += sizeof(fmt)-2; \
+ } \
+ printf(fmt, __VA_ARGS__); \
+ spacer = ' '; \
+} while (0)
+
+static void
+printkey(const struct ieee80211req_key *ik)
+{
+ static const uint8_t zerodata[IEEE80211_KEYBUF_SIZE];
+ int keylen = ik->ik_keylen;
+ int printcontents;
+
+ printcontents =
+ (memcmp(ik->ik_keydata, zerodata, keylen) != 0 || verbose);
+ if (printcontents)
+ LINE_BREAK();
+ switch (ik->ik_type) {
+ case IEEE80211_CIPHER_WEP:
+ /* compatibility */
+ LINE_CHECK("%cwepkey %u:%s", spacer, ik->ik_keyix+1,
+ keylen <= 5 ? "40-bit" :
+ keylen <= 13 ? "104-bit" : "128-bit");
+ break;
+ case IEEE80211_CIPHER_TKIP:
+ if (keylen > 128/8)
+ keylen -= 128/8; /* ignore MIC for now */
+ LINE_CHECK("%cTKIP %u:%u-bit",
+ spacer, ik->ik_keyix+1, 8*keylen);
+ break;
+ case IEEE80211_CIPHER_AES_OCB:
+ LINE_CHECK("%cAES-OCB %u:%u-bit",
+ spacer, ik->ik_keyix+1, 8*keylen);
+ break;
+ case IEEE80211_CIPHER_AES_CCM:
+ LINE_CHECK("%cAES-CCM %u:%u-bit",
+ spacer, ik->ik_keyix+1, 8*keylen);
+ break;
+ case IEEE80211_CIPHER_CKIP:
+ LINE_CHECK("%cCKIP %u:%u-bit",
+ spacer, ik->ik_keyix+1, 8*keylen);
+ break;
+ case IEEE80211_CIPHER_NONE:
+ LINE_CHECK("%cNULL %u:%u-bit",
+ spacer, ik->ik_keyix+1, 8*keylen);
+ break;
+ default:
+ LINE_CHECK("%cUNKNOWN (0x%x) %u:%u-bit", spacer,
+ ik->ik_type, ik->ik_keyix+1, 8*keylen);
+ break;
+ }
+ if (printcontents) {
+ int i;
+
+ printf(" <");
+ for (i = 0; i < keylen; i++)
+ printf("%02x", ik->ik_keydata[i]);
+ printf(">");
+ if (ik->ik_type != IEEE80211_CIPHER_WEP &&
+ (ik->ik_keyrsc != 0 || verbose))
+ printf(" rsc %llu", ik->ik_keyrsc);
+ if (ik->ik_type != IEEE80211_CIPHER_WEP &&
+ (ik->ik_keytsc != 0 || verbose))
+ printf(" tsc %llu", ik->ik_keytsc);
+ if (ik->ik_flags != 0 && verbose) {
+ const char *sep = " ";
+
+ if (ik->ik_flags & IEEE80211_KEY_XMIT)
+ printf("%stx", sep), sep = "+";
+ if (ik->ik_flags & IEEE80211_KEY_RECV)
+ printf("%srx", sep), sep = "+";
+ if (ik->ik_flags & IEEE80211_KEY_DEFAULT)
+ printf("%sdef", sep), sep = "+";
+ }
+ LINE_BREAK();
+ }
+}
+
+static void
+ieee80211_status(int s, const struct rt_addrinfo *info __unused)
+{
+ static const uint8_t zerobssid[IEEE80211_ADDR_LEN];
+ enum ieee80211_opmode opmode = get80211opmode(s);
+ int i, num, wpa, wme;
+ struct ieee80211req ireq;
+ u_int8_t data[32];
+ 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;
+ wpa = 0; /* unknown/not set */
+
ireq.i_type = IEEE80211_IOC_SSID;
ireq.i_val = -1;
if (ioctl(s, SIOCG80211, &ireq) < 0) {
/* If we can't get the SSID, the this isn't an 802.11 device. */
return;
}
- printf("\tssid ");
- print_string(data, ireq.i_len);
num = 0;
ireq.i_type = IEEE80211_IOC_NUMSSIDS;
- if (ioctl(s, SIOCG80211, &ireq) >= 0) {
+ if (ioctl(s, SIOCG80211, &ireq) >= 0)
num = ireq.i_val;
- }
- 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);
+ 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);
+ }
}
- }
- printf("\n");
+ } 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);
+ } else if (verbose)
+ printf(" channel UNDEF");
+
+ 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)
+ printf(" bssid %s", ether_ntoa(ireq.i_data));
ireq.i_type = IEEE80211_IOC_STATIONNAME;
if (ioctl(s, SIOCG80211, &ireq) != -1) {
- printf("\tstationname ");
+ printf("\n\tstationname ");
print_string(data, ireq.i_len);
- printf("\n");
}
- ireq.i_type = IEEE80211_IOC_CHANNEL;
- if (ioctl(s, SIOCG80211, &ireq) < 0) {
- goto end;
- }
- printf("\tchannel %d", ireq.i_val);
+ spacer = ' '; /* force first break */
+ LINE_BREAK();
ireq.i_type = IEEE80211_IOC_AUTHMODE;
if (ioctl(s, SIOCG80211, &ireq) != -1) {
- printf(" authmode");
switch (ireq.i_val) {
case IEEE80211_AUTH_NONE:
- printf(" NONE");
+ LINE_CHECK("%cauthmode NONE", spacer);
break;
case IEEE80211_AUTH_OPEN:
- printf(" OPEN");
+ LINE_CHECK("%cauthmode OPEN", spacer);
break;
case IEEE80211_AUTH_SHARED:
- printf(" SHARED");
+ LINE_CHECK("%cauthmode SHARED", spacer);
break;
- default:
- printf(" UNKNOWN");
+ case IEEE80211_AUTH_8021X:
+ LINE_CHECK("%cauthmode 802.1x", spacer);
break;
- }
- }
-
- ireq.i_type = IEEE80211_IOC_POWERSAVE;
- if (ioctl(s, SIOCG80211, &ireq) != -1 &&
- ireq.i_val != IEEE80211_POWERSAVE_NOSUP ) {
- printf(" powersavemode");
- switch (ireq.i_val) {
- case IEEE80211_POWERSAVE_OFF:
- printf(" OFF");
- break;
- case IEEE80211_POWERSAVE_CAM:
- printf(" CAM");
+ 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("%cauthmode WPA2/802.11i",
+ spacer);
+ break;
+ case 3:
+ LINE_CHECK("%cauthmode WPA1+WPA2/802.11i",
+ spacer);
+ break;
+ default:
+ LINE_CHECK("%cauthmode WPA", spacer);
+ break;
+ }
break;
- case IEEE80211_POWERSAVE_PSP:
- printf(" PSP");
- break;
- case IEEE80211_POWERSAVE_PSP_CAM:
- printf(" PSP-CAM");
- break;
- }
-
- ireq.i_type = IEEE80211_IOC_POWERSAVESLEEP;
- if (ioctl(s, SIOCG80211, &ireq) != -1) {
- if (ireq.i_val)
- printf(" powersavesleep %d", ireq.i_val);
- }
- }
-
- printf("\n");
-
- spacer = '\t';
- ireq.i_type = IEEE80211_IOC_RTSTHRESHOLD;
- if (ioctl(s, SIOCG80211, &ireq) != -1) {
- printf("%crtsthreshold %d", spacer, ireq.i_val);
- spacer = ' ';
- }
-
- ireq.i_type = IEEE80211_IOC_PROTMODE;
- if (ioctl(s, SIOCG80211, &ireq) != -1) {
- printf("%cprotmode", spacer);
- switch (ireq.i_val) {
- case IEEE80211_PROTMODE_OFF:
- printf(" OFF");
- break;
- case IEEE80211_PROTMODE_CTS:
- printf(" CTS");
- break;
- case IEEE80211_PROTMODE_RTSCTS:
- printf(" RTSCTS");
+ case IEEE80211_AUTH_AUTO:
+ LINE_CHECK("%cauthmode AUTO", spacer);
break;
default:
- printf(" UNKNOWN");
+ LINE_CHECK("%cauthmode UNKNOWN (0x%x)",
+ spacer, ireq.i_val);
break;
}
- spacer = ' ';
- }
-
- ireq.i_type = IEEE80211_IOC_TXPOWER;
- if (ioctl(s, SIOCG80211, &ireq) != -1) {
- printf("%ctxpower %d", spacer, ireq.i_val);
- spacer = ' ';
}
- if (spacer != '\t')
- printf("\n");
-
ireq.i_type = IEEE80211_IOC_WEP;
if (ioctl(s, SIOCG80211, &ireq) != -1 &&
ireq.i_val != IEEE80211_WEP_NOSUP) {
- printf("\twepmode");
+ int firstkey;
+
switch (ireq.i_val) {
case IEEE80211_WEP_OFF:
- printf(" OFF");
+ LINE_CHECK("%cprivacy OFF", spacer);
break;
case IEEE80211_WEP_ON:
- printf(" ON");
+ LINE_CHECK("%cprivacy ON", spacer);
break;
case IEEE80211_WEP_MIXED:
- printf(" MIXED");
+ LINE_CHECK("%cprivacy MIXED", spacer);
break;
default:
- printf(" UNKNOWN");
+ LINE_CHECK("%cprivacy UNKNOWN (0x%x)",
+ spacer, ireq.i_val);
break;
}
@@ -475,7 +1410,10 @@ ieee80211_status (int s, struct rt_addrinfo *info __unused)
warn("WEP support, but no tx key!");
goto end;
}
- printf(" weptxkey %d", ireq.i_val+1);
+ if (ireq.i_val != -1)
+ LINE_CHECK("%cdeftxkey %d", spacer, ireq.i_val+1);
+ else if (verbose)
+ LINE_CHECK("%cdeftxkey UNDEF", spacer);
ireq.i_type = IEEE80211_IOC_NUMWEPKEYS;
if (ioctl(s, SIOCG80211, &ireq) < 0) {
@@ -484,28 +1422,201 @@ ieee80211_status (int s, struct rt_addrinfo *info __unused)
}
num = ireq.i_val;
- printf("\n");
-
- ireq.i_type = IEEE80211_IOC_WEPKEY;
- spacer = '\t';
+ firstkey = 1;
for (i = 0; i < num; i++) {
- ireq.i_val = i;
+ struct ieee80211req_key ik;
+
+ 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) {
warn("WEP support, but can get keys!");
goto end;
}
- if (ireq.i_len == 0 ||
- ireq.i_len > IEEE80211_KEYBUF_SIZE)
- continue;
- printf("%cwepkey %d:%s", spacer, i+1,
- ireq.i_len <= 5 ? "40-bit" :
- ireq.i_len <= 13 ? "104-bit" : "128-bit");
- if (spacer == '\t')
+ if (ik.ik_keylen != 0) {
+ if (verbose)
+ LINE_BREAK();
+ printkey(&ik);
+ firstkey = 0;
+ }
+ }
+ }
+
+ 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("%cpowersavemode OFF",
+ spacer);
+ break;
+ case IEEE80211_POWERSAVE_CAM:
+ LINE_CHECK("%cpowersavemode CAM",
+ spacer);
+ break;
+ case IEEE80211_POWERSAVE_PSP:
+ LINE_CHECK("%cpowersavemode PSP",
+ spacer);
+ break;
+ case IEEE80211_POWERSAVE_PSP_CAM:
+ LINE_CHECK("%cpowersavemode PSP-CAM",
+ spacer);
+ break;
+ }
+ ireq.i_type = IEEE80211_IOC_POWERSAVESLEEP;
+ if (ioctl(s, SIOCG80211, &ireq) != -1)
+ LINE_CHECK("%cpowersavesleep %d",
+ spacer, ireq.i_val);
+ }
+ }
+
+ ireq.i_type = IEEE80211_IOC_TXPOWMAX;
+ if (ioctl(s, SIOCG80211, &ireq) != -1)
+ LINE_CHECK("%ctxpowmax %d", spacer, ireq.i_val);
+
+ if (verbose) {
+ ireq.i_type = IEEE80211_IOC_TXPOWER;
+ if (ioctl(s, SIOCG80211, &ireq) != -1)
+ LINE_CHECK("%ctxpower %d", spacer, ireq.i_val);
+ }
+
+ ireq.i_type = IEEE80211_IOC_RTSTHRESHOLD;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ if (ireq.i_val != IEEE80211_RTS_MAX || verbose)
+ LINE_CHECK("%crtsthreshold %d", spacer, ireq.i_val);
+ }
+
+ if (IEEE80211_IS_CHAN_G(c) || IEEE80211_IS_CHAN_PUREG(c) || verbose) {
+ ireq.i_type = IEEE80211_IOC_PROTMODE;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ switch (ireq.i_val) {
+ case IEEE80211_PROTMODE_OFF:
+ LINE_CHECK("%cprotmode OFF", spacer);
+ break;
+ case IEEE80211_PROTMODE_CTS:
+ LINE_CHECK("%cprotmode CTS", spacer);
+ break;
+ case IEEE80211_PROTMODE_RTSCTS:
+ LINE_CHECK("%cprotmode RTSCTS", spacer);
+ break;
+ default:
+ LINE_CHECK("%cprotmode UNKNOWN (0x%x)",
+ spacer, ireq.i_val);
+ break;
+ }
+ }
+ }
+
+ ireq.i_type = IEEE80211_IOC_WME;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ wme = ireq.i_val;
+ if (wme)
+ LINE_CHECK("%cwme", spacer);
+ else if (verbose)
+ LINE_CHECK("%c-wme", spacer);
+ } else
+ wme = 0;
+
+ if (opmode == IEEE80211_M_HOSTAP) {
+ ireq.i_type = IEEE80211_IOC_HIDESSID;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ if (ireq.i_val)
+ LINE_CHECK("%cssid HIDE", spacer);
+ else if (verbose)
+ LINE_CHECK("%cssid SHOW", spacer);
+ }
+
+ ireq.i_type = IEEE80211_IOC_APBRIDGE;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ if (!ireq.i_val)
+ LINE_CHECK("%c-apbridge", spacer);
+ else if (verbose)
+ LINE_CHECK("%capbridge", spacer);
+ }
+
+ ireq.i_type = IEEE80211_IOC_DTIM_PERIOD;
+ if (ioctl(s, SIOCG80211, &ireq) != -1)
+ LINE_CHECK("%cdtimperiod %u", spacer, ireq.i_val);
+ } 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) {
+ case IEEE80211_ROAMING_DEVICE:
+ LINE_CHECK("%croaming DEVICE", spacer);
+ break;
+ case IEEE80211_ROAMING_AUTO:
+ LINE_CHECK("%croaming AUTO", spacer);
+ break;
+ case IEEE80211_ROAMING_MANUAL:
+ LINE_CHECK("%croaming MANUAL", spacer);
+ break;
+ default:
+ LINE_CHECK("%croaming UNKNOWN (0x%x)",
+ spacer, ireq.i_val);
+ break;
+ }
+ }
+ }
+ }
+ ireq.i_type = IEEE80211_IOC_BEACON_INTERVAL;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ if (ireq.i_val)
+ LINE_CHECK("%cbintval %u", spacer, ireq.i_val);
+ else if (verbose)
+ LINE_CHECK("%cbintval %u", spacer, ireq.i_val);
+ }
+
+ if (wme && verbose) {
+ LINE_BREAK();
+ list_wme(s);
+ }
+
+ if (wpa) {
+ ireq.i_type = IEEE80211_IOC_COUNTERMEASURES;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ if (ireq.i_val)
+ LINE_CHECK("%ccountermeasures", spacer);
+ else if (verbose)
+ LINE_CHECK("%c-countermeasures", spacer);
+ }
+#if 0
+ /* XXX not interesting with WPA done in user space */
+ ireq.i_type = IEEE80211_IOC_KEYMGTALGS;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ }
+
+ ireq.i_type = IEEE80211_IOC_MCASTCIPHER;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ printf("%cmcastcipher ", spacer);
+ printcipher(s, &ireq, IEEE80211_IOC_MCASTKEYLEN);
+ spacer = ' ';
+ }
+
+ ireq.i_type = IEEE80211_IOC_UCASTCIPHER;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ printf("%cucastcipher ", spacer);
+ printcipher(s, &ireq, IEEE80211_IOC_UCASTKEYLEN);
+ }
+
+ if (wpa & 2) {
+ ireq.i_type = IEEE80211_IOC_RSNCAPS;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
+ printf("%cRSN caps 0x%x", spacer, ireq.i_val);
spacer = ' ';
+ }
+ }
+
+ ireq.i_type = IEEE80211_IOC_UCASTCIPHERS;
+ if (ioctl(s, SIOCG80211, &ireq) != -1) {
}
- if (spacer == ' ')
- printf("\n");
+#endif
+ LINE_BREAK();
}
+ LINE_BREAK();
end:
return;
@@ -607,3 +1718,78 @@ print_string(const u_int8_t *buf, int len)
}
}
+static struct cmd ieee80211_cmds[] = {
+ DEF_CMD_ARG("ssid", set80211ssid),
+ DEF_CMD_ARG("nwid", set80211ssid),
+ DEF_CMD_ARG("stationname", set80211stationname),
+ DEF_CMD_ARG("station", set80211stationname), /* BSD/OS */
+ DEF_CMD_ARG("channel", set80211channel),
+ DEF_CMD_ARG("authmode", set80211authmode),
+ DEF_CMD_ARG("powersavemode", set80211powersavemode),
+ DEF_CMD("powersave", 1, set80211powersave),
+ DEF_CMD("-powersave", 0, set80211powersave),
+ DEF_CMD_ARG("powersavesleep", set80211powersavesleep),
+ DEF_CMD_ARG("wepmode", set80211wepmode),
+ DEF_CMD("wep", 1, set80211wep),
+ DEF_CMD("-wep", 0, set80211wep),
+ DEF_CMD_ARG("weptxkey", set80211weptxkey),
+ DEF_CMD_ARG("wepkey", set80211wepkey),
+ DEF_CMD_ARG("nwkey", set80211nwkey), /* NetBSD */
+ DEF_CMD("-nwkey", 0, set80211wep), /* NetBSD */
+ DEF_CMD_ARG("rtsthreshold", set80211rtsthreshold),
+ DEF_CMD_ARG("protmode", set80211protmode),
+ DEF_CMD_ARG("txpower", set80211txpower),
+ DEF_CMD_ARG("roaming", set80211roaming),
+ DEF_CMD("wme", 1, set80211wme),
+ DEF_CMD("-wme", 0, set80211wme),
+ DEF_CMD("hidessid", 1, set80211hidessid),
+ DEF_CMD("-hidessid", 0, set80211hidessid),
+ DEF_CMD("apbridge", 1, set80211apbridge),
+ DEF_CMD("-apbridge", 0, set80211apbridge),
+ DEF_CMD_ARG("chanlist", set80211chanlist),
+ DEF_CMD_ARG("bssid", set80211bssid),
+ DEF_CMD_ARG("ap", set80211bssid),
+ DEF_CMD("scan", 0, set80211scan),
+ DEF_CMD_ARG("list", set80211list),
+ DEF_CMD_ARG2("cwmin", set80211cwmin),
+ DEF_CMD_ARG2("cwmax", set80211cwmax),
+ DEF_CMD_ARG2("aifs", set80211aifs),
+ DEF_CMD_ARG2("txoplimit", set80211txoplimit),
+ DEF_CMD("acm", 1, set80211acm),
+ DEF_CMD("-acm", 0, set80211acm),
+ DEF_CMD("ack", 1, set80211ackpolicy),
+ DEF_CMD("-ack", 0, set80211ackpolicy),
+ DEF_CMD_ARG2("bss:cwmin", set80211bsscwmin),
+ DEF_CMD_ARG2("bss:cwmax", set80211bsscwmax),
+ DEF_CMD_ARG2("bss:aifs", set80211bssaifs),
+ DEF_CMD_ARG2("bss:txoplimit", set80211bsstxoplimit),
+ DEF_CMD_ARG("dtimperiod", set80211dtimperiod),
+ DEF_CMD_ARG("bintval", set80211bintval),
+ DEF_CMD("mac:open", IEEE80211_MACCMD_POLICY_OPEN, set80211maccmd),
+ DEF_CMD("mac:allow", IEEE80211_MACCMD_POLICY_ALLOW, set80211maccmd),
+ DEF_CMD("mac:deny", IEEE80211_MACCMD_POLICY_DENY, set80211maccmd),
+ DEF_CMD("mac:flush", IEEE80211_MACCMD_FLUSH, set80211maccmd),
+ DEF_CMD("mac:detach", IEEE80211_MACCMD_DETACH, set80211maccmd),
+ DEF_CMD_ARG("mac:add", set80211addmac),
+ DEF_CMD_ARG("mac:del", set80211delmac),
+#if 0
+ DEF_CMD_ARG("mac:kick", set80211kickmac),
+#endif
+};
+static struct afswtch af_ieee80211 = {
+ .af_name = "af_ieee80211",
+ .af_af = AF_UNSPEC,
+ .af_status = ieee80211_status,
+};
+
+static __constructor void
+ieee80211_ctor(void)
+{
+#define N(a) (sizeof(a) / sizeof(a[0]))
+ int i;
+
+ for (i = 0; i < N(ieee80211_cmds); i++)
+ cmd_register(&ieee80211_cmds[i]);
+ af_register(&af_ieee80211);
+#undef N
+}
OpenPOWER on IntegriCloud