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