freebsd-dev/usr.sbin/wicontrol/wicontrol.c
Warner Losh e0b29225ea o Tone down the obsolete messages since we actually do something, for
the moment, with the deprecated flags.
o Better error reporting on getting values from the driver.  When we can't
  get one for the default dumpinfo output.  The old driver would succeed
  for invalid RIDs, while the new driver reports errors.  Since the info
  we're getting from the card/driver doesn't exist for all cards, we just
  don't report them.  Improve error reporting elsewhere now that wi_getval
  doesn't exit.  Also fix a file descriptor leak as a side effect.

Reported by: scottl
2003-04-06 19:11:33 +00:00

1168 lines
26 KiB
C

/*
* Copyright (c) 1997, 1998, 1999
* Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Bill Paul.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef lint
static const char copyright[] = "@(#) Copyright (c) 1997, 1998, 1999\
Bill Paul. All rights reserved.";
static const char rcsid[] =
"$FreeBSD$";
#endif /* not lint */
#include <sys/types.h>
#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_var.h>
#include <net/ethernet.h>
#include <net/if_ieee80211.h>
#include <dev/wi/if_wavelan_ieee.h>
#include <dev/wi/if_wireg.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <errno.h>
#include <err.h>
static int wi_getval(const char *, struct wi_req *);
static void wi_setval(const char *, struct wi_req *);
static void wi_printstr(struct wi_req *);
static void wi_setstr(const char *, int, char *);
static void wi_setbytes(const char *, int, char *, int);
static void wi_setword(const char *, int, int);
static void wi_sethex(const char *, int, char *);
static void wi_printwords(struct wi_req *);
static void wi_printbool(struct wi_req *);
static void wi_printhex(struct wi_req *);
static void wi_printaps(struct wi_req *);
static void wi_dumpinfo(const char *);
static void wi_dumpstats(const char *);
static void wi_setkeys(const char *, char *, int);
static void wi_printkeys(struct wi_req *);
static void wi_printaplist(const char *);
static int wi_hex2int(char);
static void wi_str2key(char *, struct wi_key *);
#ifdef WICACHE
static void wi_zerocache(const char *);
static void wi_readcache(const char *);
#endif
static void usage(const char *);
static int listaps;
static int quiet;
/*
* Print a value a la the %b format of the kernel's printf
* (ripped screaming from ifconfig/ifconfig.c)
*/
void
printb(char *s, uint32_t v, char *bits)
{
int i, any = 0;
char c;
if (bits && *bits == 8)
printf("%s=%o", s, v);
else
printf("%s=%x", s, v);
bits++;
if (bits) {
putchar('<');
while ((i = *bits++)) {
if (v & (1 << (i-1))) {
if (any)
putchar(',');
any = 1;
for (; (c = *bits) > 32; bits++)
putchar(c);
} else
for (; *bits > 32; bits++)
;
}
putchar('>');
}
}
static int
wi_getval(const char *iface, struct wi_req *wreq)
{
struct ifreq ifr;
int s;
int retval;
bzero((char *)&ifr, sizeof(ifr));
strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
ifr.ifr_data = (caddr_t)wreq;
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s == -1)
err(1, "socket");
retval = ioctl(s, SIOCGWAVELAN, &ifr);
close(s);
return (retval);
}
static void
wi_setval(const char *iface, struct wi_req *wreq)
{
struct ifreq ifr;
int s;
bzero((char *)&ifr, sizeof(ifr));
strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
ifr.ifr_data = (caddr_t)wreq;
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s == -1)
err(1, "socket");
if (ioctl(s, SIOCSWAVELAN, &ifr) == -1)
err(1, "SIOCSWAVELAN");
close(s);
return;
}
void
wi_printstr(struct wi_req *wreq)
{
char *ptr;
int i;
if (wreq->wi_type == WI_RID_SERIALNO) {
ptr = (char *)&wreq->wi_val;
for (i = 0; i < (wreq->wi_len - 1) * 2; i++) {
if (ptr[i] == '\0')
ptr[i] = ' ';
}
} else {
ptr = (char *)&wreq->wi_val[1];
for (i = 0; i < wreq->wi_val[0]; i++) {
if (ptr[i] == '\0')
ptr[i] = ' ';
}
}
ptr[i] = '\0';
printf("[ %s ]", ptr);
return;
}
void
wi_setstr(const char *iface, int code, char *str)
{
struct wi_req wreq;
if (iface == NULL)
errx(1, "must specify interface name");
if (str == NULL)
errx(1, "must specify string");
bzero((char *)&wreq, sizeof(wreq));
if (strlen(str) > 30)
errx(1, "string too long");
wreq.wi_type = code;
wreq.wi_len = 18;
wreq.wi_val[0] = strlen(str);
bcopy(str, (char *)&wreq.wi_val[1], strlen(str));
wi_setval(iface, &wreq);
return;
}
void
wi_setbytes(const char *iface, int code, char *bytes, int len)
{
struct wi_req wreq;
if (iface == NULL)
errx(1, "must specify interface name");
bzero((char *)&wreq, sizeof(wreq));
wreq.wi_type = code;
wreq.wi_len = (len / 2) + 1;
bcopy(bytes, (char *)&wreq.wi_val[0], len);
wi_setval(iface, &wreq);
return;
}
void
wi_setword(const char *iface, int code, int word)
{
struct wi_req wreq;
bzero((char *)&wreq, sizeof(wreq));
wreq.wi_type = code;
wreq.wi_len = 2;
wreq.wi_val[0] = word;
wi_setval(iface, &wreq);
return;
}
void
wi_sethex(const char *iface, int code, char *str)
{
struct ether_addr *addr;
if (str == NULL)
errx(1, "must specify address");
addr = ether_aton(str);
if (addr == NULL)
errx(1, "badly formatted address");
wi_setbytes(iface, code, (char *)addr, ETHER_ADDR_LEN);
return;
}
static int
wi_hex2int(char c)
{
if (c >= '0' && c <= '9')
return (c - '0');
if (c >= 'A' && c <= 'F')
return (c - 'A' + 10);
if (c >= 'a' && c <= 'f')
return (c - 'a' + 10);
return (0);
}
static void
wi_str2key(char *s, struct wi_key *k)
{
int n, i;
char *p;
/* Is this a hex string? */
if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
/* Yes, convert to int. */
n = 0;
p = (char *)&k->wi_keydat[0];
for (i = 2; s[i] != '\0' && s[i + 1] != '\0'; i+= 2) {
*p++ = (wi_hex2int(s[i]) << 4) + wi_hex2int(s[i + 1]);
n++;
}
if (s[i] != '\0')
errx(1, "hex strings must be of even length");
k->wi_keylen = n;
} else {
/* No, just copy it in. */
bcopy(s, k->wi_keydat, strlen(s));
k->wi_keylen = strlen(s);
}
return;
}
static void
wi_setkeys(const char *iface, char *key, int idx)
{
int keylen;
struct wi_req wreq;
struct wi_ltv_keys *keys;
struct wi_key *k;
int has_wep;
bzero((char *)&wreq, sizeof(wreq));
wreq.wi_len = WI_MAX_DATALEN;
wreq.wi_type = WI_RID_WEP_AVAIL;
if (wi_getval(iface, &wreq) == 0)
has_wep = wreq.wi_val[0];
else
has_wep = 0;
if (!has_wep)
errx(1, "no WEP option available on this card");
bzero((char *)&wreq, sizeof(wreq));
wreq.wi_len = WI_MAX_DATALEN;
wreq.wi_type = WI_RID_DEFLT_CRYPT_KEYS;
if (wi_getval(iface, &wreq) == -1)
errx(1, "Cannot get default key index");
keys = (struct wi_ltv_keys *)&wreq;
keylen = strlen(key);
if (key[0] == '0' && (key[1] == 'x' || key[1] == 'X')) {
if (keylen != 2 && keylen != 12 && keylen != 28) {
errx(1, "encryption key must be 0, 10, or 26 "
"hex digits long");
}
} else {
if (keylen != 0 && keylen != 5 && keylen != 13) {
errx(1, "encryption key must be 0, 5, or 13 "
"bytes long");
}
}
if (idx > 3)
errx(1, "only 4 encryption keys available");
k = &keys->wi_keys[idx];
wi_str2key(key, k);
wreq.wi_len = (sizeof(struct wi_ltv_keys) / 2) + 1;
wreq.wi_type = WI_RID_DEFLT_CRYPT_KEYS;
wi_setval(iface, &wreq);
return;
}
static void
wi_printkeys(struct wi_req *wreq)
{
int i, j;
int isprintable;
struct wi_key *k;
struct wi_ltv_keys *keys;
char *ptr;
keys = (struct wi_ltv_keys *)wreq;
for (i = 0; i < 4; i++) {
k = &keys->wi_keys[i];
ptr = (char *)k->wi_keydat;
isprintable = 1;
for (j = 0; j < k->wi_keylen; j++) {
if (!isprint(ptr[j])) {
isprintable = 0;
break;
}
}
if (isprintable) {
ptr[j] = '\0';
printf("[ %s ]", ptr);
} else {
printf("[ 0x");
for (j = 0; j < k->wi_keylen; j++) {
printf("%02x", ptr[j] & 0xFF);
}
printf(" ]");
}
}
return;
};
void
wi_printwords(struct wi_req *wreq)
{
int i;
printf("[ ");
for (i = 0; i < wreq->wi_len - 1; i++)
printf("%d ", wreq->wi_val[i]);
printf("]");
return;
}
void
wi_printswords(struct wi_req *wreq)
{
int i;
printf("[ ");
for (i = 0; i < wreq->wi_len - 1; i++)
printf("%d ", ((int16_t *) wreq->wi_val)[i]);
printf("]");
return;
}
void
wi_printhexwords(struct wi_req *wreq)
{
int i;
printf("[ ");
for (i = 0; i < wreq->wi_len - 1; i++)
printf("%x ", wreq->wi_val[i]);
printf("]");
return;
}
void
wi_printregdoms(struct wi_req *wreq)
{
int i;
struct wi_ltv_domains *regdom = (struct wi_ltv_domains *)wreq;
printf("[ ");
for (i = 0; i < regdom->wi_num_dom; i++) {
switch (regdom->wi_domains[i]) {
case 0x10: printf("usa"); break;
case 0x20: printf("canada"); break;
case 0x30: printf("eu/au"); break;
case 0x31: printf("es"); break;
case 0x32: printf("fr"); break;
case 0x40: printf("jp"); break;
case 0x41: printf("jp new"); break;
default: printf("0x%x", regdom->wi_domains[i]); break;
}
if (i < regdom->wi_num_dom - 1)
printf(", ");
}
printf(" ]");
return;
}
void
wi_printbool(struct wi_req *wreq)
{
if (wreq->wi_val[0])
printf("[ On ]");
else
printf("[ Off ]");
return;
}
void
wi_printhex(struct wi_req *wreq)
{
int i;
unsigned char *c;
c = (unsigned char *)&wreq->wi_val;
printf("[ ");
for (i = 0; i < (wreq->wi_len - 1) * 2; i++) {
printf("%02x", c[i]);
if (i < ((wreq->wi_len - 1) * 2) - 1)
printf(":");
}
printf(" ]");
return;
}
static int
get_wiaprate(int inrate)
{
int rate;
switch (inrate) {
case WI_APRATE_1:
rate = 1;
break;
case WI_APRATE_2:
rate = 2;
break;
case WI_APRATE_5:
rate = 5.5;
break;
case WI_APRATE_11:
rate = 11;
break;
#ifdef WI_APRATE_0
case WI_APRATE_0:
#endif
default:
rate = 0;
break;
}
return (rate);
}
void
wi_printaplist(const char *iface)
{
int prism2;
struct wi_req wreq;
struct wi_apinfo *w;
int i, nstations;
float rate;
if (!quiet)
printf("Available APs:\n");
/* first determine if this is a prism2 card or not */
wreq.wi_len = WI_MAX_DATALEN;
wreq.wi_type = WI_RID_PRISM2;
if (wi_getval(iface, &wreq) == 0)
prism2 = wreq.wi_val[0];
else
prism2 = 0;
/* send out a scan request */
wreq.wi_len = 1;
wreq.wi_type = WI_RID_SCAN_APS;
wi_setval(iface, &wreq);
do {
/*
* sleep for 100 milliseconds so there's enough time for the card to
* respond... prism2's take a little longer.
*/
usleep(prism2 ? 500000 : 100000);
/* get the scan results */
wreq.wi_len = WI_MAX_DATALEN;
wreq.wi_type = WI_RID_SCAN_RES;
} while (wi_getval(iface, &wreq) == -1 && errno == EINPROGRESS);
nstations = *(int *)wreq.wi_val;
if (!quiet) {
printf("%d station%s:\n", nstations, nstations == 1 ? "" : "s");
printf("SSID BSSID Chan SN S N Intrvl Capinfo\n");
}
w = (struct wi_apinfo *)(((char *)&wreq.wi_val) + sizeof(int));
for ( i = 0; i < nstations; i++, w++) {
printf("%-20.*s %02x:%02x:%02x:%02x:%02x:%02x %-2d "
"[ %3d %3d %3d ] %-3d "
, w->namelen, w->name
, w->bssid[0]&0xff, w->bssid[1]&0xff
, w->bssid[2]&0xff, w->bssid[3]&0xff
, w->bssid[4]&0xff, w->bssid[5]&0xff
, w->channel
, w->quality, w->signal, w->noise
, w->interval
);
if (!quiet) {
printf("[ ");
if (w->capinfo & IEEE80211_CAPINFO_ESS)
printf("ESS ");
if (w->capinfo & IEEE80211_CAPINFO_PRIVACY)
printf("WEP ");
printf("]\n ");
rate = get_wiaprate(w->rate);
if (rate) printf("* %2.1f *\n", rate);
}
putchar('\n');
}
}
#define WI_STRING 0x01
#define WI_BOOL 0x02
#define WI_WORDS 0x03
#define WI_HEXBYTES 0x04
#define WI_KEYSTRUCT 0x05
#define WI_SWORDS 0x06
#define WI_HEXWORDS 0x07
#define WI_REGDOMS 0x08
struct wi_table {
int wi_code;
int wi_type;
const char *wi_str;
};
static struct wi_table wi_table[] = {
{ WI_RID_SERIALNO, WI_STRING, "NIC serial number:\t\t\t" },
{ WI_RID_NODENAME, WI_STRING, "Station name:\t\t\t\t" },
{ WI_RID_OWN_SSID, WI_STRING, "SSID for IBSS creation:\t\t\t" },
{ WI_RID_CURRENT_SSID, WI_STRING, "Current netname (SSID):\t\t\t" },
{ WI_RID_DESIRED_SSID, WI_STRING, "Desired netname (SSID):\t\t\t" },
{ WI_RID_CURRENT_BSSID, WI_HEXBYTES, "Current BSSID:\t\t\t\t" },
{ WI_RID_CHANNEL_LIST, WI_HEXWORDS, "Channel list:\t\t\t\t" },
{ WI_RID_OWN_CHNL, WI_WORDS, "IBSS channel:\t\t\t\t" },
{ WI_RID_CURRENT_CHAN, WI_WORDS, "Current channel:\t\t\t" },
{ WI_RID_COMMS_QUALITY, WI_WORDS, "Comms quality/signal/noise:\t\t" },
{ WI_RID_DBM_COMMS_QUAL, WI_SWORDS, "dBm Coms Quality:\t\t\t" },
{ WI_RID_PROMISC, WI_BOOL, "Promiscuous mode:\t\t\t" },
{ WI_RID_PROCFRAME, WI_BOOL, "Process 802.11b Frame:\t\t\t" },
{ WI_RID_PRISM2, WI_WORDS, "Intersil-Prism2 based card:\t\t" },
{ WI_RID_PORTTYPE, WI_WORDS, "Port type (1=BSS, 3=ad-hoc):\t\t"},
{ WI_RID_MAC_NODE, WI_HEXBYTES, "MAC address:\t\t\t\t"},
{ WI_RID_TX_RATE, WI_WORDS, "TX rate (selection):\t\t\t"},
{ WI_RID_CUR_TX_RATE, WI_WORDS, "TX rate (actual speed):\t\t\t"},
{ WI_RID_RTS_THRESH, WI_WORDS, "RTS/CTS handshake threshold:\t\t"},
{ WI_RID_CREATE_IBSS, WI_BOOL, "Create IBSS:\t\t\t\t" },
{ WI_RID_SYSTEM_SCALE, WI_WORDS, "Access point density:\t\t\t" },
{ WI_RID_PM_ENABLED, WI_WORDS, "Power Mgmt (1=on, 0=off):\t\t" },
{ WI_RID_MAX_SLEEP, WI_WORDS, "Max sleep time:\t\t\t\t" },
{ WI_RID_PRI_IDENTITY, WI_WORDS, "PRI Identity:\t\t\t\t" },
{ WI_RID_STA_IDENTITY, WI_WORDS, "STA Identity:\t\t\t\t" } ,
{ WI_RID_CARD_ID, WI_HEXWORDS, "Card ID register:\t\t\t" },
{ WI_RID_REG_DOMAINS, WI_REGDOMS, "Regulatory Domains:\t\t\t" },
{ WI_RID_TEMP_TYPE, WI_WORDS, "Temperature Range:\t\t\t" },
#ifdef WI_EXTRA_INFO
{ WI_RID_PRI_SUP_RANGE, WI_WORDS, "PRI Sup Range:\t\t\t\t" },
{ WI_RID_CIF_ACT_RANGE, WI_WORDS, "CFI Act Sup Range:\t\t\t" },
{ WI_RID_STA_SUP_RANGE, WI_WORDS, "STA Sup Range:\t\t\t\t" } ,
{ WI_RID_MFI_ACT_RANGE, WI_WORDS, "MFI Act Sup Range:\t\t\t" } ,
#endif
{ 0, 0, NULL }
};
static struct wi_table wi_crypt_table[] = {
{ WI_RID_ENCRYPTION, WI_BOOL, "WEP encryption:\t\t\t\t" },
{ WI_RID_TX_CRYPT_KEY, WI_WORDS, "TX encryption key:\t\t\t" },
{ WI_RID_DEFLT_CRYPT_KEYS, WI_KEYSTRUCT, "Encryption keys:\t\t\t" },
{ 0, 0, NULL }
};
static void
wi_dumpinfo(const char *iface)
{
struct wi_req wreq;
int i, has_wep;
struct wi_table *w;
bzero((char *)&wreq, sizeof(wreq));
wreq.wi_len = WI_MAX_DATALEN;
wreq.wi_type = WI_RID_WEP_AVAIL;
if (wi_getval(iface, &wreq) == 0)
has_wep = wreq.wi_val[0];
else
has_wep = 0;
w = wi_table;
for (i = 0; w[i].wi_type; i++) {
bzero((char *)&wreq, sizeof(wreq));
wreq.wi_len = WI_MAX_DATALEN;
wreq.wi_type = w[i].wi_code;
if (wi_getval(iface, &wreq) == -1)
continue;
printf("%s", w[i].wi_str);
switch(w[i].wi_type) {
case WI_STRING:
wi_printstr(&wreq);
break;
case WI_WORDS:
wi_printwords(&wreq);
break;
case WI_SWORDS:
wi_printswords(&wreq);
break;
case WI_HEXWORDS:
wi_printhexwords(&wreq);
break;
case WI_REGDOMS:
wi_printregdoms(&wreq);
break;
case WI_BOOL:
wi_printbool(&wreq);
break;
case WI_HEXBYTES:
wi_printhex(&wreq);
break;
default:
break;
}
printf("\n");
}
if (has_wep) {
w = wi_crypt_table;
for (i = 0; w[i].wi_type; i++) {
bzero((char *)&wreq, sizeof(wreq));
wreq.wi_len = WI_MAX_DATALEN;
wreq.wi_type = w[i].wi_code;
if (wi_getval(iface, &wreq) == -1)
continue;
printf("%s", w[i].wi_str);
switch(w[i].wi_type) {
case WI_STRING:
wi_printstr(&wreq);
break;
case WI_WORDS:
if (wreq.wi_type == WI_RID_TX_CRYPT_KEY)
wreq.wi_val[0]++;
wi_printwords(&wreq);
break;
case WI_BOOL:
wi_printbool(&wreq);
break;
case WI_HEXBYTES:
wi_printhex(&wreq);
break;
case WI_KEYSTRUCT:
wi_printkeys(&wreq);
break;
default:
break;
}
printf("\n");
}
}
if (listaps)
wi_printaplist(iface);
return;
}
static void
wi_dumpstats(const char *iface)
{
struct wi_req wreq;
struct wi_counters *c;
if (iface == NULL)
errx(1, "must specify interface name");
bzero((char *)&wreq, sizeof(wreq));
wreq.wi_len = WI_MAX_DATALEN;
wreq.wi_type = WI_RID_IFACE_STATS;
if (wi_getval(iface, &wreq) == -1)
errx(1, "Cannot get interface stats");
c = (struct wi_counters *)&wreq.wi_val;
printf("Transmitted unicast frames:\t\t%d\n",
c->wi_tx_unicast_frames);
printf("Transmitted multicast frames:\t\t%d\n",
c->wi_tx_multicast_frames);
printf("Transmitted fragments:\t\t\t%d\n",
c->wi_tx_fragments);
printf("Transmitted unicast octets:\t\t%d\n",
c->wi_tx_unicast_octets);
printf("Transmitted multicast octets:\t\t%d\n",
c->wi_tx_multicast_octets);
printf("Single transmit retries:\t\t%d\n",
c->wi_tx_single_retries);
printf("Multiple transmit retries:\t\t%d\n",
c->wi_tx_multi_retries);
printf("Transmit retry limit exceeded:\t\t%d\n",
c->wi_tx_retry_limit);
printf("Transmit discards:\t\t\t%d\n",
c->wi_tx_discards);
printf("Transmit discards due to wrong SA:\t%d\n",
c->wi_tx_discards_wrong_sa);
printf("Received unicast frames:\t\t%d\n",
c->wi_rx_unicast_frames);
printf("Received multicast frames:\t\t%d\n",
c->wi_rx_multicast_frames);
printf("Received fragments:\t\t\t%d\n",
c->wi_rx_fragments);
printf("Received unicast octets:\t\t%d\n",
c->wi_rx_unicast_octets);
printf("Received multicast octets:\t\t%d\n",
c->wi_rx_multicast_octets);
printf("Receive FCS errors:\t\t\t%d\n",
c->wi_rx_fcs_errors);
printf("Receive discards due to no buffer:\t%d\n",
c->wi_rx_discards_nobuf);
printf("Can't decrypt WEP frame:\t\t%d\n",
c->wi_rx_WEP_cant_decrypt);
printf("Received message fragments:\t\t%d\n",
c->wi_rx_msg_in_msg_frags);
printf("Received message bad fragments:\t\t%d\n",
c->wi_rx_msg_in_bad_msg_frags);
return;
}
static void
usage(const char *p)
{
fprintf(stderr, "usage: %s -i iface\n", p);
fprintf(stderr, "\t%s -i iface -o\n", p);
fprintf(stderr, "\t%s -i iface -l\n", p);
fprintf(stderr, "\t%s -i iface -t tx rate\n", p);
fprintf(stderr, "\t%s -i iface -n network name\n", p);
fprintf(stderr, "\t%s -i iface -s station name\n", p);
fprintf(stderr, "\t%s -i iface -c 0|1\n", p);
fprintf(stderr, "\t%s -i iface -q SSID\n", p);
fprintf(stderr, "\t%s -i iface -p port type\n", p);
fprintf(stderr, "\t%s -i iface -a access point density\n", p);
fprintf(stderr, "\t%s -i iface -m mac address\n", p);
fprintf(stderr, "\t%s -i iface -d max data length\n", p);
fprintf(stderr, "\t%s -i iface -e 0|1\n", p);
fprintf(stderr, "\t%s -i iface -k encryption key [-v 1|2|3|4]\n", p);
fprintf(stderr, "\t%s -i iface -r RTS threshold\n", p);
fprintf(stderr, "\t%s -i iface -f frequency\n", p);
fprintf(stderr, "\t%s -i iface -F 0|1\n", p);
fprintf(stderr, "\t%s -i iface -P 0|1\n", p);
fprintf(stderr, "\t%s -i iface -S max sleep duration\n", p);
fprintf(stderr, "\t%s -i iface -T 1|2|3|4\n", p);
#ifdef WICACHE
fprintf(stderr, "\t%s -i iface -Z zero out signal cache\n", p);
fprintf(stderr, "\t%s -i iface -C print signal cache\n", p);
#endif
exit(1);
}
static void
wi_printaps(struct wi_req *wreq)
{
struct wi_apinfo *w;
int i, j, nstations, rate;
nstations = *(int *)wreq->wi_val;
printf("%d station%s:\n", nstations, nstations == 1 ? "" : "s");
w = (struct wi_apinfo *)(((char *)&wreq->wi_val) + sizeof(int));
for ( i = 0; i < nstations; i++, w++) {
printf("ap[%d]:\n", i);
if (w->scanreason) {
static char *scanm[] = {
"Host initiated",
"Firmware initiated",
"Inquiry request from host"
};
printf("\tScanReason:\t\t\t[ %s ]\n",
scanm[w->scanreason - 1]);
}
printf("\tnetname (SSID):\t\t\t[ ");
for (j = 0; j < w->namelen; j++) {
printf("%c", w->name[j]);
}
printf(" ]\n");
printf("\tBSSID:\t\t\t\t[ %02x:%02x:%02x:%02x:%02x:%02x ]\n",
w->bssid[0]&0xff, w->bssid[1]&0xff,
w->bssid[2]&0xff, w->bssid[3]&0xff,
w->bssid[4]&0xff, w->bssid[5]&0xff);
printf("\tChannel:\t\t\t[ %d ]\n", w->channel);
printf("\tQuality/Signal/Noise [signal]:\t[ %d / %d / %d ]\n"
"\t [dBm]:\t[ %d / %d / %d ]\n",
w->quality, w->signal, w->noise,
w->quality, w->signal - 149, w->noise - 149);
printf("\tBSS Beacon Interval [msec]:\t[ %d ]\n", w->interval);
printf("\tCapinfo:\t\t\t[ ");
if (w->capinfo & IEEE80211_CAPINFO_ESS)
printf("ESS ");
if (w->capinfo & IEEE80211_CAPINFO_PRIVACY)
printf("WEP ");
printf("]\n");
switch (w->rate) {
case WI_APRATE_1:
rate = 1;
break;
case WI_APRATE_2:
rate = 2;
break;
case WI_APRATE_5:
rate = 5.5;
break;
case WI_APRATE_11:
rate = 11;
break;
#ifdef WI_APRATE_0
case WI_APRATE_0:
#endif
default:
rate = 0;
break;
}
if (rate) printf("\tDataRate [Mbps]:\t\t[ %d ]\n", rate);
}
}
static void
wi_dumpstations(const char *iface)
{
struct wi_req wreq;
if (iface == NULL)
errx(1, "must specify interface name");
bzero((char *)&wreq, sizeof(wreq));
wreq.wi_len = WI_MAX_DATALEN;
wreq.wi_type = WI_RID_READ_APS;
if (wi_getval(iface, &wreq) == -1)
errx(1, "Cannot get stations");
wi_printaps(&wreq);
}
#ifdef WICACHE
static void
wi_zerocache(const char *iface)
{
struct wi_req wreq;
if (iface == NULL)
errx(1, "must specify interface name");
bzero((char *)&wreq, sizeof(wreq));
wreq.wi_len = 0;
wreq.wi_type = WI_RID_ZERO_CACHE;
wi_getval(iface, &wreq);
}
static void
wi_readcache(const char *iface)
{
struct wi_req wreq;
int *wi_sigitems;
struct wi_sigcache *sc;
char * pt;
int i;
if (iface == NULL)
errx(1, "must specify interface name");
bzero((char *)&wreq, sizeof(wreq));
wreq.wi_len = WI_MAX_DATALEN;
wreq.wi_type = WI_RID_READ_CACHE;
if (wi_getval(iface, &wreq) == -1)
errx(1, "Cannot read signal cache");
wi_sigitems = (int *) &wreq.wi_val;
pt = ((char *) &wreq.wi_val);
pt += sizeof(int);
sc = (struct wi_sigcache *) pt;
for (i = 0; i < *wi_sigitems; i++) {
printf("[%d/%d]:", i+1, *wi_sigitems);
printf(" %02x:%02x:%02x:%02x:%02x:%02x,",
sc->macsrc[0]&0xff,
sc->macsrc[1]&0xff,
sc->macsrc[2]&0xff,
sc->macsrc[3]&0xff,
sc->macsrc[4]&0xff,
sc->macsrc[5]&0xff);
printf(" %d.%d.%d.%d,",((sc->ipsrc >> 0) & 0xff),
((sc->ipsrc >> 8) & 0xff),
((sc->ipsrc >> 16) & 0xff),
((sc->ipsrc >> 24) & 0xff));
printf(" sig: %d, noise: %d, qual: %d\n",
sc->signal,
sc->noise,
sc->quality);
sc++;
}
return;
}
#endif
static void
dep(const char *flag, const char *opt)
{
warnx("warning: flag %s deprecated, migrate to ifconfig %s", flag,
opt);
}
int
main(int argc, char *argv[])
{
int ch;
const char *iface = NULL;
char *p = argv[0];
char *key = NULL;
int modifier = 0;
/* Get the interface name */
opterr = 0;
ch = getopt(argc, argv, "i:");
if (ch == 'i') {
iface = optarg;
} else {
if (argc > 1 && *argv[1] != '-') {
iface = argv[1];
optind = 2;
} else {
iface = "wi0";
optind = 1;
}
optreset = 1;
}
opterr = 1;
while((ch = getopt(argc, argv,
"a:c:d:e:f:hi:k:lm:n:op:q:r:s:t:v:CF:LP:QS:T:Z")) != -1) {
switch(ch) {
case 'Z':
#ifdef WICACHE
wi_zerocache(iface);
#else
printf("WICACHE not available\n");
#endif
exit(0);
break;
case 'C':
#ifdef WICACHE
wi_readcache(iface);
#else
printf("WICACHE not available\n");
#endif
exit(0);
break;
case 'o':
wi_dumpstats(iface);
exit(0);
break;
case 'c':
dep("c", "mediaopt");
wi_setword(iface, WI_RID_CREATE_IBSS, atoi(optarg));
exit(0);
break;
case 'd':
wi_setword(iface, WI_RID_MAX_DATALEN, atoi(optarg));
exit(0);
break;
case 'e':
dep("e", "wepmode");
wi_setword(iface, WI_RID_ENCRYPTION, atoi(optarg));
exit(0);
break;
case 'f':
dep("f", "channel");
wi_setword(iface, WI_RID_OWN_CHNL, atoi(optarg));
exit(0);
break;
case 'F':
wi_setword(iface, WI_RID_PROCFRAME, atoi(optarg));
exit(0);
break;
case 'k':
dep("k", "wepkey");
key = optarg;
break;
case 'L':
listaps++;
break;
case 'l':
wi_dumpstations(iface);
exit(0);
break;
case 'p':
dep("p", "mediaopt");
wi_setword(iface, WI_RID_PORTTYPE, atoi(optarg));
exit(0);
break;
case 'r':
wi_setword(iface, WI_RID_RTS_THRESH, atoi(optarg));
exit(0);
break;
case 't':
dep("t", "mediaopt");
wi_setword(iface, WI_RID_TX_RATE, atoi(optarg));
exit(0);
break;
case 'n':
dep("n", "ssid");
wi_setstr(iface, WI_RID_DESIRED_SSID, optarg);
exit(0);
break;
case 's':
dep("s", "stationname");
wi_setstr(iface, WI_RID_NODENAME, optarg);
exit(0);
break;
case 'm':
wi_sethex(iface, WI_RID_MAC_NODE, optarg);
exit(0);
break;
case 'Q':
quiet = 1;
break;
case 'q':
dep("q", "ssid");
wi_setstr(iface, WI_RID_OWN_SSID, optarg);
exit(0);
break;
case 'S':
dep("S", "powersleep");
wi_setword(iface, WI_RID_MAX_SLEEP, atoi(optarg));
exit(0);
break;
case 'T':
dep("T", "weptxkey");
wi_setword(iface,
WI_RID_TX_CRYPT_KEY, atoi(optarg) - 1);
exit(0);
break;
case 'P':
dep("P", "powersave");
wi_setword(iface, WI_RID_PM_ENABLED, atoi(optarg));
exit(0);
break;
case 'a':
wi_setword(iface, WI_RID_SYSTEM_SCALE, atoi(optarg));
exit(0);
break;
case 'v':
modifier = atoi(optarg);
modifier--;
break;
case 'h':
default:
usage(p);
break;
}
}
if (iface == NULL)
usage(p);
if (key != NULL) {
wi_setkeys(iface, key, modifier);
exit(0);
}
if (listaps > 1) {
wi_printaplist(iface);
exit(0);
}
wi_dumpinfo(iface);
exit(0);
}