126005Smsmith/* 226005Smsmith * Copyright (C) 1996 326005Smsmith * Michael Smith. All rights reserved. 426005Smsmith * 526005Smsmith * Redistribution and use in source and binary forms, with or without 626005Smsmith * modification, are permitted provided that the following conditions 726005Smsmith * are met: 826005Smsmith * 1. Redistributions of source code must retain the above copyright 926005Smsmith * notice, this list of conditions and the following disclaimer. 1026005Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1126005Smsmith * notice, this list of conditions and the following disclaimer in the 1226005Smsmith * documentation and/or other materials provided with the distribution. 1326005Smsmith * 1426005Smsmith * THIS SOFTWARE IS PROVIDED BY Michael Smith AND CONTRIBUTORS ``AS IS'' AND 1526005Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1626005Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1726005Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL Michael Smith OR CONTRIBUTORS BE LIABLE 1826005Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1926005Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2026005Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2126005Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2226005Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2326005Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2426005Smsmith * SUCH DAMAGE. 2526005Smsmith */ 2630774Scharnier 2730774Scharnier#ifndef lint 2830774Scharnierstatic const char rcsid[] = 2950479Speter "$FreeBSD$"; 3030774Scharnier#endif /* not lint */ 3130774Scharnier 3226005Smsmith/* 3326005Smsmith * wlconfig.c 3426005Smsmith * 3526005Smsmith * utility to read out and change various WAVELAN parameters. 3626005Smsmith * Currently supports NWID and IRQ values. 3726005Smsmith * 3826005Smsmith * The NWID is used by 2 or more wavelan controllers to determine 3926005Smsmith * if packets should be received or not. It is a filter that 4026005Smsmith * is roughly analogous to the "channel" setting with a garage 4126005Smsmith * door controller. Two companies side by side with wavelan devices 4226005Smsmith * that could actually hear each other can use different NWIDs 4326005Smsmith * and ignore packets. In truth however, the air space is shared, 4426005Smsmith * and the NWID is a virtual filter. 4526005Smsmith * 4626005Smsmith * In the current set of wavelan drivers, ioctls changed only 4726005Smsmith * the runtime radio modem registers which act in a manner analogous 4826005Smsmith * to an ethernet transceiver. The ioctls do not change the 4926005Smsmith * stored nvram PSA (or parameter storage area). At boot, the PSA 5026005Smsmith * values are stored in the radio modem. Thus when the 5126005Smsmith * system reboots it will restore the wavelan NWID to the value 5226005Smsmith * stored in the PSA. The NCR/ATT dos utilities must be used to 5326005Smsmith * change the initial NWID values in the PSA. The wlconfig utility 5426005Smsmith * may be used to set a different NWID at runtime; this is only 5526005Smsmith * permitted while the interface is up and running. 5626005Smsmith * 5726005Smsmith * By contrast, the IRQ value can only be changed while the 5826005Smsmith * Wavelan card is down and unconfigured, and it will remain 5926005Smsmith * disabled after an IRQ change until reboot. 6026005Smsmith * 6126005Smsmith */ 6226005Smsmith 6326005Smsmith#include <sys/param.h> 6426005Smsmith#include <sys/socket.h> 6526005Smsmith#include <sys/ioctl.h> 6626023Smsmith#include <sys/time.h> 6726005Smsmith#include <machine/if_wl_wavelan.h> 6826005Smsmith 6926005Smsmith#include <net/if.h> 7026005Smsmith#include <netinet/in.h> 7126005Smsmith#include <netinet/if_ether.h> 7226005Smsmith 7326005Smsmith#include <err.h> 7426005Smsmith#include <stdio.h> 7526005Smsmith#include <stdlib.h> 7626005Smsmith#include <string.h> 7726005Smsmith#include <unistd.h> 7826005Smsmith#include <limits.h> 7926005Smsmith 8026005Smsmith/* translate IRQ bit to number */ 8126005Smsmith/* array for maping irq numbers to values for the irq parameter register */ 8226005Smsmithstatic int irqvals[16] = { 8326005Smsmith 0, 0, 0, 0x01, 0x02, 0x04, 0, 0x08, 0, 0, 0x10, 0x20, 0x40, 0, 0, 0x80 8426005Smsmith}; 8526005Smsmith 8627818Smsmith/* cache */ 8727818Smsmithstatic int w_sigitems; /* count of valid items */ 8827818Smsmithstatic struct w_sigcache wsc[MAXCACHEITEMS]; 8927818Smsmith 9026005Smsmithint 9126005Smsmithwlirq(int irqval) 9226005Smsmith{ 9326005Smsmith int irq; 9426005Smsmith 9526005Smsmith for(irq = 0; irq < 16; irq++) 9626005Smsmith if(irqvals[irq] == irqval) 9726005Smsmith return(irq); 9826005Smsmith return 0; 9926005Smsmith} 10026005Smsmith 10126005Smsmithchar *compat_type[] = { 10226005Smsmith "PC-AT 915MHz", 10326005Smsmith "PC-MC 915MHz", 10426005Smsmith "PC-AT 2.4GHz", 10526005Smsmith "PC-MC 2.4GHz", 10626005Smsmith "PCCARD or 1/2 size AT, 915MHz or 2.4GHz" 10726005Smsmith}; 10826005Smsmith 10926005Smsmithchar *subband[] = { 11026005Smsmith "915MHz/see WaveModem", 11126005Smsmith "2425MHz", 11226005Smsmith "2460MHz", 11326005Smsmith "2484MHz", 11426005Smsmith "2430.5MHz" 11526005Smsmith}; 11626005Smsmith 11726005Smsmith 11826005Smsmith/* 11926005Smsmith** print_psa 12026005Smsmith** 12126005Smsmith** Given a pointer to a PSA structure, print it out 12226005Smsmith*/ 12326005Smsmithvoid 12426005Smsmithprint_psa(u_char *psa, int currnwid) 12526005Smsmith{ 12626005Smsmith int nwid; 12726005Smsmith 12826005Smsmith /* 12926005Smsmith ** Work out what sort of board we have 13026005Smsmith */ 13126005Smsmith if (psa[0] == 0x14) { 13226005Smsmith printf("Board type : Microchannel\n"); 13326005Smsmith } else { 13426005Smsmith if (psa[1] == 0) { 13526005Smsmith printf("Board type : PCCARD\n"); 13626005Smsmith } else { 13726005Smsmith printf("Board type : ISA"); 13826005Smsmith if ((psa[4] == 0) && 13926005Smsmith (psa[5] == 0) && 14026005Smsmith (psa[6] == 0)) 14126005Smsmith printf(" (DEC OEM)"); 14226005Smsmith printf("\n"); 14326005Smsmith printf("Base address options : 0x300, 0x%02x0, 0x%02x0, 0x%02x0\n", 14426005Smsmith (int)psa[1], (int)psa[2], (int)psa[3]); 14526005Smsmith printf("Waitstates : %d\n",psa[7] & 0xf); 14626005Smsmith printf("Bus mode : %s\n",(psa[7] & 0x10) ? "EISA" : "ISA"); 14726005Smsmith printf("IRQ : %d\n",wlirq(psa[8])); 14826005Smsmith } 14926005Smsmith } 15026005Smsmith printf("Default MAC address : %02x:%02x:%02x:%02x:%02x:%02x\n", 15126005Smsmith psa[0x10],psa[0x11],psa[0x12],psa[0x13],psa[0x14],psa[0x15]); 15226005Smsmith printf("Soft MAC address : %02x:%02x:%02x:%02x:%02x:%02x\n", 15326005Smsmith psa[0x16],psa[0x17],psa[0x18],psa[0x19],psa[0x1a],psa[0x1b]); 15426005Smsmith printf("Current MAC address : %s\n",(psa[0x1c] & 0x1) ? "Soft" : "Default"); 15569238Sdannyboy printf("Adapter compatibility : "); 15626005Smsmith if (psa[0x1d] < 5) { 15726005Smsmith printf("%s\n",compat_type[psa[0x1d]]); 15826005Smsmith } else { 15926005Smsmith printf("unknown\n"); 16026005Smsmith } 16126005Smsmith printf("Threshold preset : %d\n",psa[0x1e]); 16226005Smsmith printf("Call code required : %s\n",(psa[0x1f] & 0x1) ? "YES" : "NO"); 16326005Smsmith if (psa[0x1f] & 0x1) 16426005Smsmith printf("Call code : 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", 16526005Smsmith psa[0x30],psa[0x31],psa[0x32],psa[0x33],psa[0x34],psa[0x35],psa[0x36],psa[0x37]); 16626005Smsmith printf("Subband : %s\n",subband[psa[0x20] & 0xf]); 16726005Smsmith printf("Quality threshold : %d\n",psa[0x21]); 16826005Smsmith printf("Hardware version : %d (%s)\n",psa[0x22],psa[0x22] ? "Rel3" : "Rel1/Rel2"); 16926005Smsmith printf("Network ID enable : %s\n",(psa[0x25] & 0x1) ? "YES" : "NO"); 17026005Smsmith if (psa[0x25] & 0x1) { 17126005Smsmith nwid = (psa[0x23] << 8) + psa[0x24]; 17226005Smsmith printf("NWID : 0x%04x\n",nwid); 17326005Smsmith if (nwid != currnwid) { 17426005Smsmith printf("Current NWID : 0x%04x\n",currnwid); 17526005Smsmith } 17626005Smsmith } 17726005Smsmith printf("Datalink security : %s\n",(psa[0x26] & 0x1) ? "YES" : "NO"); 17826005Smsmith if (psa[0x26] & 0x1) { 17926005Smsmith printf("Encryption key : "); 18026005Smsmith if (psa[0x27] == 0) { 18126005Smsmith printf("DENIED\n"); 18226005Smsmith } else { 18326005Smsmith printf("0x%02x%02x%02x%02x%02x%02x%02x%02x\n", 18426005Smsmith psa[0x27],psa[0x28],psa[0x29],psa[0x2a],psa[0x2b],psa[0x2c],psa[0x2d],psa[0x2e]); 18526005Smsmith } 18626005Smsmith } 18726005Smsmith printf("Databus width : %d (%s)\n", 18826005Smsmith (psa[0x2f] & 0x1) ? 16 : 8, (psa[0x2f] & 0x80) ? "fixed" : "variable"); 18926005Smsmith printf("Configuration state : %sconfigured\n",(psa[0x38] & 0x1) ? "" : "un"); 19026005Smsmith printf("CRC-16 : 0x%02x%02x\n",psa[0x3e],psa[0x3d]); 19126005Smsmith printf("CRC status : "); 19226005Smsmith switch(psa[0x3f]) { 19326005Smsmith case 0xaa: 19426005Smsmith printf("OK\n"); 19526005Smsmith break; 19626005Smsmith case 0x55: 19726005Smsmith printf("BAD\n"); 19826005Smsmith break; 19926005Smsmith default: 20026005Smsmith printf("Error\n"); 20126005Smsmith break; 20226005Smsmith } 20326005Smsmith} 20426005Smsmith 20526005Smsmith 20630774Scharnierstatic void 20730774Scharnierusage() 20826005Smsmith{ 20930774Scharnier fprintf(stderr,"usage: wlconfig ifname [param value ...]\n"); 21026005Smsmith exit(1); 21126005Smsmith} 21226005Smsmith 21327818Smsmith 21426005Smsmithvoid 21527818Smsmithget_cache(int sd, struct ifreq *ifr) 21627818Smsmith{ 21727818Smsmith /* get the cache count */ 21830774Scharnier if (ioctl(sd, SIOCGWLCITEM, (caddr_t)ifr)) 21930774Scharnier err(1, "SIOCGWLCITEM - get cache count"); 22027818Smsmith w_sigitems = (int) ifr->ifr_data; 22127818Smsmith 22227818Smsmith ifr->ifr_data = (caddr_t) &wsc; 22327818Smsmith /* get the cache */ 22430774Scharnier if (ioctl(sd, SIOCGWLCACHE, (caddr_t)ifr)) 22530774Scharnier err(1, "SIOCGWLCACHE - get cache count"); 22627818Smsmith} 22727818Smsmith 22827818Smsmithstatic int 22927818Smsmithscale_value(int value, int max) 23027818Smsmith{ 23127818Smsmith double dmax = (double) max; 23227818Smsmith if (value > max) 23327818Smsmith return(100); 23427818Smsmith return((value/dmax) * 100); 23527818Smsmith} 23627818Smsmith 23727818Smsmithstatic void 23827818Smsmithdump_cache(int rawFlag) 23927818Smsmith{ 24027818Smsmith int i; 24127818Smsmith int signal, silence, quality; 24227818Smsmith 24327818Smsmith if (rawFlag) 24427818Smsmith printf("signal range 0..63: silence 0..63: quality 0..15\n"); 24527818Smsmith else 24627818Smsmith printf("signal range 0..100: silence 0..100: quality 0..100\n"); 24727818Smsmith 24827818Smsmith /* after you read it, loop through structure,i.e. wsc 24927818Smsmith * print each item: 25027818Smsmith */ 25127818Smsmith for(i = 0; i < w_sigitems; i++) { 25227818Smsmith printf("[%d:%d]>\n", i+1, w_sigitems); 25327818Smsmith printf("\tip: %d.%d.%d.%d,",((wsc[i].ipsrc >> 0) & 0xff), 25427818Smsmith ((wsc[i].ipsrc >> 8) & 0xff), 25527818Smsmith ((wsc[i].ipsrc >> 16) & 0xff), 25627818Smsmith ((wsc[i].ipsrc >> 24) & 0xff)); 25727818Smsmith printf(" mac: %02x:%02x:%02x:%02x:%02x:%02x\n", 25827818Smsmith wsc[i].macsrc[0]&0xff, 25927818Smsmith wsc[i].macsrc[1]&0xff, 26027818Smsmith wsc[i].macsrc[2]&0xff, 26127818Smsmith wsc[i].macsrc[3]&0xff, 26227818Smsmith wsc[i].macsrc[4]&0xff, 26327818Smsmith wsc[i].macsrc[5]&0xff); 26427818Smsmith if (rawFlag) { 26527818Smsmith signal = wsc[i].signal; 26627818Smsmith silence = wsc[i].silence; 26727818Smsmith quality = wsc[i].quality; 26827818Smsmith } 26927818Smsmith else { 27027818Smsmith signal = scale_value(wsc[i].signal, 63); 27127818Smsmith silence = scale_value(wsc[i].silence, 63); 27227818Smsmith quality = scale_value(wsc[i].quality, 15); 27327818Smsmith } 27427818Smsmith printf("\tsignal: %d, silence: %d, quality: %d, ", 27527818Smsmith signal, 27627818Smsmith silence, 27727818Smsmith quality); 27827818Smsmith printf("snr: %d\n", signal - silence); 27927818Smsmith } 28027818Smsmith} 28127818Smsmith 28227818Smsmith#define raw_cache() dump_cache(1) 28327818Smsmith#define scale_cache() dump_cache(0) 28427818Smsmith 28530774Scharnierint 28626005Smsmithmain(int argc, char *argv[]) 28726005Smsmith{ 28826005Smsmith int sd; 28926005Smsmith struct ifreq ifr; 29026005Smsmith u_char psabuf[0x40]; 29126005Smsmith int val, argind, i; 29226005Smsmith char *cp, *param, *value; 29326005Smsmith struct ether_addr *ea; 29426005Smsmith int work = 0; 29526005Smsmith int currnwid; 29626005Smsmith 29726005Smsmith if ((argc < 2) || (argc % 2)) 29830774Scharnier usage(); 29926005Smsmith 30026005Smsmith /* get a socket */ 30126005Smsmith sd = socket(AF_INET, SOCK_DGRAM, 0); 30226005Smsmith if (sd < 0) 30326005Smsmith err(1,"socket"); 30426005Smsmith strncpy(ifr.ifr_name, argv[1], sizeof(ifr.ifr_name)); 30526005Smsmith ifr.ifr_addr.sa_family = AF_INET; 30626005Smsmith 30726005Smsmith /* get the PSA */ 30826005Smsmith ifr.ifr_data = (caddr_t)psabuf; 30926005Smsmith if (ioctl(sd, SIOCGWLPSA, (caddr_t)&ifr)) 31030774Scharnier err(1,"get PSA"); 31126005Smsmith 31226005Smsmith /* get the current NWID */ 31326005Smsmith if (ioctl(sd, SIOCGWLCNWID, (caddr_t)&ifr)) 31430774Scharnier err(1,"get NWID"); 31526005Smsmith currnwid = (int)ifr.ifr_data; 31626005Smsmith 31726005Smsmith /* just dump and exit? */ 31826005Smsmith if (argc == 2) { 31926005Smsmith print_psa(psabuf, currnwid); 32026005Smsmith exit(0); 32126005Smsmith } 32226005Smsmith 32326005Smsmith /* loop reading arg pairs */ 32426005Smsmith for (argind = 2; argind < argc; argind += 2) { 32526005Smsmith 32626005Smsmith param = argv[argind]; 32726005Smsmith value = argv[argind+1]; 32826005Smsmith 32926005Smsmith /* What to do? */ 33026005Smsmith 33126005Smsmith if (!strcasecmp(param,"currnwid")) { /* set current NWID */ 33226005Smsmith val = strtol(value,&cp,0); 33326005Smsmith if ((val < 0) || (val > 0xffff) || (cp == value)) 33430774Scharnier errx(1,"bad NWID '%s'",value); 33526005Smsmith 33626005Smsmith ifr.ifr_data = (caddr_t)val; 33726005Smsmith if (ioctl(sd, SIOCSWLCNWID, (caddr_t)&ifr)) 33830774Scharnier err(1,"set NWID (interface not up?)"); 33926005Smsmith continue ; 34026005Smsmith } 34126005Smsmith 34226005Smsmith if (!strcasecmp(param,"irq")) { 34326005Smsmith val = strtol(value,&cp,0); 34426005Smsmith val = irqvals[val]; 34526005Smsmith if ((val == 0) || (cp == value)) 34630774Scharnier errx(1,"bad IRQ '%s'",value); 34726005Smsmith psabuf[WLPSA_IRQNO] = (u_char)val; 34826005Smsmith work = 1; 34926005Smsmith continue; 35026005Smsmith } 35126005Smsmith 35226005Smsmith if (!strcasecmp(param,"mac")) { 35326005Smsmith if ((ea = ether_aton(value)) == NULL) 35430774Scharnier errx(1,"bad ethernet address '%s'",value); 35526005Smsmith for (i = 0; i < 6; i++) 35626005Smsmith psabuf[WLPSA_LOCALMAC + i] = ea->octet[i]; 35726005Smsmith work = 1; 35826005Smsmith continue; 35926005Smsmith } 36026005Smsmith 36126005Smsmith if (!strcasecmp(param,"macsel")) { 36226005Smsmith if (!strcasecmp(value,"local")) { 36326005Smsmith psabuf[WLPSA_MACSEL] |= 0x1; 36426005Smsmith work = 1; 36526005Smsmith continue; 36626005Smsmith } 36726005Smsmith if (!strcasecmp(value,"universal")) { 36826005Smsmith psabuf[WLPSA_MACSEL] &= ~0x1; 36926005Smsmith work = 1; 37026005Smsmith continue; 37126005Smsmith } 37230774Scharnier errx(1,"bad macsel value '%s'",value); 37326005Smsmith } 37426005Smsmith 37526005Smsmith if (!strcasecmp(param,"nwid")) { 37626005Smsmith val = strtol(value,&cp,0); 37726005Smsmith if ((val < 0) || (val > 0xffff) || (cp == value)) 37830774Scharnier errx(1,"bad NWID '%s'",value); 37926005Smsmith psabuf[WLPSA_NWID] = (val >> 8) & 0xff; 38026005Smsmith psabuf[WLPSA_NWID+1] = val & 0xff; 38126005Smsmith work = 1; 38226005Smsmith continue; 38326005Smsmith } 38427818Smsmith if (!strcasecmp(param,"cache")) { 38527818Smsmith 38627818Smsmith /* raw cache dump 38727818Smsmith */ 38827818Smsmith if (!strcasecmp(value,"raw")) { 38927818Smsmith get_cache(sd, &ifr); 39027818Smsmith raw_cache(); 39127818Smsmith continue; 39227818Smsmith } 39327818Smsmith /* scaled cache dump 39427818Smsmith */ 39527818Smsmith else if (!strcasecmp(value,"scale")) { 39627818Smsmith get_cache(sd, &ifr); 39727818Smsmith scale_cache(); 39827818Smsmith continue; 39927818Smsmith } 40027818Smsmith /* zero out cache 40127818Smsmith */ 40227818Smsmith else if (!strcasecmp(value,"zero")) { 40327818Smsmith if (ioctl(sd, SIOCDWLCACHE, (caddr_t)&ifr)) 40430774Scharnier err(1,"zero cache"); 40527818Smsmith continue; 40627818Smsmith } 40730774Scharnier errx(1,"unknown value '%s'", value); 40827818Smsmith } 40930774Scharnier errx(1,"unknown parameter '%s'",param); 41026005Smsmith } 41126005Smsmith if (work) { 41226005Smsmith ifr.ifr_data = (caddr_t)psabuf; 41326005Smsmith if (ioctl(sd, SIOCSWLPSA, (caddr_t)&ifr)) 41430774Scharnier err(1,"set PSA"); 41526005Smsmith } 41630774Scharnier return(0); 41726005Smsmith} 418