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