freebsd-dev/usr.sbin/wlconfig/wlconfig.c
Mike Smith 8445169b4c Make it build under 3.x
Submitted by:	fsmp
1997-05-23 04:04:17 +00:00

328 lines
9.8 KiB
C

/*
* Copyright (C) 1996
* Michael Smith. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY Michael Smith AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Michael Smith OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: wlconfig.c,v 1.1.1.1 1997/05/22 08:58:18 msmith Exp $
*
*/
/*
* wlconfig.c
*
* utility to read out and change various WAVELAN parameters.
* Currently supports NWID and IRQ values.
*
* The NWID is used by 2 or more wavelan controllers to determine
* if packets should be received or not. It is a filter that
* is roughly analogous to the "channel" setting with a garage
* door controller. Two companies side by side with wavelan devices
* that could actually hear each other can use different NWIDs
* and ignore packets. In truth however, the air space is shared,
* and the NWID is a virtual filter.
*
* In the current set of wavelan drivers, ioctls changed only
* the runtime radio modem registers which act in a manner analogous
* to an ethernet transceiver. The ioctls do not change the
* stored nvram PSA (or parameter storage area). At boot, the PSA
* values are stored in the radio modem. Thus when the
* system reboots it will restore the wavelan NWID to the value
* stored in the PSA. The NCR/ATT dos utilities must be used to
* change the initial NWID values in the PSA. The wlconfig utility
* may be used to set a different NWID at runtime; this is only
* permitted while the interface is up and running.
*
* By contrast, the IRQ value can only be changed while the
* Wavelan card is down and unconfigured, and it will remain
* disabled after an IRQ change until reboot.
*
*/
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <machine/if_wl_wavelan.h>
#include <net/if.h>
#include <net/if_var.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
extern struct ether_addr *ether_aton(char *a);
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
/* translate IRQ bit to number */
/* array for maping irq numbers to values for the irq parameter register */
static int irqvals[16] = {
0, 0, 0, 0x01, 0x02, 0x04, 0, 0x08, 0, 0, 0x10, 0x20, 0x40, 0, 0, 0x80
};
int
wlirq(int irqval)
{
int irq;
for(irq = 0; irq < 16; irq++)
if(irqvals[irq] == irqval)
return(irq);
return 0;
}
char *compat_type[] = {
"PC-AT 915MHz",
"PC-MC 915MHz",
"PC-AT 2.4GHz",
"PC-MC 2.4GHz",
"PCCARD or 1/2 size AT, 915MHz or 2.4GHz"
};
char *subband[] = {
"915MHz/see WaveModem",
"2425MHz",
"2460MHz",
"2484MHz",
"2430.5MHz"
};
/*
** print_psa
**
** Given a pointer to a PSA structure, print it out
*/
void
print_psa(u_char *psa, int currnwid)
{
int nwid;
/*
** Work out what sort of board we have
*/
if (psa[0] == 0x14) {
printf("Board type : Microchannel\n");
} else {
if (psa[1] == 0) {
printf("Board type : PCCARD\n");
} else {
printf("Board type : ISA");
if ((psa[4] == 0) &&
(psa[5] == 0) &&
(psa[6] == 0))
printf(" (DEC OEM)");
printf("\n");
printf("Base address options : 0x300, 0x%02x0, 0x%02x0, 0x%02x0\n",
(int)psa[1], (int)psa[2], (int)psa[3]);
printf("Waitstates : %d\n",psa[7] & 0xf);
printf("Bus mode : %s\n",(psa[7] & 0x10) ? "EISA" : "ISA");
printf("IRQ : %d\n",wlirq(psa[8]));
}
}
printf("Default MAC address : %02x:%02x:%02x:%02x:%02x:%02x\n",
psa[0x10],psa[0x11],psa[0x12],psa[0x13],psa[0x14],psa[0x15]);
printf("Soft MAC address : %02x:%02x:%02x:%02x:%02x:%02x\n",
psa[0x16],psa[0x17],psa[0x18],psa[0x19],psa[0x1a],psa[0x1b]);
printf("Current MAC address : %s\n",(psa[0x1c] & 0x1) ? "Soft" : "Default");
printf("Adapter compatability : ");
if (psa[0x1d] < 5) {
printf("%s\n",compat_type[psa[0x1d]]);
} else {
printf("unknown\n");
}
printf("Threshold preset : %d\n",psa[0x1e]);
printf("Call code required : %s\n",(psa[0x1f] & 0x1) ? "YES" : "NO");
if (psa[0x1f] & 0x1)
printf("Call code : 0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
psa[0x30],psa[0x31],psa[0x32],psa[0x33],psa[0x34],psa[0x35],psa[0x36],psa[0x37]);
printf("Subband : %s\n",subband[psa[0x20] & 0xf]);
printf("Quality threshold : %d\n",psa[0x21]);
printf("Hardware version : %d (%s)\n",psa[0x22],psa[0x22] ? "Rel3" : "Rel1/Rel2");
printf("Network ID enable : %s\n",(psa[0x25] & 0x1) ? "YES" : "NO");
if (psa[0x25] & 0x1) {
nwid = (psa[0x23] << 8) + psa[0x24];
printf("NWID : 0x%04x\n",nwid);
if (nwid != currnwid) {
printf("Current NWID : 0x%04x\n",currnwid);
}
}
printf("Datalink security : %s\n",(psa[0x26] & 0x1) ? "YES" : "NO");
if (psa[0x26] & 0x1) {
printf("Encryption key : ");
if (psa[0x27] == 0) {
printf("DENIED\n");
} else {
printf("0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
psa[0x27],psa[0x28],psa[0x29],psa[0x2a],psa[0x2b],psa[0x2c],psa[0x2d],psa[0x2e]);
}
}
printf("Databus width : %d (%s)\n",
(psa[0x2f] & 0x1) ? 16 : 8, (psa[0x2f] & 0x80) ? "fixed" : "variable");
printf("Configuration state : %sconfigured\n",(psa[0x38] & 0x1) ? "" : "un");
printf("CRC-16 : 0x%02x%02x\n",psa[0x3e],psa[0x3d]);
printf("CRC status : ");
switch(psa[0x3f]) {
case 0xaa:
printf("OK\n");
break;
case 0x55:
printf("BAD\n");
break;
default:
printf("Error\n");
break;
}
}
void
syntax(char *pname)
{
fprintf(stderr,"Usage: %s <ifname> [<param> <value> ...]\n",pname);
fprintf(stderr," <ifname> Wavelan interface name.\n");
fprintf(stderr," <param> Parameter name (see below)\n");
fprintf(stderr," <value> New value for parameter.\n");
fprintf(stderr," Parameter name: Value:\n");
fprintf(stderr," irq 3,4,5,6,10,11,12,15\n");
fprintf(stderr," mac soft ethernet address\n");
fprintf(stderr," macsel soft or default\n");
fprintf(stderr," nwid default NWID (0x0-0xffff)\n");
fprintf(stderr," currnwid current NWID (0x0-0xffff) or 'get'\n");
exit(1);
}
void
main(int argc, char *argv[])
{
int sd;
struct ifreq ifr;
u_char psabuf[0x40];
int val, argind, i;
char *cp, *param, *value;
struct ether_addr *ea;
int work = 0;
int currnwid;
if ((argc < 2) || (argc % 2))
syntax(argv[0]);
/* get a socket */
sd = socket(AF_INET, SOCK_DGRAM, 0);
if (sd < 0)
err(1,"socket");
strncpy(ifr.ifr_name, argv[1], sizeof(ifr.ifr_name));
ifr.ifr_addr.sa_family = AF_INET;
/* get the PSA */
ifr.ifr_data = (caddr_t)psabuf;
if (ioctl(sd, SIOCGWLPSA, (caddr_t)&ifr))
err(1,"Get PSA");
/* get the current NWID */
if (ioctl(sd, SIOCGWLCNWID, (caddr_t)&ifr))
err(1,"Get NWID");
currnwid = (int)ifr.ifr_data;
/* just dump and exit? */
if (argc == 2) {
print_psa(psabuf, currnwid);
exit(0);
}
/* loop reading arg pairs */
for (argind = 2; argind < argc; argind += 2) {
param = argv[argind];
value = argv[argind+1];
/* What to do? */
if (!strcasecmp(param,"currnwid")) { /* set current NWID */
val = strtol(value,&cp,0);
if ((val < 0) || (val > 0xffff) || (cp == value))
errx(1,"Bad NWID '%s'",value);
ifr.ifr_data = (caddr_t)val;
if (ioctl(sd, SIOCSWLCNWID, (caddr_t)&ifr))
err(1,"Set NWID (interface not up?)");
continue ;
}
if (!strcasecmp(param,"irq")) {
val = strtol(value,&cp,0);
val = irqvals[val];
if ((val == 0) || (cp == value))
errx(1,"Bad IRQ '%s'",value);
psabuf[WLPSA_IRQNO] = (u_char)val;
work = 1;
continue;
}
if (!strcasecmp(param,"mac")) {
if ((ea = ether_aton(value)) == NULL)
errx(1,"Bad ethernet address '%s'",value);
for (i = 0; i < 6; i++)
psabuf[WLPSA_LOCALMAC + i] = ea->octet[i];
work = 1;
continue;
}
if (!strcasecmp(param,"macsel")) {
if (!strcasecmp(value,"local")) {
psabuf[WLPSA_MACSEL] |= 0x1;
work = 1;
continue;
}
if (!strcasecmp(value,"universal")) {
psabuf[WLPSA_MACSEL] &= ~0x1;
work = 1;
continue;
}
errx(1,"Bad macsel value '%s'",value);
}
if (!strcasecmp(param,"nwid")) {
val = strtol(value,&cp,0);
if ((val < 0) || (val > 0xffff) || (cp == value))
errx(1,"Bad NWID '%s'",value);
psabuf[WLPSA_NWID] = (val >> 8) & 0xff;
psabuf[WLPSA_NWID+1] = val & 0xff;
work = 1;
continue;
}
errx(1,"Unknown parameter '%s'",param);
}
if (work) {
ifr.ifr_data = (caddr_t)psabuf;
if (ioctl(sd, SIOCSWLPSA, (caddr_t)&ifr))
err(1,"Set PSA");
}
}