wlconfig.c revision 69238
1217309Snwhitehorn/* 2251843Sbapt * Copyright (C) 1996 3217309Snwhitehorn * Michael Smith. All rights reserved. 4217309Snwhitehorn * 5217309Snwhitehorn * Redistribution and use in source and binary forms, with or without 6220749Snwhitehorn * modification, are permitted provided that the following conditions 7217309Snwhitehorn * are met: 8217309Snwhitehorn * 1. Redistributions of source code must retain the above copyright 9217309Snwhitehorn * notice, this list of conditions and the following disclaimer. 10217309Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright 11217309Snwhitehorn * notice, this list of conditions and the following disclaimer in the 12217309Snwhitehorn * documentation and/or other materials provided with the distribution. 13217309Snwhitehorn * 14217309Snwhitehorn * THIS SOFTWARE IS PROVIDED BY Michael Smith AND CONTRIBUTORS ``AS IS'' AND 15217309Snwhitehorn * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16217309Snwhitehorn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17217309Snwhitehorn * ARE DISCLAIMED. IN NO EVENT SHALL Michael Smith OR CONTRIBUTORS BE LIABLE 18217309Snwhitehorn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19217309Snwhitehorn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20217309Snwhitehorn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21217309Snwhitehorn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22217309Snwhitehorn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23217309Snwhitehorn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24217309Snwhitehorn * SUCH DAMAGE. 25217309Snwhitehorn */ 26217309Snwhitehorn 27217309Snwhitehorn#ifndef lint 28224014Snwhitehornstatic const char rcsid[] = 29217309Snwhitehorn "$FreeBSD: head/usr.sbin/wlconfig/wlconfig.c 69238 2000-11-26 23:51:07Z dannyboy $"; 30217309Snwhitehorn#endif /* not lint */ 31217309Snwhitehorn 32217309Snwhitehorn/* 33217309Snwhitehorn * wlconfig.c 34217309Snwhitehorn * 35217309Snwhitehorn * utility to read out and change various WAVELAN parameters. 36217309Snwhitehorn * Currently supports NWID and IRQ values. 37217309Snwhitehorn * 38217309Snwhitehorn * The NWID is used by 2 or more wavelan controllers to determine 39217309Snwhitehorn * if packets should be received or not. It is a filter that 40217309Snwhitehorn * is roughly analogous to the "channel" setting with a garage 41217309Snwhitehorn * door controller. Two companies side by side with wavelan devices 42217309Snwhitehorn * that could actually hear each other can use different NWIDs 43217309Snwhitehorn * and ignore packets. In truth however, the air space is shared, 44217309Snwhitehorn * and the NWID is a virtual filter. 45217309Snwhitehorn * 46217309Snwhitehorn * In the current set of wavelan drivers, ioctls changed only 47217309Snwhitehorn * the runtime radio modem registers which act in a manner analogous 48251843Sbapt * to an ethernet transceiver. The ioctls do not change the 49217309Snwhitehorn * stored nvram PSA (or parameter storage area). At boot, the PSA 50217309Snwhitehorn * values are stored in the radio modem. Thus when the 51217309Snwhitehorn * system reboots it will restore the wavelan NWID to the value 52217309Snwhitehorn * stored in the PSA. The NCR/ATT dos utilities must be used to 53217309Snwhitehorn * change the initial NWID values in the PSA. The wlconfig utility 54217309Snwhitehorn * may be used to set a different NWID at runtime; this is only 55217309Snwhitehorn * permitted while the interface is up and running. 56217309Snwhitehorn * 57217309Snwhitehorn * By contrast, the IRQ value can only be changed while the 58217309Snwhitehorn * Wavelan card is down and unconfigured, and it will remain 59217309Snwhitehorn * disabled after an IRQ change until reboot. 60217309Snwhitehorn * 61217309Snwhitehorn */ 62217309Snwhitehorn 63217309Snwhitehorn#include <sys/param.h> 64217309Snwhitehorn#include <sys/socket.h> 65217309Snwhitehorn#include <sys/ioctl.h> 66217309Snwhitehorn#include <sys/time.h> 67217309Snwhitehorn#include <machine/if_wl_wavelan.h> 68217309Snwhitehorn 69217309Snwhitehorn#include <net/if.h> 70217309Snwhitehorn#include <netinet/in.h> 71217309Snwhitehorn#include <netinet/if_ether.h> 72217309Snwhitehorn 73217309Snwhitehorn#include <err.h> 74217309Snwhitehorn#include <stdio.h> 75217309Snwhitehorn#include <stdlib.h> 76217309Snwhitehorn#include <string.h> 77217309Snwhitehorn#include <unistd.h> 78217309Snwhitehorn#include <limits.h> 79217309Snwhitehorn 80217309Snwhitehorn/* translate IRQ bit to number */ 81217309Snwhitehorn/* array for maping irq numbers to values for the irq parameter register */ 82220749Snwhitehornstatic int irqvals[16] = { 83217309Snwhitehorn 0, 0, 0, 0x01, 0x02, 0x04, 0, 0x08, 0, 0, 0x10, 0x20, 0x40, 0, 0, 0x80 84217309Snwhitehorn}; 85217309Snwhitehorn 86217309Snwhitehorn/* cache */ 87217309Snwhitehornstatic int w_sigitems; /* count of valid items */ 88217309Snwhitehornstatic struct w_sigcache wsc[MAXCACHEITEMS]; 89217309Snwhitehorn 90217309Snwhitehornint 91217309Snwhitehornwlirq(int irqval) 92217309Snwhitehorn{ 93217309Snwhitehorn int irq; 94217309Snwhitehorn 95217309Snwhitehorn for(irq = 0; irq < 16; irq++) 96217309Snwhitehorn if(irqvals[irq] == irqval) 97217309Snwhitehorn return(irq); 98217309Snwhitehorn return 0; 99217309Snwhitehorn} 100217309Snwhitehorn 101220749Snwhitehornchar *compat_type[] = { 102217309Snwhitehorn "PC-AT 915MHz", 103217309Snwhitehorn "PC-MC 915MHz", 104217309Snwhitehorn "PC-AT 2.4GHz", 105217309Snwhitehorn "PC-MC 2.4GHz", 106217309Snwhitehorn "PCCARD or 1/2 size AT, 915MHz or 2.4GHz" 107217309Snwhitehorn}; 108217309Snwhitehorn 109217309Snwhitehornchar *subband[] = { 110220749Snwhitehorn "915MHz/see WaveModem", 111217309Snwhitehorn "2425MHz", 112217309Snwhitehorn "2460MHz", 113217309Snwhitehorn "2484MHz", 114217309Snwhitehorn "2430.5MHz" 115217309Snwhitehorn}; 116217309Snwhitehorn 117217309Snwhitehorn 118217309Snwhitehorn/* 119217309Snwhitehorn** print_psa 120217309Snwhitehorn** 121217309Snwhitehorn** Given a pointer to a PSA structure, print it out 122217309Snwhitehorn*/ 123217309Snwhitehornvoid 124217309Snwhitehornprint_psa(u_char *psa, int currnwid) 125217309Snwhitehorn{ 126217309Snwhitehorn int nwid; 127217309Snwhitehorn 128217309Snwhitehorn /* 129217309Snwhitehorn ** Work out what sort of board we have 130217309Snwhitehorn */ 131217309Snwhitehorn if (psa[0] == 0x14) { 132217309Snwhitehorn printf("Board type : Microchannel\n"); 133217309Snwhitehorn } else { 134217309Snwhitehorn if (psa[1] == 0) { 135217309Snwhitehorn printf("Board type : PCCARD\n"); 136217309Snwhitehorn } else { 137217309Snwhitehorn printf("Board type : ISA"); 138217309Snwhitehorn if ((psa[4] == 0) && 139217309Snwhitehorn (psa[5] == 0) && 140217309Snwhitehorn (psa[6] == 0)) 141217309Snwhitehorn printf(" (DEC OEM)"); 142217309Snwhitehorn printf("\n"); 143217309Snwhitehorn printf("Base address options : 0x300, 0x%02x0, 0x%02x0, 0x%02x0\n", 144217309Snwhitehorn (int)psa[1], (int)psa[2], (int)psa[3]); 145217309Snwhitehorn printf("Waitstates : %d\n",psa[7] & 0xf); 146220749Snwhitehorn printf("Bus mode : %s\n",(psa[7] & 0x10) ? "EISA" : "ISA"); 147217309Snwhitehorn printf("IRQ : %d\n",wlirq(psa[8])); 148220749Snwhitehorn } 149217309Snwhitehorn } 150217309Snwhitehorn printf("Default MAC address : %02x:%02x:%02x:%02x:%02x:%02x\n", 151251843Sbapt psa[0x10],psa[0x11],psa[0x12],psa[0x13],psa[0x14],psa[0x15]); 152217309Snwhitehorn printf("Soft MAC address : %02x:%02x:%02x:%02x:%02x:%02x\n", 153217309Snwhitehorn psa[0x16],psa[0x17],psa[0x18],psa[0x19],psa[0x1a],psa[0x1b]); 154217309Snwhitehorn printf("Current MAC address : %s\n",(psa[0x1c] & 0x1) ? "Soft" : "Default"); 155217309Snwhitehorn printf("Adapter compatibility : "); 156217309Snwhitehorn if (psa[0x1d] < 5) { 157217309Snwhitehorn printf("%s\n",compat_type[psa[0x1d]]); 158217309Snwhitehorn } else { 159217309Snwhitehorn printf("unknown\n"); 160217309Snwhitehorn } 161217309Snwhitehorn printf("Threshold preset : %d\n",psa[0x1e]); 162217309Snwhitehorn printf("Call code required : %s\n",(psa[0x1f] & 0x1) ? "YES" : "NO"); 163217309Snwhitehorn if (psa[0x1f] & 0x1) 164217309Snwhitehorn printf("Call code : 0x%02x%02x%02x%02x%02x%02x%02x%02x\n", 165217309Snwhitehorn psa[0x30],psa[0x31],psa[0x32],psa[0x33],psa[0x34],psa[0x35],psa[0x36],psa[0x37]); 166217309Snwhitehorn printf("Subband : %s\n",subband[psa[0x20] & 0xf]); 167217309Snwhitehorn printf("Quality threshold : %d\n",psa[0x21]); 168217309Snwhitehorn printf("Hardware version : %d (%s)\n",psa[0x22],psa[0x22] ? "Rel3" : "Rel1/Rel2"); 169217309Snwhitehorn printf("Network ID enable : %s\n",(psa[0x25] & 0x1) ? "YES" : "NO"); 170217309Snwhitehorn if (psa[0x25] & 0x1) { 171217309Snwhitehorn nwid = (psa[0x23] << 8) + psa[0x24]; 172217309Snwhitehorn printf("NWID : 0x%04x\n",nwid); 173217309Snwhitehorn if (nwid != currnwid) { 174217309Snwhitehorn printf("Current NWID : 0x%04x\n",currnwid); 175217309Snwhitehorn } 176 } 177 printf("Datalink security : %s\n",(psa[0x26] & 0x1) ? "YES" : "NO"); 178 if (psa[0x26] & 0x1) { 179 printf("Encryption key : "); 180 if (psa[0x27] == 0) { 181 printf("DENIED\n"); 182 } else { 183 printf("0x%02x%02x%02x%02x%02x%02x%02x%02x\n", 184 psa[0x27],psa[0x28],psa[0x29],psa[0x2a],psa[0x2b],psa[0x2c],psa[0x2d],psa[0x2e]); 185 } 186 } 187 printf("Databus width : %d (%s)\n", 188 (psa[0x2f] & 0x1) ? 16 : 8, (psa[0x2f] & 0x80) ? "fixed" : "variable"); 189 printf("Configuration state : %sconfigured\n",(psa[0x38] & 0x1) ? "" : "un"); 190 printf("CRC-16 : 0x%02x%02x\n",psa[0x3e],psa[0x3d]); 191 printf("CRC status : "); 192 switch(psa[0x3f]) { 193 case 0xaa: 194 printf("OK\n"); 195 break; 196 case 0x55: 197 printf("BAD\n"); 198 break; 199 default: 200 printf("Error\n"); 201 break; 202 } 203} 204 205 206static void 207usage() 208{ 209 fprintf(stderr,"usage: wlconfig ifname [param value ...]\n"); 210 exit(1); 211} 212 213 214void 215get_cache(int sd, struct ifreq *ifr) 216{ 217 /* get the cache count */ 218 if (ioctl(sd, SIOCGWLCITEM, (caddr_t)ifr)) 219 err(1, "SIOCGWLCITEM - get cache count"); 220 w_sigitems = (int) ifr->ifr_data; 221 222 ifr->ifr_data = (caddr_t) &wsc; 223 /* get the cache */ 224 if (ioctl(sd, SIOCGWLCACHE, (caddr_t)ifr)) 225 err(1, "SIOCGWLCACHE - get cache count"); 226} 227 228static int 229scale_value(int value, int max) 230{ 231 double dmax = (double) max; 232 if (value > max) 233 return(100); 234 return((value/dmax) * 100); 235} 236 237static void 238dump_cache(int rawFlag) 239{ 240 int i; 241 int signal, silence, quality; 242 243 if (rawFlag) 244 printf("signal range 0..63: silence 0..63: quality 0..15\n"); 245 else 246 printf("signal range 0..100: silence 0..100: quality 0..100\n"); 247 248 /* after you read it, loop through structure,i.e. wsc 249 * print each item: 250 */ 251 for(i = 0; i < w_sigitems; i++) { 252 printf("[%d:%d]>\n", i+1, w_sigitems); 253 printf("\tip: %d.%d.%d.%d,",((wsc[i].ipsrc >> 0) & 0xff), 254 ((wsc[i].ipsrc >> 8) & 0xff), 255 ((wsc[i].ipsrc >> 16) & 0xff), 256 ((wsc[i].ipsrc >> 24) & 0xff)); 257 printf(" mac: %02x:%02x:%02x:%02x:%02x:%02x\n", 258 wsc[i].macsrc[0]&0xff, 259 wsc[i].macsrc[1]&0xff, 260 wsc[i].macsrc[2]&0xff, 261 wsc[i].macsrc[3]&0xff, 262 wsc[i].macsrc[4]&0xff, 263 wsc[i].macsrc[5]&0xff); 264 if (rawFlag) { 265 signal = wsc[i].signal; 266 silence = wsc[i].silence; 267 quality = wsc[i].quality; 268 } 269 else { 270 signal = scale_value(wsc[i].signal, 63); 271 silence = scale_value(wsc[i].silence, 63); 272 quality = scale_value(wsc[i].quality, 15); 273 } 274 printf("\tsignal: %d, silence: %d, quality: %d, ", 275 signal, 276 silence, 277 quality); 278 printf("snr: %d\n", signal - silence); 279 } 280} 281 282#define raw_cache() dump_cache(1) 283#define scale_cache() dump_cache(0) 284 285int 286main(int argc, char *argv[]) 287{ 288 int sd; 289 struct ifreq ifr; 290 u_char psabuf[0x40]; 291 int val, argind, i; 292 char *cp, *param, *value; 293 struct ether_addr *ea; 294 int work = 0; 295 int currnwid; 296 297 if ((argc < 2) || (argc % 2)) 298 usage(); 299 300 /* get a socket */ 301 sd = socket(AF_INET, SOCK_DGRAM, 0); 302 if (sd < 0) 303 err(1,"socket"); 304 strncpy(ifr.ifr_name, argv[1], sizeof(ifr.ifr_name)); 305 ifr.ifr_addr.sa_family = AF_INET; 306 307 /* get the PSA */ 308 ifr.ifr_data = (caddr_t)psabuf; 309 if (ioctl(sd, SIOCGWLPSA, (caddr_t)&ifr)) 310 err(1,"get PSA"); 311 312 /* get the current NWID */ 313 if (ioctl(sd, SIOCGWLCNWID, (caddr_t)&ifr)) 314 err(1,"get NWID"); 315 currnwid = (int)ifr.ifr_data; 316 317 /* just dump and exit? */ 318 if (argc == 2) { 319 print_psa(psabuf, currnwid); 320 exit(0); 321 } 322 323 /* loop reading arg pairs */ 324 for (argind = 2; argind < argc; argind += 2) { 325 326 param = argv[argind]; 327 value = argv[argind+1]; 328 329 /* What to do? */ 330 331 if (!strcasecmp(param,"currnwid")) { /* set current NWID */ 332 val = strtol(value,&cp,0); 333 if ((val < 0) || (val > 0xffff) || (cp == value)) 334 errx(1,"bad NWID '%s'",value); 335 336 ifr.ifr_data = (caddr_t)val; 337 if (ioctl(sd, SIOCSWLCNWID, (caddr_t)&ifr)) 338 err(1,"set NWID (interface not up?)"); 339 continue ; 340 } 341 342 if (!strcasecmp(param,"irq")) { 343 val = strtol(value,&cp,0); 344 val = irqvals[val]; 345 if ((val == 0) || (cp == value)) 346 errx(1,"bad IRQ '%s'",value); 347 psabuf[WLPSA_IRQNO] = (u_char)val; 348 work = 1; 349 continue; 350 } 351 352 if (!strcasecmp(param,"mac")) { 353 if ((ea = ether_aton(value)) == NULL) 354 errx(1,"bad ethernet address '%s'",value); 355 for (i = 0; i < 6; i++) 356 psabuf[WLPSA_LOCALMAC + i] = ea->octet[i]; 357 work = 1; 358 continue; 359 } 360 361 if (!strcasecmp(param,"macsel")) { 362 if (!strcasecmp(value,"local")) { 363 psabuf[WLPSA_MACSEL] |= 0x1; 364 work = 1; 365 continue; 366 } 367 if (!strcasecmp(value,"universal")) { 368 psabuf[WLPSA_MACSEL] &= ~0x1; 369 work = 1; 370 continue; 371 } 372 errx(1,"bad macsel value '%s'",value); 373 } 374 375 if (!strcasecmp(param,"nwid")) { 376 val = strtol(value,&cp,0); 377 if ((val < 0) || (val > 0xffff) || (cp == value)) 378 errx(1,"bad NWID '%s'",value); 379 psabuf[WLPSA_NWID] = (val >> 8) & 0xff; 380 psabuf[WLPSA_NWID+1] = val & 0xff; 381 work = 1; 382 continue; 383 } 384 if (!strcasecmp(param,"cache")) { 385 386 /* raw cache dump 387 */ 388 if (!strcasecmp(value,"raw")) { 389 get_cache(sd, &ifr); 390 raw_cache(); 391 continue; 392 } 393 /* scaled cache dump 394 */ 395 else if (!strcasecmp(value,"scale")) { 396 get_cache(sd, &ifr); 397 scale_cache(); 398 continue; 399 } 400 /* zero out cache 401 */ 402 else if (!strcasecmp(value,"zero")) { 403 if (ioctl(sd, SIOCDWLCACHE, (caddr_t)&ifr)) 404 err(1,"zero cache"); 405 continue; 406 } 407 errx(1,"unknown value '%s'", value); 408 } 409 errx(1,"unknown parameter '%s'",param); 410 } 411 if (work) { 412 ifr.ifr_data = (caddr_t)psabuf; 413 if (ioctl(sd, SIOCSWLPSA, (caddr_t)&ifr)) 414 err(1,"set PSA"); 415 } 416 return(0); 417} 418