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