
/*
 * Copyright (c) 1996 Portland State University 
 * 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.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by Portland State University.
 * 4. The name of Portland State University may not be used to endorse 
 *    or promote products derived from this software without specific 
 *    prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR/S ``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 THE AUTHOR/S 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.
 */

/*
 * wlconfig.c
 * 
 * utility to read out and change various WAVELAN parameters.
 * Currently it only reads and writes the wavelan NWID.
 *
 * 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, but admins should
 * be careful to call it only after the wl[p] drivers are setup
 * with ifconfig.
 *
 * wlconfig -i <ifname> -r -> read out the current nwid
 * wlconfig -i <ifname> -w <nwid> -> set the nwid
 *
 * The -i parameter is required.
 *
 * Example:
 *	wlconfig -i wlp0 -w 0x0102
 *
 * This will set the nwid to 0x0102 on the wlp0 pcmcia device.
 *
 * syntax for setting nwid:
 *	hex string of two nibbles; e.g., 0x0102
 *
 * 01 will be high byte of nwid.
 * 02 will be low byte of nwid.
 */

#include <sys/param.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <machine/wavelan.h>

#include <net/if.h>
#include <net/if_dl.h>
#include <netinet/in.h>
#include <netinet/in_var.h>
#include <arpa/inet.h>

#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <nlist.h>
#include <kvm.h>
#include <fcntl.h>

void parseArgs(int argc, char **argv);

int readonly = 1;	/* default action is to read nwid */ 
int nwid = 0;
char ifname[1024]; 

main(int argc, char **argv)
{
	int sd;
	struct	ifreq		ifr; 

	if (getuid()) {
		fprintf(stderr,"wlconfig - root only\n");
		exit(1);
	}

	parseArgs(argc, argv);

	sd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sd < 0) {
		perror("wlconfig: socket");
		exit(1);
	}
	strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
	ifr.ifr_addr.sa_family = AF_INET;
	if (readonly) {
		if (ioctl(sd, SIOCGWLNWID, (caddr_t)&ifr) < 0) {
			perror("ioctl SIOCGWLNWID ");
		    	exit(1);
	    	}
	    	printf("%s: nwid == 0x%x\n", ifname, (int) ifr.ifr_data);
	}
	else {
		ifr.ifr_data = (caddr_t) nwid;
		if (ioctl(sd, SIOCSWLNWID, (caddr_t)&ifr) < 0) {
			perror("ioctl SIOCSWLNWID ");
		    	exit(1);
	    	}
	    	printf("%s: nwid set to == 0x%x\n", ifname, (int) ifr.ifr_data);
	}
	close(sd);
	exit(0);
}

syntax()
{
	printf("wlconfig -i <ifname> -r: reads out nwid\n");
	printf("wlconfig -i <ifname> -w <nwid>: sets new nwid\n");
	printf("\twlconfig -i wlp0 -w 0x0102: example for setting nwid\n");
	exit(1);
}

void
parseArgs(int argc, char **argv)
{
	extern int      errno;
	extern char    *optarg;
	extern int      optind;
	int             ch, fd;
	int 		rc;
	int 		iflag = 0;

	while ((ch = getopt(argc, argv, "i:rw:")) != EOF) {
		switch (ch) {
		case 'r':
			readonly = 1;
			break;
		case 'w':
			readonly = 0;
			sscanf(optarg, "%x", &nwid);
			break;
		case 'i':
			strncpy(ifname, optarg, 1024);
			iflag = 1;
			break;
		case '?':
		default:
			syntax();
		}
	}
	if (!iflag) {
		syntax();
	}
}

