wlconfig.c revision 30774
1/* 2 * Copyright (C) 1996 3 * Michael Smith. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY Michael Smith AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL Michael Smith OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#ifndef lint 28static const char rcsid[] = 29 "$Id$"; 30#endif /* not lint */ 31 32/* 33 * wlconfig.c 34 * 35 * utility to read out and change various WAVELAN parameters. 36 * Currently supports NWID and IRQ values. 37 * 38 * The NWID is used by 2 or more wavelan controllers to determine 39 * if packets should be received or not. It is a filter that 40 * is roughly analogous to the "channel" setting with a garage 41 * door controller. Two companies side by side with wavelan devices 42 * that could actually hear each other can use different NWIDs 43 * and ignore packets. In truth however, the air space is shared, 44 * and the NWID is a virtual filter. 45 * 46 * In the current set of wavelan drivers, ioctls changed only 47 * the runtime radio modem registers which act in a manner analogous 48 * to an ethernet transceiver. The ioctls do not change the 49 * stored nvram PSA (or parameter storage area). At boot, the PSA 50 * values are stored in the radio modem. Thus when the 51 * system reboots it will restore the wavelan NWID to the value 52 * stored in the PSA. The NCR/ATT dos utilities must be used to 53 * change the initial NWID values in the PSA. The wlconfig utility 54 * may be used to set a different NWID at runtime; this is only 55 * permitted while the interface is up and running. 56 * 57 * By contrast, the IRQ value can only be changed while the 58 * Wavelan card is down and unconfigured, and it will remain 59 * disabled after an IRQ change until reboot. 60 * 61 */ 62 63#include <sys/param.h> 64#include <sys/socket.h> 65#include <sys/ioctl.h> 66#include <sys/time.h> 67#include <machine/if_wl_wavelan.h> 68 69#include <net/if.h> 70#include <net/if_var.h> 71#include <netinet/in.h> 72#include <netinet/if_ether.h> 73extern struct ether_addr *ether_aton(char *a); 74 75#include <err.h> 76#include <stdio.h> 77#include <stdlib.h> 78#include <string.h> 79#include <unistd.h> 80#include <limits.h> 81 82/* translate IRQ bit to number */ 83/* array for maping irq numbers to values for the irq parameter register */ 84static int irqvals[16] = { 85 0, 0, 0, 0x01, 0x02, 0x04, 0, 0x08, 0, 0, 0x10, 0x20, 0x40, 0, 0, 0x80 86}; 87 88/* cache */ 89static int w_sigitems; /* count of valid items */ 90static struct w_sigcache wsc[MAXCACHEITEMS]; 91 92int 93wlirq(int irqval) 94{ 95 int irq; 96 97 for(irq = 0; irq < 16; irq++) 98 if(irqvals[irq] == irqval) 99 return(irq); 100 return 0; 101} 102 103char *compat_type[] = { 104 "PC-AT 915MHz", 105 "PC-MC 915MHz", 106 "PC-AT 2.4GHz", 107 "PC-MC 2.4GHz", 108 "PCCARD or 1/2 size AT, 915MHz or 2.4GHz" 109}; 110 111char *subband[] = { 112 "915MHz/see WaveModem", 113 "2425MHz", 114 "2460MHz", 115 "2484MHz", 116 "2430.5MHz" 117}; 118 119 120/* 121** print_psa 122** 123** Given a pointer to a PSA structure, print it out 124*/ 125void 126print_psa(u_char *psa, int currnwid) 127{ 128 int nwid; 129 130 /* 131 ** Work out what sort of board we have 132 */ 133 if (psa[0] == 0x14) { 134 printf("Board type : Microchannel\n"); 135 } else { 136 if (psa[1] == 0) { 137 printf("Board type : PCCARD\n"); 138 } else { 139 printf("Board type : ISA"); 140 if ((psa[4] == 0) && 141 (psa[5] == 0) && 142 (psa[6] == 0)) 143 printf(" (DEC OEM)"); 144 printf("\n"); 145 printf("Base address options : 0x300, 0x%02x0, 0x%02x0, 0x%02x0\n", 146 (int)psa[1], (int)psa[2], (int)psa[3]); 147 printf("Waitstates : %d\n",psa[7] & 0xf); 148 printf("Bus mode : %s\n",(psa[7] & 0x10) ? "EISA" : "ISA"); 149 printf("IRQ : %d\n",wlirq(psa[8])); 150 } 151 } 152 printf("Default MAC address : %02x:%02x:%02x:%02x:%02x:%02x\n", 153 psa[0x10],psa[0x11],psa[0x12],psa[0x13],psa[0x14],psa[0x15]); 154 printf("Soft MAC address : %02x:%02x:%02x:%02x:%02x:%02x\n", 155 psa[0x16],psa[0x17],psa[0x18],psa[0x19],psa[0x1a],psa[0x1b]); 156 printf("Current MAC address : %s\n",(psa[0x1c] & 0x1) ? "Soft" : "Default"); 157 printf("Adapter compatability : "); 158 if (psa[0x1d] < 5) { 159 printf("%s\n",compat_type[psa[0x1d]]); 160 } else { 161 printf("unknown\n"); 162 } 163 printf("Threshold preset : %d\n",psa[0x1e]); 164 printf("Call code required : %s\n",(psa[0x1f] & 0x1) ? "YES" : "NO"); 165 if (psa[0x1f] & 0x1) 166 printf("Call code : 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", 167 psa[0x30],psa[0x31],psa[0x32],psa[0x33],psa[0x34],psa[0x35],psa[0x36],psa[0x37]); 168 printf("Subband : %s\n",subband[psa[0x20] & 0xf]); 169 printf("Quality threshold : %d\n",psa[0x21]); 170 printf("Hardware version : %d (%s)\n",psa[0x22],psa[0x22] ? "Rel3" : "Rel1/Rel2"); 171 printf("Network ID enable : %s\n",(psa[0x25] & 0x1) ? "YES" : "NO"); 172 if (psa[0x25] & 0x1) { 173 nwid = (psa[0x23] << 8) + psa[0x24]; 174 printf("NWID : 0x%04x\n",nwid); 175 if (nwid != currnwid) { 176 printf("Current NWID : 0x%04x\n",currnwid); 177 } 178 } 179 printf("Datalink security : %s\n",(psa[0x26] & 0x1) ? "YES" : "NO"); 180 if (psa[0x26] & 0x1) { 181 printf("Encryption key : "); 182 if (psa[0x27] == 0) { 183 printf("DENIED\n"); 184 } else { 185 printf("0x%02x%02x%02x%02x%02x%02x%02x%02x\n", 186 psa[0x27],psa[0x28],psa[0x29],psa[0x2a],psa[0x2b],psa[0x2c],psa[0x2d],psa[0x2e]); 187 } 188 } 189 printf("Databus width : %d (%s)\n", 190 (psa[0x2f] & 0x1) ? 16 : 8, (psa[0x2f] & 0x80) ? "fixed" : "variable"); 191 printf("Configuration state : %sconfigured\n",(psa[0x38] & 0x1) ? "" : "un"); 192 printf("CRC-16 : 0x%02x%02x\n",psa[0x3e],psa[0x3d]); 193 printf("CRC status : "); 194 switch(psa[0x3f]) { 195 case 0xaa: 196 printf("OK\n"); 197 break; 198 case 0x55: 199 printf("BAD\n"); 200 break; 201 default: 202 printf("Error\n"); 203 break; 204 } 205} 206 207 208static void 209usage() 210{ 211 fprintf(stderr,"usage: wlconfig ifname [param value ...]\n"); 212 exit(1); 213} 214 215 216void 217get_cache(int sd, struct ifreq *ifr) 218{ 219 /* get the cache count */ 220 if (ioctl(sd, SIOCGWLCITEM, (caddr_t)ifr)) 221 err(1, "SIOCGWLCITEM - get cache count"); 222 w_sigitems = (int) ifr->ifr_data; 223 224 ifr->ifr_data = (caddr_t) &wsc; 225 /* get the cache */ 226 if (ioctl(sd, SIOCGWLCACHE, (caddr_t)ifr)) 227 err(1, "SIOCGWLCACHE - get cache count"); 228} 229 230static int 231scale_value(int value, int max) 232{ 233 double dmax = (double) max; 234 if (value > max) 235 return(100); 236 return((value/dmax) * 100); 237} 238 239static void 240dump_cache(int rawFlag) 241{ 242 int i; 243 int signal, silence, quality; 244 245 if (rawFlag) 246 printf("signal range 0..63: silence 0..63: quality 0..15\n"); 247 else 248 printf("signal range 0..100: silence 0..100: quality 0..100\n"); 249 250 /* after you read it, loop through structure,i.e. wsc 251 * print each item: 252 */ 253 for(i = 0; i < w_sigitems; i++) { 254 printf("[%d:%d]>\n", i+1, w_sigitems); 255 printf("\tip: %d.%d.%d.%d,",((wsc[i].ipsrc >> 0) & 0xff), 256 ((wsc[i].ipsrc >> 8) & 0xff), 257 ((wsc[i].ipsrc >> 16) & 0xff), 258 ((wsc[i].ipsrc >> 24) & 0xff)); 259 printf(" mac: %02x:%02x:%02x:%02x:%02x:%02x\n", 260 wsc[i].macsrc[0]&0xff, 261 wsc[i].macsrc[1]&0xff, 262 wsc[i].macsrc[2]&0xff, 263 wsc[i].macsrc[3]&0xff, 264 wsc[i].macsrc[4]&0xff, 265 wsc[i].macsrc[5]&0xff); 266 if (rawFlag) { 267 signal = wsc[i].signal; 268 silence = wsc[i].silence; 269 quality = wsc[i].quality; 270 } 271 else { 272 signal = scale_value(wsc[i].signal, 63); 273 silence = scale_value(wsc[i].silence, 63); 274 quality = scale_value(wsc[i].quality, 15); 275 } 276 printf("\tsignal: %d, silence: %d, quality: %d, ", 277 signal, 278 silence, 279 quality); 280 printf("snr: %d\n", signal - silence); 281 } 282} 283 284#define raw_cache() dump_cache(1) 285#define scale_cache() dump_cache(0) 286 287int 288main(int argc, char *argv[]) 289{ 290 int sd; 291 struct ifreq ifr; 292 u_char psabuf[0x40]; 293 int val, argind, i; 294 char *cp, *param, *value; 295 struct ether_addr *ea; 296 int work = 0; 297 int currnwid; 298 299 if ((argc < 2) || (argc % 2)) 300 usage(); 301 302 /* get a socket */ 303 sd = socket(AF_INET, SOCK_DGRAM, 0); 304 if (sd < 0) 305 err(1,"socket"); 306 strncpy(ifr.ifr_name, argv[1], sizeof(ifr.ifr_name)); 307 ifr.ifr_addr.sa_family = AF_INET; 308 309 /* get the PSA */ 310 ifr.ifr_data = (caddr_t)psabuf; 311 if (ioctl(sd, SIOCGWLPSA, (caddr_t)&ifr)) 312 err(1,"get PSA"); 313 314 /* get the current NWID */ 315 if (ioctl(sd, SIOCGWLCNWID, (caddr_t)&ifr)) 316 err(1,"get NWID"); 317 currnwid = (int)ifr.ifr_data; 318 319 /* just dump and exit? */ 320 if (argc == 2) { 321 print_psa(psabuf, currnwid); 322 exit(0); 323 } 324 325 /* loop reading arg pairs */ 326 for (argind = 2; argind < argc; argind += 2) { 327 328 param = argv[argind]; 329 value = argv[argind+1]; 330 331 /* What to do? */ 332 333 if (!strcasecmp(param,"currnwid")) { /* set current NWID */ 334 val = strtol(value,&cp,0); 335 if ((val < 0) || (val > 0xffff) || (cp == value)) 336 errx(1,"bad NWID '%s'",value); 337 338 ifr.ifr_data = (caddr_t)val; 339 if (ioctl(sd, SIOCSWLCNWID, (caddr_t)&ifr)) 340 err(1,"set NWID (interface not up?)"); 341 continue ; 342 } 343 344 if (!strcasecmp(param,"irq")) { 345 val = strtol(value,&cp,0); 346 val = irqvals[val]; 347 if ((val == 0) || (cp == value)) 348 errx(1,"bad IRQ '%s'",value); 349 psabuf[WLPSA_IRQNO] = (u_char)val; 350 work = 1; 351 continue; 352 } 353 354 if (!strcasecmp(param,"mac")) { 355 if ((ea = ether_aton(value)) == NULL) 356 errx(1,"bad ethernet address '%s'",value); 357 for (i = 0; i < 6; i++) 358 psabuf[WLPSA_LOCALMAC + i] = ea->octet[i]; 359 work = 1; 360 continue; 361 } 362 363 if (!strcasecmp(param,"macsel")) { 364 if (!strcasecmp(value,"local")) { 365 psabuf[WLPSA_MACSEL] |= 0x1; 366 work = 1; 367 continue; 368 } 369 if (!strcasecmp(value,"universal")) { 370 psabuf[WLPSA_MACSEL] &= ~0x1; 371 work = 1; 372 continue; 373 } 374 errx(1,"bad macsel value '%s'",value); 375 } 376 377 if (!strcasecmp(param,"nwid")) { 378 val = strtol(value,&cp,0); 379 if ((val < 0) || (val > 0xffff) || (cp == value)) 380 errx(1,"bad NWID '%s'",value); 381 psabuf[WLPSA_NWID] = (val >> 8) & 0xff; 382 psabuf[WLPSA_NWID+1] = val & 0xff; 383 work = 1; 384 continue; 385 } 386 if (!strcasecmp(param,"cache")) { 387 388 /* raw cache dump 389 */ 390 if (!strcasecmp(value,"raw")) { 391 get_cache(sd, &ifr); 392 raw_cache(); 393 continue; 394 } 395 /* scaled cache dump 396 */ 397 else if (!strcasecmp(value,"scale")) { 398 get_cache(sd, &ifr); 399 scale_cache(); 400 continue; 401 } 402 /* zero out cache 403 */ 404 else if (!strcasecmp(value,"zero")) { 405 if (ioctl(sd, SIOCDWLCACHE, (caddr_t)&ifr)) 406 err(1,"zero cache"); 407 continue; 408 } 409 errx(1,"unknown value '%s'", value); 410 } 411 errx(1,"unknown parameter '%s'",param); 412 } 413 if (work) { 414 ifr.ifr_data = (caddr_t)psabuf; 415 if (ioctl(sd, SIOCSWLPSA, (caddr_t)&ifr)) 416 err(1,"set PSA"); 417 } 418 return(0); 419} 420