MFC r1.6 r1.30 r1.28 (HEAD):
[dragonfly.git] / usr.sbin / wlconfig / wlconfig.c
blobc3ed3660b420cca6e026fdd8efa3bc184156bf67
1 /*
2 * Copyright (C) 1996
3 * Michael Smith. All rights reserved.
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.
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.
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 $
31 * wlconfig.c
33 * utility to read out and change various WAVELAN parameters.
34 * Currently supports NWID and IRQ values.
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.
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.
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.
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>
67 #include <net/if.h>
68 #include <netinet/in.h>
69 #include <netinet/if_ether.h>
71 #include <err.h>
72 #include <stdio.h>
73 #include <stdlib.h>
74 #include <string.h>
75 #include <unistd.h>
76 #include <limits.h>
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
84 /* cache */
85 static int w_sigitems; /* count of valid items */
86 static struct w_sigcache wsc[MAXCACHEITEMS];
88 int
89 wlirq(int irqval)
91 int irq;
93 for(irq = 0; irq < 16; irq++)
94 if(irqvals[irq] == irqval)
95 return(irq);
96 return 0;
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"
107 char *subband[] = {
108 "915MHz/see WaveModem",
109 "2425MHz",
110 "2460MHz",
111 "2484MHz",
112 "2430.5MHz"
117 ** print_psa
119 ** Given a pointer to a PSA structure, print it out
121 void
122 print_psa(u_char *psa, int currnwid)
124 int nwid;
127 ** Work out what sort of board we have
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]));
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");
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);
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]);
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;
204 static void
205 usage(void)
207 fprintf(stderr,"usage: wlconfig ifname [param value ...]\n");
208 exit(1);
212 void
213 get_cache(int sd, struct ifreq *ifr)
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;
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");
226 static int
227 scale_value(int value, int max)
229 double dmax = (double) max;
230 if (value > max)
231 return(100);
232 return((value/dmax) * 100);
235 static void
236 dump_cache(int rawFlag)
238 int i;
239 int signal, silence, quality;
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");
246 /* after you read it, loop through structure,i.e. wsc
247 * print each item:
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;
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);
272 printf("\tsignal: %d, silence: %d, quality: %d, ",
273 signal,
274 silence,
275 quality);
276 printf("snr: %d\n", signal - silence);
280 #define raw_cache() dump_cache(1)
281 #define scale_cache() dump_cache(0)
284 main(int argc, char *argv[])
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;
295 if ((argc < 2) || (argc % 2))
296 usage();
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;
305 /* get the PSA */
306 ifr.ifr_data = (caddr_t)psabuf;
307 if (ioctl(sd, SIOCGWLPSA, (caddr_t)&ifr))
308 err(1,"get PSA");
310 /* get the current NWID */
311 if (ioctl(sd, SIOCGWLCNWID, (caddr_t)&ifr))
312 err(1,"get NWID");
313 currnwid = (int)ifr.ifr_data;
315 /* just dump and exit? */
316 if (argc == 2) {
317 print_psa(psabuf, currnwid);
318 exit(0);
321 /* loop reading arg pairs */
322 for (argind = 2; argind < argc; argind += 2) {
324 param = argv[argind];
325 value = argv[argind+1];
327 /* What to do? */
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);
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 ;
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;
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;
359 if (!strcasecmp(param,"macsel")) {
360 if (!strcasecmp(value,"local")) {
361 psabuf[WLPSA_MACSEL] |= 0x1;
362 work = 1;
363 continue;
365 if (!strcasecmp(value,"universal")) {
366 psabuf[WLPSA_MACSEL] &= ~0x1;
367 work = 1;
368 continue;
370 errx(1,"bad macsel value '%s'",value);
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;
382 if (!strcasecmp(param,"cache")) {
384 /* raw cache dump
386 if (!strcasecmp(value,"raw")) {
387 get_cache(sd, &ifr);
388 raw_cache();
389 continue;
391 /* scaled cache dump
393 else if (!strcasecmp(value,"scale")) {
394 get_cache(sd, &ifr);
395 scale_cache();
396 continue;
398 /* zero out cache
400 else if (!strcasecmp(value,"zero")) {
401 if (ioctl(sd, SIOCDWLCACHE, (caddr_t)&ifr))
402 err(1,"zero cache");
403 continue;
405 errx(1,"unknown value '%s'", value);
407 errx(1,"unknown parameter '%s'",param);
409 if (work) {
410 ifr.ifr_data = (caddr_t)psabuf;
411 if (ioctl(sd, SIOCSWLPSA, (caddr_t)&ifr))
412 err(1,"set PSA");
414 return(0);