--- /dev/null
+.\" Jean II - HPLB - 96
+.\" iwconfig.8
+.\"
+.TH IWCONFIG 8 "31 October 1996" "net-tools" "Linux Programmer's Manual"
+.\"
+.\" NAME part
+.\"
+.SH NAME
+iwconfig \- configure a wireless network interface
+.\"
+.\" SYNOPSIS part
+.\"
+.SH SYNOPSIS
+.BI "iwconfig [" interface ]
+.br
+.BI "iwconfig " interface " [nwid " N "] [freq " F ]
+.\"
+.\" DESCRIPTION part
+.\"
+.SH DESCRIPTION
+.B Iwconfig
+is similar to
+.IR ifconfig (8),
+but is dedicated to the wireless interfaces. It is used to set the
+parameters of the network interface which are specific to the wireless
+operation (for example : the frequency).
+.B Iwconfig
+may also be used to display those parameters, and the wireless
+statistics (extracted from
+.IR /proc/net/wireless ).
+.PP
+All these parameters and statistics are device dependant. Each driver
+will provide only some of them depending on the hardware support, and
+the range of value may change. Please refer to the man page of each
+device for details.
+.\"
+.\" PARAMETER part
+.\"
+.SH PARAMETERS
+.TP
+.B nwid
+Set the Network ID (in some products it is also called Domain). As all
+adjacent wireless networks share the same medium, this number is used
+to differenciate them (create virtual networks).
+.TP
+.BR freq / channel
+Set the operating frequency or channel in the device. Value below 1000
+are the channel number, value over this is the frequency in Hz. You
+may prepend the suffix k, M or G to the value (for example, "2.46G"
+for 2.46 GHz frequency).
+.\"
+.\" DISPLAY part
+.\"
+.SH DISPLAY
+For each device which support wireless extensions,
+.I iwconfig
+will display the name of the
+.B MAC protocol
+used (name of device for proprietary protocols), the
+.B NWID
+and the
+.B frequency
+(if available).
+.PP
+If
+.I /proc/net/wireless
+exists,
+.I iwconfig
+will also display its content :
+.TP
+.B Link quality
+Quality of the link or the modulation (how good the received signal is).
+.TP
+.B Signal level
+Received signal strength (how strong the received signal is).
+.TP
+.B Noise level
+Background noise level (when no packet is transmited).
+.TP
+.B invalid nwid
+Number of packets received with a different NWID. Used to detect
+configuration problems or adjacent network existence.
+.TP
+.B invalid crypt
+Number of packets that the hardware was unable to decrypt.
+.TP
+.B invalid misc
+Other packets lost in relation with specific wireless operations.
+.\"
+.\" AUTHOR part
+.\"
+.SH AUTHOR
+Jean Tourrilhes \- jt@hplb.hpl.hp.com
+.\"
+.\" FILES part
+.\"
+.SH FILES
+.I /proc/net/wireless
+.\"
+.\" SEE ALSO part
+.\"
+.SH SEE ALSO
+.BR ifconfig (8),
+.BR iwspy (8),
+.BR iwpriv (8),
+.BR wavelan (4),
+.BR wavelan_cs (4),
+.BR xircnw_cs (4).
--- /dev/null
+/*
+ * Hack my way... Jean II
+ */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <linux/netdevice.h>
+#include <linux/if.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/ipx.h>
+#include <linux/wireless.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/* Some usefull constants */
+#define KILO 1e3
+#define MEGA 1e6
+#define GIGA 1e9
+
+typedef struct iw_statistics iwstats;
+typedef struct iw_range iwrange;
+
+/* Structure for storing all wireless information for each device */
+struct wireless_info
+{
+ char dev[IFNAMSIZ]; /* Interface name (device) */
+ char name[12]; /* Wireless name */
+ int has_nwid;
+ int nwid_on;
+ u_long nwid; /* Network ID */
+ int has_freq;
+ u_long freq; /* Frequency/channel */
+
+ /* Stats */
+ iwstats stats;
+ int has_stats;
+ iwrange range;
+ int has_range;
+};
+
+int skfd = -1; /* generic raw socket desc. */
+int ipx_sock = -1; /* IPX socket */
+int ax25_sock = -1; /* AX.25 socket */
+int inet_sock = -1; /* INET socket */
+int ddp_sock = -1; /* Appletalk DDP socket */
+
+
+static void
+usage(void)
+{
+ fprintf(stderr, "Usage: iwconfig interface\n");
+ fprintf(stderr, " [nwid NN]\n");
+ fprintf(stderr, " [freq N.NN (add k, M or G) ]\n");
+ fprintf(stderr, " [channel N]\n");
+ exit(1);
+}
+
+
+static void
+print_info(struct wireless_info * info)
+{
+ /* Display device name */
+ printf("%-8.8s ", info->dev);
+
+ /* Display wireless name */
+ printf("%s ", info->name);
+
+ /* Display Network ID */
+ if(info->has_nwid)
+ if(info->nwid_on)
+ printf("NWID:%lX ", info->nwid);
+ else
+ printf("NWID:off ");
+
+ /* Display frequency / channel */
+ if(info->has_freq)
+ if(info->freq < KILO)
+ printf("Channel:%g ", (double) info->freq);
+ else
+ if(info->freq > GIGA)
+ printf("Frequency:%gGHz ", info->freq / GIGA);
+ else
+ if(info->freq > MEGA)
+ printf("Frequency:%gMHz ", info->freq / MEGA);
+ else
+ printf("Frequency:%gkHz ", info->freq / KILO);
+
+ printf("\n");
+
+ if(info->has_stats)
+ {
+ if(info->has_range)
+ printf(" Link quality:%d/%d Signal level:%d/%d Noise level:%d/%d\n",
+ info->stats.qual.qual, info->range.max_qual.qual,
+ info->stats.qual.level, info->range.max_qual.level,
+ info->stats.qual.noise, info->range.max_qual.noise);
+ else
+ printf(" Link quality:%d Signal level:%d Noise level:%d\n",
+ info->stats.qual.qual,
+ info->stats.qual.level,
+ info->stats.qual.noise);
+
+ printf(" Rx invalid nwid:%d invalid crypt:%d invalid misc:%d\n",
+ info->stats.discard.nwid,
+ info->stats.discard.crypt,
+ info->stats.discard.misc);
+ }
+
+ printf("\n");
+}
+
+static int if_getstats(char *ifname, iwstats * stats)
+{
+ FILE *f=fopen("/proc/net/wireless","r");
+ char buf[256];
+ char *bp;
+ if(f==NULL)
+ return -1;
+ while(fgets(buf,255,f))
+ {
+ bp=buf;
+ while(*bp&&isspace(*bp))
+ bp++;
+ if(strncmp(bp,ifname,strlen(ifname))==0 && bp[strlen(ifname)]==':')
+ {
+ bp=strchr(bp,':');
+ bp++;
+ bp = strtok(bp, " .");
+ sscanf(bp, "%X", &stats->status);
+ bp = strtok(NULL, " .");
+ sscanf(bp, "%d", &stats->qual.qual);
+ bp = strtok(NULL, " .");
+ sscanf(bp, "%d", &stats->qual.level);
+ bp = strtok(NULL, " .");
+ sscanf(bp, "%d", &stats->qual.noise);
+ bp = strtok(NULL, " .");
+ sscanf(bp, "%d", &stats->discard.nwid);
+ bp = strtok(NULL, " .");
+ sscanf(bp, "%d", &stats->discard.crypt);
+ bp = strtok(NULL, " .");
+ sscanf(bp, "%d", &stats->discard.misc);
+ fclose(f);
+ return;
+ }
+ }
+ fclose(f);
+ return 0;
+}
+
+/* Get wireless informations & config from the device driver */
+static int
+get_info(char * ifname,
+ struct wireless_info * info)
+{
+ struct iwreq wrq;
+
+ memset((char *) info, 0, sizeof(struct wireless_info));
+
+ /* Get device name */
+ strcpy(info->dev, ifname);
+
+ /* Get wireless name */
+ strcpy(wrq.ifr_name, ifname);
+ if(ioctl(skfd, SIOCGIWNAME, &wrq) < 0)
+ /* If no wireless name : no wireless extensions */
+ return(-1);
+ else
+ strcpy(info->name, wrq.u.name);
+
+ /* Get network ID */
+ strcpy(wrq.ifr_name, ifname);
+ if(ioctl(skfd, SIOCGIWNWID, &wrq) >= 0)
+ {
+ info->has_nwid = 1;
+ info->nwid_on = wrq.u.nwid.on;
+ info->nwid = wrq.u.nwid.nwid;
+ }
+
+ /* Get frequency / channel */
+ strcpy(wrq.ifr_name, ifname);
+ if(ioctl(skfd, SIOCGIWFREQ, &wrq) >= 0)
+ {
+ info->has_freq = 1;
+ info->freq = wrq.u.freq;
+ }
+
+ /* Get stats */
+ if(if_getstats(ifname, &(info->stats)) == 0)
+ {
+ info->has_stats = 1;
+ }
+
+ /* Get ranges */
+ strcpy(wrq.ifr_name, ifname);
+ wrq.u.data.pointer = (caddr_t) &(info->range);
+ wrq.u.data.length = 0;
+ wrq.u.data.flags = 0;
+ if(ioctl(skfd, SIOCGIWRANGE, &wrq) >= 0)
+ {
+ info->has_range = 1;
+ }
+
+ return(0);
+}
+
+
+static int
+set_info(char * args[], /* Command line args */
+ int count, /* Args count */
+ char * ifname) /* Dev name */
+{
+ struct iwreq wrq;
+ int i;
+
+ /* Set dev name */
+ strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
+
+ /* The other args on the line specify options to be set... */
+ for(i = 0; i < count; i++)
+ {
+ /* Set network ID */
+ if(!strcmp(args[i], "nwid"))
+ {
+ if(++i >= count)
+ usage();
+ if(!strcasecmp(args[i], "off"))
+ wrq.u.nwid.on = 0;
+ else
+ if(sscanf(args[i], "%lX", &(wrq.u.nwid.nwid)) != 1)
+ usage();
+ else
+ wrq.u.nwid.on = 1;
+
+ if(ioctl(skfd, SIOCSIWNWID, &wrq) < 0)
+ {
+ fprintf(stderr, "SIOCSIWNWID: %s\n", strerror(errno));
+ return(-1);
+ }
+ continue;
+ }
+
+ /* Set frequency / channel */
+ if((!strncmp(args[i], "freq", 4)) ||
+ (!strcmp(args[i], "channel")))
+ {
+ if(++i >= count)
+ {
+ struct iw_range range;
+ int k;
+
+ wrq.u.data.pointer = (caddr_t) ⦥
+ wrq.u.data.length = 0;
+ wrq.u.data.flags = 0;
+ if(ioctl(skfd, SIOCGIWRANGE, &wrq) < 0)
+ {
+ fprintf(stderr, "SIOCGIWRANGE: %s\n", strerror(errno));
+ return(-1);
+ }
+
+ printf("%d channels ; available frequencies :",
+ range.num_channels);
+ for(k = 0; k < range.num_frequency; k++)
+ if(range.freq[k] > GIGA)
+ printf(" %gGHz ", range.freq[k] / GIGA);
+ else
+ if(range.freq[k] > MEGA)
+ printf(" %gMHz ", range.freq[k] / MEGA);
+ else
+ printf(" %gkHz ", range.freq[k] / KILO);
+ printf("\n");
+ return; /* no more arg */
+ }
+
+ if(sscanf(args[i], "%g", &(wrq.u.freq)) != 1)
+ usage();
+ if(index(args[i], 'G')) wrq.u.freq *= GIGA;
+ if(index(args[i], 'M')) wrq.u.freq *= MEGA;
+ if(index(args[i], 'k')) wrq.u.freq *= KILO;
+
+ if(ioctl(skfd, SIOCSIWFREQ, &wrq) < 0)
+ {
+ fprintf(stderr, "SIOCSIWFREQ: %s\n", strerror(errno));
+ return(-1);
+ }
+ continue;
+ }
+
+ /* Here we have an unrecognised arg... */
+ fprintf(stderr, "Invalid argument : %s\n", args[i]);
+ usage();
+ return(-1);
+ } /* for(index ... */
+ return(0);
+}
+
+static void
+print_devices(char *ifname)
+{
+ char buff[1024];
+ struct wireless_info info;
+ struct ifconf ifc;
+ struct ifreq *ifr;
+ int i;
+
+ if(ifname == (char *)NULL)
+ {
+ ifc.ifc_len = sizeof(buff);
+ ifc.ifc_buf = buff;
+ if(ioctl(skfd, SIOCGIFCONF, &ifc) < 0)
+ {
+ fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno));
+ return;
+ }
+
+ ifr = ifc.ifc_req;
+ for(i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++)
+ {
+ if(get_info(ifr->ifr_name, &info) < 0)
+ {
+ /* Could skip this message ? */
+ fprintf(stderr, "%-8.8s no wireless extensions.\n\n",
+ ifr->ifr_name);
+ continue;
+ }
+
+ print_info(&info);
+ }
+ }
+ else
+ {
+ if(get_info(ifname, &info) < 0)
+ {
+ fprintf(stderr, "%s: no wireless extensions.\n",
+ ifname);
+ usage();
+ }
+ else
+ print_info(&info);
+ }
+}
+
+
+static int sockets_open()
+{
+ inet_sock=socket(AF_INET, SOCK_DGRAM, 0);
+ ipx_sock=socket(AF_IPX, SOCK_DGRAM, 0);
+ ax25_sock=socket(AF_AX25, SOCK_DGRAM, 0);
+ ddp_sock=socket(AF_APPLETALK, SOCK_DGRAM, 0);
+ /*
+ * Now pick any (exisiting) useful socket family for generic queries
+ */
+ if(inet_sock!=-1)
+ return inet_sock;
+ if(ipx_sock!=-1)
+ return ipx_sock;
+ if(ax25_sock!=-1)
+ return ax25_sock;
+ /*
+ * If this is -1 we have no known network layers and its time to jump.
+ */
+
+ return ddp_sock;
+}
+
+int
+main(int argc,
+ char ** argv)
+{
+ int goterr = 0;
+
+ /* Create a channel to the NET kernel. */
+ if((skfd = sockets_open()) < 0)
+ {
+ perror("socket");
+ exit(-1);
+ }
+
+ /* No argument : show the list of all device + info */
+ if(argc == 1)
+ {
+ print_devices((char *)NULL);
+ close(skfd);
+ exit(0);
+ }
+
+ /* The device name must be the first argument */
+ if(argc == 2)
+ {
+ print_devices(argv[1]);
+ close(skfd);
+ exit(0);
+ }
+
+ /* The other args on the line specify options to be set... */
+ goterr = set_info(argv + 2, argc - 2, argv[1]);
+
+ /* Close the socket. */
+ close(skfd);
+
+ return(goterr);
+}
--- /dev/null
+/*
+ * Warning : this program need wireless extensions...
+ */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <linux/netdevice.h>
+#include <linux/if.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/ipx.h>
+#include <linux/wireless.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+int skfd = -1; /* generic raw socket desc. */
+int ipx_sock = -1; /* IPX socket */
+int ax25_sock = -1; /* AX.25 socket */
+int inet_sock = -1; /* INET socket */
+int ddp_sock = -1; /* Appletalk DDP socket */
+
+static int sockets_open()
+{
+ inet_sock=socket(AF_INET, SOCK_DGRAM, 0);
+ ipx_sock=socket(AF_IPX, SOCK_DGRAM, 0);
+ ax25_sock=socket(AF_AX25, SOCK_DGRAM, 0);
+ ddp_sock=socket(AF_APPLETALK, SOCK_DGRAM, 0);
+ /*
+ * Now pick any (exisiting) useful socket family for generic queries
+ */
+ if(inet_sock!=-1)
+ return inet_sock;
+ if(ipx_sock!=-1)
+ return ipx_sock;
+ if(ax25_sock!=-1)
+ return ax25_sock;
+ /*
+ * If this is -1 we have no known network layers and its time to jump.
+ */
+
+ return ddp_sock;
+}
+
+int
+byte_size(args)
+{
+ int ret = args & IW_PRIV_SIZE_MASK;
+
+ if(((args & IW_PRIV_TYPE_MASK) == IW_PRIV_TYPE_INT) ||
+ ((args & IW_PRIV_TYPE_MASK) == IW_PRIV_TYPE_FLOAT))
+ ret <<= 2;
+
+ if((args & IW_PRIV_TYPE_MASK) == IW_PRIV_TYPE_NONE)
+ return 0;
+
+ return ret;
+}
+
+int
+main(int argc,
+ char ** argv)
+{
+ struct iwreq wrq;
+ char * ifname = argv[1];
+ struct iw_priv_args priv[16];
+ int k;
+
+ if(argc < 2)
+ exit(0);
+
+ /* Create a channel to the NET kernel. */
+ if((skfd = sockets_open()) < 0)
+ {
+ perror("socket");
+ exit(-1);
+ }
+
+ strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
+ wrq.u.data.pointer = (caddr_t) priv;
+ wrq.u.data.length = 0;
+ wrq.u.data.flags = 0;
+ if(ioctl(skfd, SIOCGIWPRIV, &wrq) < 0)
+ {
+ fprintf(stderr, "Interface doesn't provide private interface info...\n");
+ fprintf(stderr, "SIOCGIWPRIV: %s\n", strerror(errno));
+ return(-1);
+ }
+
+ /* If no args... */
+ if(argc < 3)
+ {
+ char * argtype[] = { " ", "byte", "char", "", "int", "float" };
+
+ printf("Available private ioctl :\n");
+ for(k = 0; k < wrq.u.data.length; k++)
+ printf("%s (%lX) : set %3d %s & get %3d %s\n",
+ priv[k].name, priv[k].cmd,
+ priv[k].set_args & IW_PRIV_SIZE_MASK,
+ argtype[(priv[k].set_args & IW_PRIV_TYPE_MASK) >> 12],
+ priv[k].get_args & IW_PRIV_SIZE_MASK,
+ argtype[(priv[k].get_args & IW_PRIV_TYPE_MASK) >> 12]);
+ }
+ else
+ {
+ u_char buffer[1024];
+
+ /* Seach the correct ioctl */
+ k = -1;
+ while((++k < wrq.u.data.length) && strcmp(priv[k].name, argv[2]))
+ ;
+ /* If not found... */
+ if(k == wrq.u.data.length)
+ fprintf(stderr, "Invalid argument : %s\n", argv[2]);
+
+ /* If we have to set some data */
+ if((priv[k].set_args & IW_PRIV_TYPE_MASK) &&
+ (priv[k].set_args & IW_PRIV_SIZE_MASK))
+ {
+ int i;
+
+ /* Warning : we may have no args to set... */
+
+ switch(priv[k].set_args & IW_PRIV_TYPE_MASK)
+ {
+ case IW_PRIV_TYPE_BYTE:
+ /* Number of args to fetch */
+ wrq.u.data.length = argc - 3;
+ if(wrq.u.data.length > (priv[k].set_args & IW_PRIV_SIZE_MASK))
+ wrq.u.data.length = priv[k].set_args & IW_PRIV_SIZE_MASK;
+
+ /* Fetch args */
+ for(i = 0; i < wrq.u.data.length; i++)
+ sscanf(argv[i + 3], "%d", buffer + i);
+ break;
+
+ case IW_PRIV_TYPE_INT:
+ /* Number of args to fetch */
+ wrq.u.data.length = argc - 3;
+ if(wrq.u.data.length > (priv[k].set_args & IW_PRIV_SIZE_MASK))
+ wrq.u.data.length = priv[k].set_args & IW_PRIV_SIZE_MASK;
+
+ /* Fetch args */
+ for(i = 0; i < wrq.u.data.length; i++)
+ sscanf(argv[i + 3], "%d", ((u_int *) buffer) + i);
+ break;
+
+ default:
+ fprintf(stderr, "Not yet implemented...\n");
+ return(-1);
+ }
+
+ if((priv[k].set_args & IW_PRIV_SIZE_FIXED) &&
+ (wrq.u.data.length != (priv[k].set_args & IW_PRIV_SIZE_MASK)))
+ {
+ printf("The command %s need exactly %d argument...\n",
+ priv[k].name, priv[k].set_args & IW_PRIV_SIZE_MASK);
+ return(-1);
+ }
+ } /* if args to set */
+ else
+ {
+ wrq.u.data.length = 0L;
+ }
+
+ strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
+
+ if((priv[k].set_args & IW_PRIV_SIZE_FIXED) &&
+ (byte_size(priv[k].set_args) < IFNAMSIZ))
+ memcpy(wrq.u.name, buffer, IFNAMSIZ);
+ else
+ {
+ wrq.u.data.pointer = (caddr_t) buffer;
+ wrq.u.data.flags = 0;
+ }
+
+ if(ioctl(skfd, priv[k].cmd, &wrq) < 0)
+ {
+ fprintf(stderr, "Interface doesn't accept private ioctl...\n");
+ fprintf(stderr, "%X: %s\n", priv[k].cmd, strerror(errno));
+ return(-1);
+ }
+
+ /* If we have to get some data */
+ if((priv[k].get_args & IW_PRIV_TYPE_MASK) &&
+ (priv[k].get_args & IW_PRIV_SIZE_MASK))
+ {
+ int i;
+ int n; /* number of args */
+
+ if((priv[k].get_args & IW_PRIV_SIZE_FIXED) &&
+ (byte_size(priv[k].get_args) < IFNAMSIZ))
+ {
+ memcpy(buffer, wrq.u.name, IFNAMSIZ);
+ n = priv[k].get_args & IW_PRIV_SIZE_MASK;
+ }
+ else
+ n = wrq.u.data.length;
+
+ switch(priv[k].get_args & IW_PRIV_TYPE_MASK)
+ {
+ case IW_PRIV_TYPE_BYTE:
+ /* Display args */
+ for(i = 0; i < n; i++)
+ printf("%d ", buffer[i]);
+ printf("\n");
+ break;
+
+ case IW_PRIV_TYPE_INT:
+ /* Display args */
+ for(i = 0; i < n; i++)
+ printf("%d ", ((u_int *) buffer)[i]);
+ printf("\n");
+ break;
+
+ default:
+ fprintf(stderr, "Not yet implemented...\n");
+ return(-1);
+ }
+
+ } /* if args to set */
+
+ } /* if ioctl list else ioctl exec */
+
+ /* Close the socket. */
+ close(skfd);
+
+ return(1);
+}
--- /dev/null
+.\" Jean II - HPLB - 96
+.\" iwspy.8
+.\"
+.TH IWSPY 8 "31 October 1996" "net-tools" "Linux Programmer's Manual"
+.\"
+.\" NAME part
+.\"
+.SH NAME
+iwspy \- Get wireless statistics from specific nodes
+.\"
+.\" SYNOPSIS part
+.\"
+.SH SYNOPSIS
+.BI "iwspy " interface
+.br
+.BI "iwspy " interface " [+] " IPADDR " | hw " HWADDR " [...]"
+.br
+.BI "iwspy " interface " off"
+.\"
+.\" DESCRIPTION part
+.\"
+.SH DESCRIPTION
+.B Iwspy
+is used to set a list of addresses in a wireless network interface and
+to read back quality of link information for each of those. This
+information is the same as the one available in
+.I /proc/net/wireless
+: quality of the link, signal strength and noise level.
+.PP
+This information is updated each time a new packet is received, so
+each address of the list add some overhead in the driver.
+.\"
+.\" PARAMETER part
+.\"
+.SH PARAMETERS
+You may set any number of addresses up to 8.
+.TP
+.B IPADDR
+Set an IP address. As the hardware work with hardware addresses,
+.B iwspy
+will translate this address through
+.IR ARP .
+In some case, this address might not be in the ARP cache and
+.B iwspy
+will fail. In those case,
+.IR ping (8)
+this address and retry.
+.TP
+.B hw HWADDR
+Set a hardware (MAC) address (this address is not translated & checked
+like the IP one).
+.TP
+.B +
+Add the new set of addresses at the end of the current list instead of
+replacing it. The address list is unique for each device, so each user
+should use this option to avoid conflicts.
+.TP
+.B off
+Remove the current list of addresses and disable the functionality
+.\"
+.\" FILES part
+.\"
+.SH FILES
+.I /proc/net/wireless
+.\"
+.\" SEE ALSO part
+.\"
+.SH SEE ALSO
+.BR iwconfig (8),
+.BR ifconfig (8),
+.BR iwpriv (8).
+
--- /dev/null
+/*
+ * Warning : this program need to be link against libsupport.a
+ * in net-tools-1.2.0
+ * This program need also wireless extensions...
+ */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <linux/netdevice.h>
+#include <linux/if.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/ipx.h>
+#include <linux/wireless.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "support.h"
+
+int skfd = -1; /* generic raw socket desc. */
+int ipx_sock = -1; /* IPX socket */
+int ax25_sock = -1; /* AX.25 socket */
+int inet_sock = -1; /* INET socket */
+int ddp_sock = -1; /* Appletalk DDP socket */
+
+static int sockets_open()
+{
+ inet_sock=socket(AF_INET, SOCK_DGRAM, 0);
+ ipx_sock=socket(AF_IPX, SOCK_DGRAM, 0);
+ ax25_sock=socket(AF_AX25, SOCK_DGRAM, 0);
+ ddp_sock=socket(AF_APPLETALK, SOCK_DGRAM, 0);
+ /*
+ * Now pick any (exisiting) useful socket family for generic queries
+ */
+ if(inet_sock!=-1)
+ return inet_sock;
+ if(ipx_sock!=-1)
+ return ipx_sock;
+ if(ax25_sock!=-1)
+ return ax25_sock;
+ /*
+ * If this is -1 we have no known network layers and its time to jump.
+ */
+
+ return ddp_sock;
+}
+
+int
+main(int argc,
+ char ** argv)
+{
+ struct ifreq ifr;
+ struct iwreq wrq;
+ struct aftype *ap;
+ struct hwtype *hw;
+ char * ifname = argv[1];
+
+ if(argc < 2)
+ exit(0);
+
+ /* Create a channel to the NET kernel. */
+ if((skfd = sockets_open()) < 0)
+ {
+ perror("socket");
+ exit(-1);
+ }
+
+ /* Get the type of interface address */
+ strcpy(ifr.ifr_name, ifname);
+ if((ioctl(inet_sock, SIOCGIFADDR, &ifr) < 0) ||
+ ((ap = get_afntype(ifr.ifr_addr.sa_family)) == NULL))
+ {
+ /* Deep trouble... */
+ fprintf(stderr, "Interface %s unavailable\n", ifname);
+ exit(0);
+ }
+
+#ifdef DEBUG
+ printf("Interface : %d - %s - %s\n", ifr.ifr_addr.sa_family,
+ ap->name, ap->sprint(&ifr.ifr_addr, 1));
+#endif
+
+ /* Get the type of hardware address */
+ strcpy(ifr.ifr_name, ifname);
+ if((ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) ||
+ ((hw = get_hwntype(ifr.ifr_hwaddr.sa_family)) == NULL))
+ {
+ /* Deep trouble... */
+ fprintf(stderr, "Unable to get hardware address of the interface %s\n",
+ ifname);
+ exit(0);
+ }
+
+#ifdef DEBUG
+ printf("Hardware : %d - %s - %s\n", ifr.ifr_hwaddr.sa_family,
+ hw->name, hw->print(ifr.ifr_hwaddr.sa_data));
+#endif
+
+ /* Is there any arguments ? */
+ if(argc < 3)
+ { /* Nope : read out from kernel */
+ char buffer[(sizeof(struct iw_quality) +
+ sizeof(struct sockaddr)) * IW_MAX_SPY];
+ struct sockaddr * hwa;
+ struct iw_quality *qual;
+ int n;
+ int i;
+
+ strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
+ wrq.u.data.pointer = (caddr_t) buffer;
+ wrq.u.data.length = 0;
+ wrq.u.data.flags = 0;
+ if(ioctl(skfd, SIOCGIWSPY, &wrq) < 0)
+ {
+ fprintf(stderr, "Interface doesn't accept reading addresses...\n");
+ fprintf(stderr, "SIOCGIWSPY: %s\n", strerror(errno));
+ return(-1);
+ }
+
+ n = wrq.u.data.length;
+
+ hwa = (struct sockaddr *) buffer;
+ qual = (struct iw_quality *) (buffer + (sizeof(struct sockaddr) * n));
+
+ for(i = 0; i < n; i++)
+ printf("%s : Quality %d ; Signal %d ; Noise %d %s\n",
+ hw->print(hwa[i].sa_data),
+ qual[i].qual, qual[i].level, qual[i].noise,
+ qual[i].updated & 0x7 ? "(updated)" : "");
+ }
+ else
+ { /* Send addresses to kernel */
+ int i;
+ int nbr; /* Number of valid addresses */
+ struct sockaddr hw_address[IW_MAX_SPY];
+ struct sockaddr if_address;
+ struct arpreq arp_query;
+
+ /* Read command line */
+ i = 2; /* first arg to read */
+ nbr = 0; /* Number of args readen so far */
+
+ /* "off" : disable functionality (set 0 addresses) */
+ if(!strcmp(argv[2], "off"))
+ i = argc; /* hack */
+
+ /* "+" : add all addresses already in the driver */
+ if(!strcmp(argv[2], "+"))
+ {
+ char buffer[(sizeof(struct iw_quality) +
+ sizeof(struct sockaddr)) * IW_MAX_SPY];
+
+ strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
+ wrq.u.data.pointer = (caddr_t) buffer;
+ wrq.u.data.length = 0;
+ wrq.u.data.flags = 0;
+ if(ioctl(skfd, SIOCGIWSPY, &wrq) < 0)
+ {
+ fprintf(stderr, "Interface doesn't accept reading addresses...\n");
+ fprintf(stderr, "SIOCGIWSPY: %s\n", strerror(errno));
+ return(-1);
+ }
+
+ /* Copy old addresses */
+ nbr = wrq.u.data.length;
+ memcpy(hw_address, buffer, nbr * sizeof(struct sockaddr));
+
+ i = 3; /* skip the "+" */
+ }
+
+ /* Read other args on command line */
+ while((i < argc) && (nbr < IW_MAX_SPY))
+ {
+ /* If it is not a hardware address (prefixed by hw)... */
+ if(strcmp(argv[i], "hw"))
+ {
+ /* Read interface address */
+ if(ap->input(argv[i++], &if_address) < 0)
+ {
+ fprintf(stderr, "Invalid interface address %s\n", argv[i - 1]);
+ continue;
+ }
+
+ /* Translate IP addresses to MAC addresses */
+ memcpy((char *) &(arp_query.arp_pa),
+ (char *) &if_address,
+ sizeof(struct sockaddr));
+ arp_query.arp_ha.sa_family = 0;
+ arp_query.arp_flags = 0;
+ /* The following restrict the search to the interface only */
+ strcpy(arp_query.arp_dev, ifname);
+ if((ioctl(inet_sock, SIOCGARP, &arp_query) < 0) ||
+ !(arp_query.arp_flags & ATF_COM))
+ {
+ fprintf(stderr, "Arp failed for %s... (%d) Try to ping the address before.\n",
+ ap->sprint(&if_address, 1), errno);
+ continue;
+ }
+
+ /* Store new MAC address */
+ memcpy((char *) &(hw_address[nbr++]),
+ (char *) &(arp_query.arp_ha),
+ sizeof(struct sockaddr));
+
+#ifdef DEBUG
+ printf("IP Address %s => Hw Address = %s - %d\n",
+ ap->sprint(&if_address, 1),
+ hw->print(hw_address[nbr - 1].sa_data));
+#endif
+ }
+ else /* If it's an hardware address */
+ {
+ if(++i >= argc)
+ {
+ fprintf(stderr, "hw must be followed by an address...\n");
+ continue;
+ }
+
+ /* Get the hardware address */
+ if(hw->input(argv[i++], &(hw_address[nbr])) < 0)
+ {
+ fprintf(stderr, "Invalid hardware address %s\n", argv[i - 1]);
+ continue;
+ }
+ nbr++;
+
+#ifdef DEBUG
+ printf("Hw Address = %s - %d\n",
+ hw->print(hw_address[nbr - 1].sa_data));
+#endif
+ }
+ } /* Loop on all addresses */
+
+
+ /* Check the number of addresses */
+ if((nbr == 0) && strcmp(argv[2], "off"))
+ {
+ fprintf(stderr, "No valid addresses found : exiting...\n");
+ exit(0);
+ }
+
+ /* Check if there is some remaining arguments */
+ if(i < argc)
+ {
+ fprintf(stderr, "Got only the first %d addresses, remaining discarded\n", IW_MAX_SPY);
+ }
+
+ /* Time to do send addresses to the driver */
+ strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
+ wrq.u.data.pointer = (caddr_t) hw_address;
+ wrq.u.data.length = nbr;
+ wrq.u.data.flags = 0;
+ if(ioctl(skfd, SIOCSIWSPY, &wrq) < 0)
+ {
+ fprintf(stderr, "Interface doesn't accept addresses...\n");
+ fprintf(stderr, "SIOCSIWSPY: %s\n", strerror(errno));
+ return(-1);
+ }
+ }
+
+ /* Close the socket. */
+ close(skfd);
+
+ return(1);
+}