diff options
Diffstat (limited to 'usr.sbin/wlconfig/wlconfig.c')
-rw-r--r-- | usr.sbin/wlconfig/wlconfig.c | 417 |
1 files changed, 417 insertions, 0 deletions
diff --git a/usr.sbin/wlconfig/wlconfig.c b/usr.sbin/wlconfig/wlconfig.c new file mode 100644 index 0000000..f361b2c --- /dev/null +++ b/usr.sbin/wlconfig/wlconfig.c @@ -0,0 +1,417 @@ +/* + * Copyright (C) 1996 + * Michael Smith. 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. + * + * THIS SOFTWARE IS PROVIDED BY Michael Smith 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 Michael Smith OR CONTRIBUTORS 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 rcsid[] = + "$FreeBSD$"; +#endif /* not lint */ + +/* + * wlconfig.c + * + * utility to read out and change various WAVELAN parameters. + * Currently supports NWID and IRQ values. + * + * The NWID is used by 2 or more wavelan controllers to determine + * if packets should be received or not. It is a filter that + * is roughly analogous to the "channel" setting with a garage + * door controller. Two companies side by side with wavelan devices + * that could actually hear each other can use different NWIDs + * and ignore packets. In truth however, the air space is shared, + * and the NWID is a virtual filter. + * + * In the current set of wavelan drivers, ioctls changed only + * the runtime radio modem registers which act in a manner analogous + * to an ethernet transceiver. The ioctls do not change the + * stored nvram PSA (or parameter storage area). At boot, the PSA + * values are stored in the radio modem. Thus when the + * system reboots it will restore the wavelan NWID to the value + * stored in the PSA. The NCR/ATT dos utilities must be used to + * change the initial NWID values in the PSA. The wlconfig utility + * may be used to set a different NWID at runtime; this is only + * permitted while the interface is up and running. + * + * By contrast, the IRQ value can only be changed while the + * Wavelan card is down and unconfigured, and it will remain + * disabled after an IRQ change until reboot. + * + */ + +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <machine/if_wl_wavelan.h> + +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/if_ether.h> + +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <limits.h> + +/* translate IRQ bit to number */ +/* array for maping irq numbers to values for the irq parameter register */ +static int irqvals[16] = { + 0, 0, 0, 0x01, 0x02, 0x04, 0, 0x08, 0, 0, 0x10, 0x20, 0x40, 0, 0, 0x80 +}; + +/* cache */ +static int w_sigitems; /* count of valid items */ +static struct w_sigcache wsc[MAXCACHEITEMS]; + +int +wlirq(int irqval) +{ + int irq; + + for(irq = 0; irq < 16; irq++) + if(irqvals[irq] == irqval) + return(irq); + return 0; +} + +char *compat_type[] = { + "PC-AT 915MHz", + "PC-MC 915MHz", + "PC-AT 2.4GHz", + "PC-MC 2.4GHz", + "PCCARD or 1/2 size AT, 915MHz or 2.4GHz" +}; + +char *subband[] = { + "915MHz/see WaveModem", + "2425MHz", + "2460MHz", + "2484MHz", + "2430.5MHz" +}; + + +/* +** print_psa +** +** Given a pointer to a PSA structure, print it out +*/ +void +print_psa(u_char *psa, int currnwid) +{ + int nwid; + + /* + ** Work out what sort of board we have + */ + if (psa[0] == 0x14) { + printf("Board type : Microchannel\n"); + } else { + if (psa[1] == 0) { + printf("Board type : PCCARD\n"); + } else { + printf("Board type : ISA"); + if ((psa[4] == 0) && + (psa[5] == 0) && + (psa[6] == 0)) + printf(" (DEC OEM)"); + printf("\n"); + printf("Base address options : 0x300, 0x%02x0, 0x%02x0, 0x%02x0\n", + (int)psa[1], (int)psa[2], (int)psa[3]); + printf("Waitstates : %d\n",psa[7] & 0xf); + printf("Bus mode : %s\n",(psa[7] & 0x10) ? "EISA" : "ISA"); + printf("IRQ : %d\n",wlirq(psa[8])); + } + } + printf("Default MAC address : %02x:%02x:%02x:%02x:%02x:%02x\n", + psa[0x10],psa[0x11],psa[0x12],psa[0x13],psa[0x14],psa[0x15]); + printf("Soft MAC address : %02x:%02x:%02x:%02x:%02x:%02x\n", + psa[0x16],psa[0x17],psa[0x18],psa[0x19],psa[0x1a],psa[0x1b]); + printf("Current MAC address : %s\n",(psa[0x1c] & 0x1) ? "Soft" : "Default"); + printf("Adapter compatibility : "); + if (psa[0x1d] < 5) { + printf("%s\n",compat_type[psa[0x1d]]); + } else { + printf("unknown\n"); + } + printf("Threshold preset : %d\n",psa[0x1e]); + printf("Call code required : %s\n",(psa[0x1f] & 0x1) ? "YES" : "NO"); + if (psa[0x1f] & 0x1) + printf("Call code : 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", + psa[0x30],psa[0x31],psa[0x32],psa[0x33],psa[0x34],psa[0x35],psa[0x36],psa[0x37]); + printf("Subband : %s\n",subband[psa[0x20] & 0xf]); + printf("Quality threshold : %d\n",psa[0x21]); + printf("Hardware version : %d (%s)\n",psa[0x22],psa[0x22] ? "Rel3" : "Rel1/Rel2"); + printf("Network ID enable : %s\n",(psa[0x25] & 0x1) ? "YES" : "NO"); + if (psa[0x25] & 0x1) { + nwid = (psa[0x23] << 8) + psa[0x24]; + printf("NWID : 0x%04x\n",nwid); + if (nwid != currnwid) { + printf("Current NWID : 0x%04x\n",currnwid); + } + } + printf("Datalink security : %s\n",(psa[0x26] & 0x1) ? "YES" : "NO"); + if (psa[0x26] & 0x1) { + printf("Encryption key : "); + if (psa[0x27] == 0) { + printf("DENIED\n"); + } else { + printf("0x%02x%02x%02x%02x%02x%02x%02x%02x\n", + psa[0x27],psa[0x28],psa[0x29],psa[0x2a],psa[0x2b],psa[0x2c],psa[0x2d],psa[0x2e]); + } + } + printf("Databus width : %d (%s)\n", + (psa[0x2f] & 0x1) ? 16 : 8, (psa[0x2f] & 0x80) ? "fixed" : "variable"); + printf("Configuration state : %sconfigured\n",(psa[0x38] & 0x1) ? "" : "un"); + printf("CRC-16 : 0x%02x%02x\n",psa[0x3e],psa[0x3d]); + printf("CRC status : "); + switch(psa[0x3f]) { + case 0xaa: + printf("OK\n"); + break; + case 0x55: + printf("BAD\n"); + break; + default: + printf("Error\n"); + break; + } +} + + +static void +usage() +{ + fprintf(stderr,"usage: wlconfig ifname [param value ...]\n"); + exit(1); +} + + +void +get_cache(int sd, struct ifreq *ifr) +{ + /* get the cache count */ + if (ioctl(sd, SIOCGWLCITEM, (caddr_t)ifr)) + err(1, "SIOCGWLCITEM - get cache count"); + w_sigitems = (int) ifr->ifr_data; + + ifr->ifr_data = (caddr_t) &wsc; + /* get the cache */ + if (ioctl(sd, SIOCGWLCACHE, (caddr_t)ifr)) + err(1, "SIOCGWLCACHE - get cache count"); +} + +static int +scale_value(int value, int max) +{ + double dmax = (double) max; + if (value > max) + return(100); + return((value/dmax) * 100); +} + +static void +dump_cache(int rawFlag) +{ + int i; + int signal, silence, quality; + + if (rawFlag) + printf("signal range 0..63: silence 0..63: quality 0..15\n"); + else + printf("signal range 0..100: silence 0..100: quality 0..100\n"); + + /* after you read it, loop through structure,i.e. wsc + * print each item: + */ + for(i = 0; i < w_sigitems; i++) { + printf("[%d:%d]>\n", i+1, w_sigitems); + printf("\tip: %d.%d.%d.%d,",((wsc[i].ipsrc >> 0) & 0xff), + ((wsc[i].ipsrc >> 8) & 0xff), + ((wsc[i].ipsrc >> 16) & 0xff), + ((wsc[i].ipsrc >> 24) & 0xff)); + printf(" mac: %02x:%02x:%02x:%02x:%02x:%02x\n", + wsc[i].macsrc[0]&0xff, + wsc[i].macsrc[1]&0xff, + wsc[i].macsrc[2]&0xff, + wsc[i].macsrc[3]&0xff, + wsc[i].macsrc[4]&0xff, + wsc[i].macsrc[5]&0xff); + if (rawFlag) { + signal = wsc[i].signal; + silence = wsc[i].silence; + quality = wsc[i].quality; + } + else { + signal = scale_value(wsc[i].signal, 63); + silence = scale_value(wsc[i].silence, 63); + quality = scale_value(wsc[i].quality, 15); + } + printf("\tsignal: %d, silence: %d, quality: %d, ", + signal, + silence, + quality); + printf("snr: %d\n", signal - silence); + } +} + +#define raw_cache() dump_cache(1) +#define scale_cache() dump_cache(0) + +int +main(int argc, char *argv[]) +{ + int sd; + struct ifreq ifr; + u_char psabuf[0x40]; + int val, argind, i; + char *cp, *param, *value; + struct ether_addr *ea; + int work = 0; + int currnwid; + + if ((argc < 2) || (argc % 2)) + usage(); + + /* get a socket */ + sd = socket(AF_INET, SOCK_DGRAM, 0); + if (sd < 0) + err(1,"socket"); + strncpy(ifr.ifr_name, argv[1], sizeof(ifr.ifr_name)); + ifr.ifr_addr.sa_family = AF_INET; + + /* get the PSA */ + ifr.ifr_data = (caddr_t)psabuf; + if (ioctl(sd, SIOCGWLPSA, (caddr_t)&ifr)) + err(1,"get PSA"); + + /* get the current NWID */ + if (ioctl(sd, SIOCGWLCNWID, (caddr_t)&ifr)) + err(1,"get NWID"); + currnwid = (int)ifr.ifr_data; + + /* just dump and exit? */ + if (argc == 2) { + print_psa(psabuf, currnwid); + exit(0); + } + + /* loop reading arg pairs */ + for (argind = 2; argind < argc; argind += 2) { + + param = argv[argind]; + value = argv[argind+1]; + + /* What to do? */ + + if (!strcasecmp(param,"currnwid")) { /* set current NWID */ + val = strtol(value,&cp,0); + if ((val < 0) || (val > 0xffff) || (cp == value)) + errx(1,"bad NWID '%s'",value); + + ifr.ifr_data = (caddr_t)val; + if (ioctl(sd, SIOCSWLCNWID, (caddr_t)&ifr)) + err(1,"set NWID (interface not up?)"); + continue ; + } + + if (!strcasecmp(param,"irq")) { + val = strtol(value,&cp,0); + val = irqvals[val]; + if ((val == 0) || (cp == value)) + errx(1,"bad IRQ '%s'",value); + psabuf[WLPSA_IRQNO] = (u_char)val; + work = 1; + continue; + } + + if (!strcasecmp(param,"mac")) { + if ((ea = ether_aton(value)) == NULL) + errx(1,"bad ethernet address '%s'",value); + for (i = 0; i < 6; i++) + psabuf[WLPSA_LOCALMAC + i] = ea->octet[i]; + work = 1; + continue; + } + + if (!strcasecmp(param,"macsel")) { + if (!strcasecmp(value,"local")) { + psabuf[WLPSA_MACSEL] |= 0x1; + work = 1; + continue; + } + if (!strcasecmp(value,"universal")) { + psabuf[WLPSA_MACSEL] &= ~0x1; + work = 1; + continue; + } + errx(1,"bad macsel value '%s'",value); + } + + if (!strcasecmp(param,"nwid")) { + val = strtol(value,&cp,0); + if ((val < 0) || (val > 0xffff) || (cp == value)) + errx(1,"bad NWID '%s'",value); + psabuf[WLPSA_NWID] = (val >> 8) & 0xff; + psabuf[WLPSA_NWID+1] = val & 0xff; + work = 1; + continue; + } + if (!strcasecmp(param,"cache")) { + + /* raw cache dump + */ + if (!strcasecmp(value,"raw")) { + get_cache(sd, &ifr); + raw_cache(); + continue; + } + /* scaled cache dump + */ + else if (!strcasecmp(value,"scale")) { + get_cache(sd, &ifr); + scale_cache(); + continue; + } + /* zero out cache + */ + else if (!strcasecmp(value,"zero")) { + if (ioctl(sd, SIOCDWLCACHE, (caddr_t)&ifr)) + err(1,"zero cache"); + continue; + } + errx(1,"unknown value '%s'", value); + } + errx(1,"unknown parameter '%s'",param); + } + if (work) { + ifr.ifr_data = (caddr_t)psabuf; + if (ioctl(sd, SIOCSWLPSA, (caddr_t)&ifr)) + err(1,"set PSA"); + } + return(0); +} |