OSDN Git Service

v19
authorchris-kirby <chris.kirby@hpe.com>
Tue, 11 Oct 2016 20:42:04 +0000 (14:42 -0600)
committerchris-kirby <chris.kirby@hpe.com>
Tue, 11 Oct 2016 20:42:04 +0000 (14:42 -0600)
18 files changed:
wireless_tools/INSTALL [new file with mode: 0644]
wireless_tools/Makefile [new file with mode: 0644]
wireless_tools/README [new file with mode: 0644]
wireless_tools/compat.h [new file with mode: 0644]
wireless_tools/iwcommon.c [new file with mode: 0644]
wireless_tools/iwcommon.h [new file with mode: 0644]
wireless_tools/iwconfig [new file with mode: 0644]
wireless_tools/iwconfig.8
wireless_tools/iwconfig.c
wireless_tools/iwpriv [new file with mode: 0644]
wireless_tools/iwpriv.8 [new file with mode: 0644]
wireless_tools/iwpriv.c
wireless_tools/iwspy [new file with mode: 0644]
wireless_tools/iwspy.8
wireless_tools/iwspy.c
wireless_tools/wireless.h [new file with mode: 0644]
wireless_tools/xwireless.c [new file with mode: 0644]
wireless_tools/xwireless.make [new file with mode: 0644]

diff --git a/wireless_tools/INSTALL b/wireless_tools/INSTALL
new file mode 100644 (file)
index 0000000..9f39ed4
--- /dev/null
@@ -0,0 +1,35 @@
+You need :
+--------
+       o A kernel supporting wireless extensions
+               -> from 2.1.17 onward
+               -> from 2.0.30 onward
+               -> patch available for 1.2.13
+               Note : CONFIG_NET_RADIO must be enabled
+       o Driver supporting wireless extensions
+               -> Wavelan isa from kernel 2.1.17 onward
+               -> Wavelan pcmcia from pcmcia 2.9.2 onward
+               -> Netwave pcmcia from pcmcia 2.9.12 onward
+               -> Wavelan IEEE pcmcia drivers
+               -> Proxim RangeLan2/Symphony driver
+               -> Patch your favourite driver
+       Note : more recent kernels and drivers are likely to support
+               more wireless extension features...
+
+Compile wireless tools :
+----------------------
+       In theory, a make should suffice.
+       In practice, there is big troubles with the headers. Depending
+on which version of the kernel headers (might be different from
+kernel) and library headers you have, you need to play with the
+options buried in iwcommon.h.
+
+
+This package was originally created by:
+
+       Jean <jt@hpl.hp.com>
+
+And is now being maintained by:
+       Justin Seger <jseger@media.mit.edu>
+
+It seem that I've been taking over !
+       Jean <jt@hpl.hp.com>
diff --git a/wireless_tools/Makefile b/wireless_tools/Makefile
new file mode 100644 (file)
index 0000000..9764187
--- /dev/null
@@ -0,0 +1,30 @@
+CC = gcc
+RM = rm -f
+
+RM_CMD = $(RM) *.BAK *.bak *.o ,* *~ *.a
+
+CFLAGS=-O2 -Wall
+
+PROGS=iwconfig iwpriv iwspy
+LIBS=-lm
+
+all:: $(PROGS)
+
+.c.o:
+       $(CC) $(CFLAGS) -c $<
+
+iwconfig: iwconfig.o iwcommon.o
+       gcc -O2 -o $@ $^ $(LIBS)
+
+iwpriv: iwpriv.o iwcommon.o
+       gcc -O2 -o $@ $^ $(LIBS)
+
+iwspy: iwspy.o iwcommon.o
+       gcc -O2 -o $@ $^ $(LIBS)
+
+clean::
+       $(RM_CMD) 
+
+depend::
+       makedepend -s "# DO NOT DELETE" -- $(INCLUDES) -- $(SRCS)
+# DO NOT DELETE
diff --git a/wireless_tools/README b/wireless_tools/README
new file mode 100644 (file)
index 0000000..4a706b4
--- /dev/null
@@ -0,0 +1,31 @@
+       This package contain the Wireless tools, used to manipulate
+the Wireless Extensions. The Wireless Extension is an interface
+allowing you to set Wireless LAN specific parameters and get the
+specific stats.
+
+iwconfig.c
+----------
+       The main wireless tool. Used for device configuration.
+       You need of course to compile it.
+       This also includes the functionality previously contained in iwpriv.c.
+       It allows you to access device specific extensions.
+
+iwspy.c
+-------
+       Mobile IP support test and allow get get stats per MAC address
+       (instead of globally).
+
+iwpriv.c
+--------
+       Manipulate driver private ioctls.
+
+xwireless.c
+-----------
+       Graphical tool for the Netwave created by Dag Brattli <dagb@cs.uit.no>
+
+
+       The man page should describe adequately the behaviour of the tools.
+       The list of changes, credits and errata notes are in
+iwcommon.h. Compilation might be tricky.
+
+       Jean <jt@hpl.hp.com>
diff --git a/wireless_tools/compat.h b/wireless_tools/compat.h
new file mode 100644 (file)
index 0000000..224e048
--- /dev/null
@@ -0,0 +1,96 @@
+/* This whole file is flaky */
+/* This is all we need to compile and can't find only in linux headers.
+ * So, I did copy past here...
+ */
+#define __u8   unsigned char
+#define __u16  unsigned short
+#define __u32  unsigned long           /* Hum, and on Alpha ? */
+#define __u64  unsigned long long      /* Unsure about this one */
+
+#define        IFNAMSIZ        16
+#define ARPHRD_ETHER   1               /* Ethernet 10Mbps              */
+#define ETH_ALEN       6               /* Octets in one ethernet addr   */
+
+/*
+ * Interface request structure used for socket
+ * ioctl's.  All interface ioctl's must have parameter
+ * definitions which begin with ifr_name.  The
+ * remainder may be interface specific.
+ */
+struct ifreq 
+{
+#define IFHWADDRLEN    6
+#define        IFNAMSIZ        16
+       union
+       {
+               char    ifrn_name[IFNAMSIZ];            /* if name, e.g. "en0" */
+       } ifr_ifrn;
+       
+       union {
+               struct  sockaddr ifru_addr;
+               struct  sockaddr ifru_dstaddr;
+               struct  sockaddr ifru_broadaddr;
+               struct  sockaddr ifru_netmask;
+               struct  sockaddr ifru_hwaddr;
+               short   ifru_flags;
+               int     ifru_metric;
+               int     ifru_mtu;
+#if 0
+               struct  ifmap ifru_map;
+#endif
+               char    ifru_slave[IFNAMSIZ];   /* Just fits the size */
+               caddr_t ifru_data;
+       } ifr_ifru;
+};
+#define ifr_name       ifr_ifrn.ifrn_name      /* interface name       */
+#define ifr_hwaddr     ifr_ifru.ifru_hwaddr    /* MAC address          */
+#define        ifr_addr        ifr_ifru.ifru_addr      /* address              */
+
+/*
+ * Structure used in SIOCGIFCONF request.
+ * Used to retrieve interface configuration
+ * for machine (useful for programs which
+ * must know all networks accessible).
+ */
+struct ifconf 
+{
+       int     ifc_len;                        /* size of buffer       */
+       union 
+       {
+               caddr_t ifcu_buf;
+               struct  ifreq *ifcu_req;
+       } ifc_ifcu;
+};
+#define        ifc_buf ifc_ifcu.ifcu_buf               /* buffer address       */
+#define        ifc_req ifc_ifcu.ifcu_req               /* array of structures  */
+
+/* Internet address. */
+struct in_addr {
+       __u32   s_addr;
+};
+
+/* Address to accept any incoming messages. */
+#define        INADDR_ANY              ((unsigned long int) 0x00000000)
+
+/* Structure describing an Internet (IP) socket address. */
+#define __SOCK_SIZE__  16              /* sizeof(struct sockaddr)      */
+struct sockaddr_in {
+  short int            sin_family;     /* Address family               */
+  unsigned short int   sin_port;       /* Port number                  */
+  struct in_addr       sin_addr;       /* Internet address             */
+
+  /* Pad to size of `struct sockaddr'. */
+  unsigned char                __pad[__SOCK_SIZE__ - sizeof(short int) -
+                       sizeof(unsigned short int) - sizeof(struct in_addr)];
+};
+
+#define ATF_COM                0x02            /* completed entry (ha valid)   */
+/* ARP ioctl request. */
+struct arpreq {
+  struct sockaddr      arp_pa;         /* protocol address             */
+  struct sockaddr      arp_ha;         /* hardware address             */
+  int                  arp_flags;      /* flags                        */
+  struct sockaddr       arp_netmask;    /* netmask (only for proxy arps) */
+  char                 arp_dev[16];
+};
+
diff --git a/wireless_tools/iwcommon.c b/wireless_tools/iwcommon.c
new file mode 100644 (file)
index 0000000..43de184
--- /dev/null
@@ -0,0 +1,392 @@
+/*
+ *     Wireless Tools
+ *
+ *             Jean II - HPLB '99
+ *
+ * Common subroutines to all the wireless tools...
+ */
+
+#include "iwcommon.h"          /* Header */
+
+/************************ SOCKET SUBROUTINES *************************/
+
+/*------------------------------------------------------------------*/
+/*
+ * Open a socket.
+ * Depending on the protocol present, open the right socket. The socket
+ * will allow us to talk to the driver.
+ */
+int
+sockets_open(void)
+{
+       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         */
+
+       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;
+}
+
+/*********************** WIRELESS SUBROUTINES ************************/
+
+/*------------------------------------------------------------------*/
+/*
+ * Get the range information out of the driver
+ */
+int
+get_range_info(int             skfd,
+              char *           ifname,
+              iwrange *        range)
+{
+  struct iwreq         wrq;
+
+  strcpy(wrq.ifr_name, ifname);
+  wrq.u.data.pointer = (caddr_t) range;
+  wrq.u.data.length = 0;
+  wrq.u.data.flags = 0;
+  if(ioctl(skfd, SIOCGIWRANGE, &wrq) < 0)
+    return(-1);
+
+  return(0);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Get information about what private ioctls are supported by the driver
+ */
+int
+get_priv_info(int              skfd,
+             char *            ifname,
+             iwprivargs *      priv)
+{
+  struct iwreq         wrq;
+
+  /* Ask the driver */
+  strcpy(wrq.ifr_name, ifname);
+  wrq.u.data.pointer = (caddr_t) priv;
+  wrq.u.data.length = 0;
+  wrq.u.data.flags = 0;
+  if(ioctl(skfd, SIOCGIWPRIV, &wrq) < 0)
+    return(-1);
+
+  /* Return the number of ioctls */
+  return(wrq.u.data.length);
+}
+
+/********************** FREQUENCY SUBROUTINES ***********************/
+
+/*------------------------------------------------------------------*/
+/*
+ * Convert a floating point the our internal representation of
+ * frequencies.
+ * The kernel doesn't want to hear about floating point, so we use
+ * this custom format instead.
+ */
+void
+float2freq(double      in,
+          iwfreq *     out)
+{
+  out->e = (short) (floor(log10(in)));
+  if(out->e > 8)
+    {
+      out->m = ((long) (floor(in / pow(10,out->e - 6)))) * 100;
+      out->e -= 8;
+    }
+  else
+    {
+      out->m = in;
+      out->e = 0;
+    }
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Convert our internal representation of frequencies to a floating point.
+ */
+double
+freq2float(iwfreq *    in)
+{
+  return ((double) in->m) * pow(10,in->e);
+}
+
+
+/*********************** ADDRESS SUBROUTINES ************************/
+/*
+ * This section is mostly a cut & past from net-tools-1.2.0
+ * manage address display and input...
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Check if interface support the right address types...
+ */
+int
+check_addr_type(int    skfd,
+               char *  ifname)
+{
+  struct ifreq         ifr;
+
+  /* Get the type of interface address */
+  strcpy(ifr.ifr_name, ifname);
+  if((ioctl(skfd, SIOCGIFADDR, &ifr) < 0) ||
+     (ifr.ifr_addr.sa_family !=  AF_INET))
+    {
+      /* Deep trouble... */
+      fprintf(stderr, "Interface %s doesn't support IP addresses\n", ifname);
+      return(-1);
+    }
+
+#ifdef DEBUG
+  printf("Interface : %d - 0x%lX\n", ifr.ifr_addr.sa_family,
+        *((unsigned long *) ifr.ifr_addr.sa_data));
+#endif
+
+  /* Get the type of hardware address */
+  strcpy(ifr.ifr_name, ifname);
+  if((ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) ||
+     (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER))
+    {
+      /* Deep trouble... */
+      fprintf(stderr, "Interface %s doesn't support MAC addresses\n",
+            ifname);
+      return(-1);
+    }
+
+#ifdef DEBUG
+  printf("Hardware : %d - %s\n", ifr.ifr_hwaddr.sa_family,
+        pr_ether(ifr.ifr_hwaddr.sa_data));
+#endif
+
+  return(0);
+}
+
+
+/*------------------------------------------------------------------*/
+/*
+ * Display an Ethernet address in readable format.
+ */
+char *
+pr_ether(unsigned char *ptr)
+{
+  static char buff[64];
+
+  sprintf(buff, "%02X:%02X:%02X:%02X:%02X:%02X",
+       (ptr[0] & 0xFF), (ptr[1] & 0xFF), (ptr[2] & 0xFF),
+       (ptr[3] & 0xFF), (ptr[4] & 0xFF), (ptr[5] & 0xFF)
+  );
+  return(buff);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Input an Ethernet address and convert to binary.
+ */
+int
+in_ether(char *bufp, struct sockaddr *sap)
+{
+  unsigned char *ptr;
+  char c, *orig;
+  int i, val;
+
+  sap->sa_family = ARPHRD_ETHER;
+  ptr = sap->sa_data;
+
+  i = 0;
+  orig = bufp;
+  while((*bufp != '\0') && (i < ETH_ALEN)) {
+       val = 0;
+       c = *bufp++;
+       if (isdigit(c)) val = c - '0';
+         else if (c >= 'a' && c <= 'f') val = c - 'a' + 10;
+         else if (c >= 'A' && c <= 'F') val = c - 'A' + 10;
+         else {
+#ifdef DEBUG
+               fprintf(stderr, "in_ether(%s): invalid ether address!\n", orig);
+#endif
+               errno = EINVAL;
+               return(-1);
+       }
+       val <<= 4;
+       c = *bufp++;
+       if (isdigit(c)) val |= c - '0';
+         else if (c >= 'a' && c <= 'f') val |= c - 'a' + 10;
+         else if (c >= 'A' && c <= 'F') val |= c - 'A' + 10;
+         else {
+#ifdef DEBUG
+               fprintf(stderr, "in_ether(%s): invalid ether address!\n", orig);
+#endif
+               errno = EINVAL;
+               return(-1);
+       }
+       *ptr++ = (unsigned char) (val & 0377);
+       i++;
+
+       /* We might get a semicolon here - not required. */
+       if (*bufp == ':') {
+               if (i == ETH_ALEN) {
+#ifdef DEBUG
+                       fprintf(stderr, "in_ether(%s): trailing : ignored!\n",
+                               orig)
+#endif
+                                               ; /* nothing */
+               }
+               bufp++;
+       }
+  }
+
+  /* That's it.  Any trailing junk? */
+  if ((i == ETH_ALEN) && (*bufp != '\0')) {
+#ifdef DEBUG
+       fprintf(stderr, "in_ether(%s): trailing junk!\n", orig);
+       errno = EINVAL;
+       return(-1);
+#endif
+  }
+
+#ifdef DEBUG
+  fprintf(stderr, "in_ether(%s): %s\n", orig, pr_ether(sap->sa_data));
+#endif
+
+  return(0);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Input an Internet address and convert to binary.
+ */
+int
+in_inet(char *bufp, struct sockaddr *sap)
+{
+  struct hostent *hp;
+  struct netent *np;
+  char *name = bufp;
+  struct sockaddr_in *sin = (struct sockaddr_in *) sap;
+
+  /* Grmpf. -FvK */
+  sin->sin_family = AF_INET;
+  sin->sin_port = 0;
+
+  /* Default is special, meaning 0.0.0.0. */
+  if (!strcmp(name, "default")) {
+       sin->sin_addr.s_addr = INADDR_ANY;
+       return(1);
+  }
+
+  /* Try the NETWORKS database to see if this is a known network. */
+  if ((np = getnetbyname(name)) != (struct netent *)NULL) {
+       sin->sin_addr.s_addr = htonl(np->n_net);
+       strcpy(name, np->n_name);
+       return(1);
+  }
+
+  if ((hp = gethostbyname(name)) == (struct hostent *)NULL) {
+       errno = h_errno;
+       return(-1);
+  }
+  memcpy((char *) &sin->sin_addr, (char *) hp->h_addr_list[0], hp->h_length);
+  strcpy(name, hp->h_name);
+  return(0);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Input an address and convert to binary.
+ */
+int
+in_addr(int            skfd,
+       char *          ifname,
+       char *          bufp,
+       struct sockaddr *sap)
+{
+  /* Check if it is a hardware or IP address */
+  if(index(bufp, ':') == NULL)
+    {
+      struct sockaddr  if_address;
+      struct arpreq    arp_query;
+
+      /* Read interface address */
+      if(in_inet(bufp, &if_address) < 0)
+       {
+         fprintf(stderr, "Invalid interface address %s\n", bufp);
+         return(-1);
+       }
+
+      /* 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 */
+      /* For old kernels which complain, just comment it... */
+      strcpy(arp_query.arp_dev, ifname);
+      if((ioctl(skfd, SIOCGARP, &arp_query) < 0) ||
+        !(arp_query.arp_flags & ATF_COM))
+       {
+         fprintf(stderr, "Arp failed for %s on %s... (%d)\nTry to ping the address before setting it.\n",
+                 bufp, ifname, errno);
+         return(-1);
+       }
+
+      /* Store new MAC address */
+      memcpy((char *) sap,
+            (char *) &(arp_query.arp_ha),
+            sizeof(struct sockaddr));
+
+#ifdef DEBUG
+      printf("IP Address %s => Hw Address = %s\n",
+            bufp, pr_ether(sap->sa_data));
+#endif
+    }
+  else /* If it's an hardware address */
+    /* Get the hardware address */
+    if(in_ether(bufp, sap) < 0)
+      {
+       fprintf(stderr, "Invalid hardware address %s\n", bufp);
+       return(-1);
+      }
+
+#ifdef DEBUG
+  printf("Hw Address = %s\n", pr_ether(sap->sa_data));
+#endif
+
+  return(0);
+}
+
+/************************* MISC SUBROUTINES **************************/
+
+/*------------------------------------------------------------------*/
+/*
+ */
+int
+byte_size(int  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;
+}
+
diff --git a/wireless_tools/iwcommon.h b/wireless_tools/iwcommon.h
new file mode 100644 (file)
index 0000000..cfdea27
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ *     Wireless Tools
+ *
+ *             Jean II - HPLB '99
+ *
+ * Common header for the wireless tools...
+ */
+
+#ifndef IWCOMMON_H
+#define IWCOMMON_H
+
+/************************** DOCUMENTATION **************************/
+/*
+ * None ? Todo...
+ */
+
+/* --------------------------- HISTORY --------------------------- */
+/*
+ * wireless 16 :               (Jean Tourrilhes)
+ * -----------
+ *     o iwconfig, iwpriv & iwspy
+ *
+ * wireless 17 :               (Justin Seger)
+ * -----------
+ *     o Compile under glibc fix
+ *     o merge iwpriv in iwconfig
+ *     o Add Wavelan roaming support
+ *     o Update man page of iwconfig
+ *
+ * wireless 18 :
+ * -----------
+ *             (From Andreas Neuhaus <andy@fasta.fh-dortmund.de>)
+ *     o Many fix to remove "core dumps" in iwconfig
+ *     o Remove useless headers in iwconfig
+ *     o CHAR wide private ioctl
+ *             (From Jean Tourrilhes)
+ *     o Create iwcommon.h and iwcommon.c
+ *     o Separate iwpriv again for user interface issues
+ *       The folllowing didn't make sense and crashed :
+ *             iwconfig eth0 priv sethisto 12 15 nwid 100
+ *     o iwspy no longer depend on net-tools-1.2.0
+ *     o Reorganisation of the code, cleanup
+ *     o Add ESSID stuff in iwconfig
+ *     o Add display of level & noise in dBm (stats in iwconfig)
+ *     o Update man page of iwconfig and iwpriv
+ *     o Add xwireless (didn't check if it compiles)
+ *             (From Dean W. Gehnert <deang@tpi.com>)
+ *     o Minor fixes
+ *             (Jan Rafaj <rafaj@cedric.vabo.cz>)
+ *     o Cosmetic changes (sensitivity relative, freq list)
+ *     o Frequency computation on double
+ *     o Compile clean on libc5
+ *             (From Jean Tourrilhes)
+ *     o Move listing of frequencies to iwspy
+ *     o Add AP address stuff in iwconfig
+ *     o Add AP list stuff in iwspy
+ *
+ * wireless 19 :
+ * -----------
+ *             (From Jean Tourrilhes)
+ *     o Allow for sensitivity in dBm (if < 0) [iwconfig]
+ *     o Formatting changes in displaying ap address in [iwconfig]
+ *     o Slightly improved man pages and usage display
+ *     o Add channel number for each frequency in list [iwspy]
+ *     o Add nickname... [iwconfig]
+ *     o Add "port" private ioctl shortcut [iwpriv]
+ *     o If signal level = 0, no range or dBms [iwconfig]
+ *     o I think I now got set/get char strings right in [iwpriv]
+ *             (From Thomas Ekstrom <tomeck@thelogic.com>)
+ *     o Fix a very obscure bug in [iwspy]
+ */
+
+/* ----------------------------- TODO ----------------------------- */
+/*
+ * One day, maybe...
+ *
+ * iwconfig :
+ * --------
+ *     Use new 802.11 parameters (rate, rts, frag)...
+ *
+ * iwpriv :
+ * ------
+ *     ?
+ *
+ * iwspy :
+ * -----
+ *     ?
+ *
+ * Doc & man pages :
+ * ---------------
+ *     ?
+ */
+
+/***************************** INCLUDES *****************************/
+
+/* Standard headers */
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <math.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <netdb.h>             /* gethostbyname, getnetbyname */
+
+/* This is our header selection. Try to hide the mess and the misery :-(
+ * Please choose only one of the define...
+ */
+#define KER2_2_HEADERS         /* Kernel 2.2.X + Glibc - ok for most people */
+#undef LINUX_HEADERS           /* Kernel 2.0.X + Glibc - Debian 2.0, RH5 */
+#undef LIBC5_HEADERS           /* Kernel 2.0.X + libc5 - old systems */
+#undef PRIVATE_HEADERS         /* Ugly last resort case */
+
+#ifdef KER2_2_HEADERS
+#include <socketbits.h>
+#include <linux/if_arp.h>      /* For ARPHRD_ETHER */
+#include <linux/socket.h>      /* For AF_INET & struct sockaddr */
+#include <linux/in.h>          /* For struct sockaddr_in */
+
+/* Wireless extensions */
+#include <linux/wireless.h>
+
+#endif /* KER2_2_HEADERS */
+
+#ifdef LINUX_HEADERS
+#include <linux/if_arp.h>      /* For ARPHRD_ETHER */
+#include <linux/socket.h>      /* For AF_INET & struct sockaddr */
+#include <linux/in.h>          /* For struct sockaddr_in */
+
+/* Wireless extensions */
+#include <linux/wireless.h>
+
+#endif /* LINUX_HEADERS */
+
+#ifdef LIBC5_HEADERS
+#include <sys/socket.h>                /* For AF_INET & struct sockaddr & socket() */
+#include <linux/if_arp.h>      /* For ARPHRD_ETHER */
+#include <linux/in.h>          /* For struct sockaddr_in */
+
+/* Wireless extensions */
+#include <linux/wireless.h>
+
+#endif /* LIBC5_HEADERS */
+
+#ifdef PRIVATE_HEADERS
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <socketbits.h>
+#include "compat.h"            /* Don't ask ! */
+
+/* Wireless extensions */
+#include "wireless.h"
+
+#endif /* PRIVATE_HEADERS */
+
+
+/****************************** DEBUG ******************************/
+
+
+/************************ CONSTANTS & MACROS ************************/
+
+/* Some usefull constants */
+#define KILO   1e3
+#define MEGA   1e6
+#define GIGA   1e9
+
+/* Some hack */
+#ifndef IW_ESSID_MAX_SIZE
+#define IW_ESSID_MAX_SIZE      32      /* Should be in wireless.h */
+#endif
+#ifndef IW_MAX_AP
+#define IW_MAX_AP              8       /* Should be in wireless.h */
+#endif
+
+/****************************** TYPES ******************************/
+
+/* Shortcuts */
+typedef struct iw_statistics   iwstats;
+typedef struct iw_range                iwrange;
+typedef struct iw_freq         iwfreq;
+typedef struct iw_priv_args    iwprivargs;
+typedef struct sockaddr                sockaddr;
+
+/* Structure for storing all wireless information for each device */
+typedef struct wireless_info
+{
+  char         name[IFNAMSIZ];         /* Wireless/protocol name */
+  int          has_nwid;
+  int          nwid_on;
+  u_long       nwid;                   /* Network ID */
+  int          has_freq;
+  float                freq;                   /* Frequency/channel */
+  int          has_sens;
+  int          sens;                   /* sensitivity */
+  int          has_enc;
+  int          enc_method;             /* encoding method or off */
+  long long    enc_key;                /* key used */
+  int          has_essid;
+  int          essid_on;
+  char         essid[IW_ESSID_MAX_SIZE + 1];   /* ESSID (extended network) */
+  int          has_nickname;
+  char         nickname[IW_ESSID_MAX_SIZE + 1]; /* NickName */
+  int          has_ap_addr;
+  sockaddr     ap_addr;                /* Access point address */
+  int          has_bitrate;
+  long         bitrate;                /* Bit rate in bps */
+  int          bitrate_fixed;          /* Fixed or auto */
+  int          has_rts;
+  long         rts;                    /* RTS threshold in bytes */
+  int          rts_fixed;              /* Fixed or auto */
+  int          has_frag;
+  long         frag;                   /* Fragmentation threshold in bytes */
+  int          frag_fixed;             /* Fixed or auto */
+
+  /* Stats */
+  iwstats      stats;
+  int          has_stats;
+  iwrange      range;
+  int          has_range;
+} wireless_info;
+
+/**************************** PROTOTYPES ****************************/
+/*
+ * All the functions in iwcommon.c
+ */
+/* ---------------------- SOCKET SUBROUTINES -----------------------*/
+int
+       sockets_open(void);
+/* --------------------- WIRELESS SUBROUTINES ----------------------*/
+int
+       get_range_info(int              skfd,
+                      char *           ifname,
+                      iwrange *        range);
+int
+       get_priv_info(int               skfd,
+                     char *            ifname,
+                     iwprivargs *      priv);
+/* -------------------- FREQUENCY SUBROUTINES --------------------- */
+void
+       float2freq(double       in,
+                  iwfreq *     out);
+double
+       freq2float(iwfreq *     in);
+/* --------------------- ADDRESS SUBROUTINES ---------------------- */
+int
+       check_addr_type(int     skfd,
+                       char *  ifname);
+char *
+       pr_ether(unsigned char *ptr);
+int
+       in_ether(char *bufp, struct sockaddr *sap);
+int
+       in_inet(char *bufp, struct sockaddr *sap);
+int
+       in_addr(int             skfd,
+               char *          ifname,
+               char *          bufp,
+               struct sockaddr *sap);
+/* ----------------------- MISC SUBROUTINES ------------------------ */
+int
+       byte_size(int           args);
+
+/**************************** VARIABLES ****************************/
+
+#endif /* IWCOMMON_H */
diff --git a/wireless_tools/iwconfig b/wireless_tools/iwconfig
new file mode 100644 (file)
index 0000000..abc90a6
Binary files /dev/null and b/wireless_tools/iwconfig differ
index b2e3d60..24c1e50 100644 (file)
@@ -13,7 +13,11 @@ iwconfig \- configure a wireless network interface
 .SH SYNOPSIS
 .BI "iwconfig [" interface ]
 .br
-.BI "iwconfig " interface " [nwid " N "] [freq " F ]
+.BI "iwconfig " interface " [essid " X "] [nwid " N "] [freq " F "] [channel " C ]
+.br
+.BI "                   [sens " S "] [enc " E "] [ap " A "] [nick " NN ]
+.br
+.BI "                   [rate " R "] [rts " RT "] [frag " FT ]
 .\"
 .\" DESCRIPTION part
 .\"
@@ -38,16 +42,101 @@ device for details.
 .\"
 .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).
+.B essid
+Set the ESSID (or Network Name - in some products it may also called
+Domain ID). The ESSID is used to identify cells which are part of the
+same virtual network.
+.br
+As opposed to the NWID which defines a single cell, the ESSID defines
+a group of cell connected via repeaters or infrastructure, where the
+user may roam.  With some card, you may disable the ESSID checking
+(ESSID promiscuous) with
+.IR off " (and " on
+to reenable it).
+.TP
+.BR nwid / domain
+Set the Network ID (in some products it is also called Domain ID). As
+all adjacent wireless networks share the same medium, this parameter
+is used to differenciate them (create logical colocated networks) and
+identify nodes belonguing to the same cell. With some card, you may
+disable the Network ID checking (NWID promiscuous) with
+.IR off " (and " on
+to reenable it).
 .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).
+must prepend the suffix k, M or G to the value (for example, "2.46G"
+for 2.46 GHz frequency), or add enough '0'.
+.br
+Channels are usually numbered starting at 1,
+and you may use
+.IR iwpriv (8)
+to get the total number of channels and list the available
+frequencies. Depending on regulations, some frequencies/channels may
+not be available.
+.TP
+.B sens
+Set the sensitivity threshold. This is the lowest signal level for
+which we attempt a packet reception, signal lower than this are not
+received. This is used to avoid receiving background noise, so you
+should set it according to the average noise level. Positive values
+are assumed to be the raw value used by the hardware or a percentage,
+negative values are assumed to be dBm.
+.br
+With some hardware, this parameter also control the defer threshold
+(lowest signal level for which we consider the channel busy) and the
+handover threshold (lowest signal level where we stay associated with
+the current access point).
+.TP
+.B enc
+Set the encryption or scrambing key (the syntax is
+.IR XXXX-XXXX-XXXX-XXXX " or " XXXXXXXX ).
+Used also to control the encryption feature
+.RI ( on / off ).
+.TP
+.B ap
+Register to the Access Point given by the address, if it is
+possible. When the quality of the connection goes too low, the driver
+may revert back to automatic mode.
+.TP
+.BR nick [ name ]
+Set the nickname, or the station name. Most 802.11 products do define
+it, but this is not used as far as the protocols (MAC, IP, TCP) are
+concerned and completely accessory as far as configuration goes. In
+fact only some diagnostic tools may use it.
+.TP
+.BR rate / bit [ rate ]
+For cards supporting multiple bit rates, set the bit-rate in b/s. The
+bit-rate is the speed at which bits are transmitted over the medium,
+the user speed of the link is lower due to medium sharing and
+overhead.
+.br
+You must prepend the suffix k, M or G to the value (decimal multiplier
+: 10^3, 10^6 and 10^9 b/s), or add enough '0'. Values below 1000 are
+card specific, usually an index in the bit-rate list. Use
+.I auto
+to select the automatic bit-rate mode (fallback to lower rate on noisy
+channels), which is the default for most cards, and
+.I fixed
+to revert back to fixed setting.
+.TP
+.BR rts [ _threshold ]
+RTS/CTS adds a handshake before each packet transmission to make sure
+that the channel is clear. This adds overhead, but increase
+performance in case of hidden nodes or large number of active
+nodes. This parameters set the size of the smallest packet for which
+the node sends RTS, a value equal to the maximum packet size disable
+the scheme. You may also set this parameter to
+.IR auto ", " fixed " or " off .
+.TP
+.BR frag [ mentation_threshold ]
+Fragmentation allow to split a IP packet in a burst of smaller
+fragments transmitted on the medium. In most cases this adds overhead,
+but in very noisy environment this reduce the error penalty. This
+parameter set the maximum fragment size, a value equal to the maximum
+packet size disable the scheme. You may also set this parameter to
+.IR auto ", " fixed " or " off .
 .\"
 .\" DISPLAY part
 .\"
@@ -57,10 +146,24 @@ For each device which support wireless extensions,
 will display the name of the
 .B MAC protocol
 used (name of device for proprietary protocols), the
-.B NWID
-and the
+.B ESSID
+(Network Name), the
+.BR NWID ,
+the
 .B frequency
-(if available).
+(or channel), the
+.BR sensitivity ,
+the
+.B Access Point
+address, the
+.B bit-rate
+(with
+.B (f)
+if fixed), the
+.BR "RTS threshold" ", the " "fragmentation threshold" ,
+and the
+.B encryption key
+(depending on availability). See above for explanations.
 .PP
 If
 .I /proc/net/wireless
index 33bc879..8cb9f0c 100644 (file)
 /*
- * Hack my way... Jean II
+ *     Wireless Tools
+ *
+ *             Jean II - HPLB '99
+ *
+ * Main code for "iwconfig". This is the generic tool for most
+ * manipulations...
+ * You need to link this code against "iwcommon.c" and "-lm".
  */
-#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         */
 
+#include "iwcommon.h"          /* Header */
+
+/************************* MISC SUBROUTINES **************************/
 
+/*------------------------------------------------------------------*/
+/*
+ * Print usage string
+ */
 static void
-usage(void)
+iw_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");
+  fprintf(stderr, "Usage: iwconfig interface [essid {NN|on|off}]\n");
+  fprintf(stderr, "                          [nwid {NN|on|off}]\n");
+  fprintf(stderr, "                          [freq N.NNNN[k|M|G]]\n");
+  fprintf(stderr, "                          [channel N]\n");
+  fprintf(stderr, "                          [sens N]\n");
+  fprintf(stderr, "                          [nick N]\n");
+  fprintf(stderr, "                          [rate {N|auto|fixed}]\n");
+  fprintf(stderr, "                          [rts {N|auto|fixed|off}]\n");
+  fprintf(stderr, "                          [frag {N|auto|fixed|off}]\n");
+  fprintf(stderr, "                          [enc NNNN-NNNN]\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");
-}
+/************************* DISPLAY ROUTINES **************************/
 
-static int if_getstats(char *ifname, iwstats * stats)
+/*------------------------------------------------------------------*/
+/*
+ * Read /proc/net/wireless to get the latest statistics
+ */
+static int
+iw_getstats(char *     ifname,
+           iwstats *   stats)
 {
   FILE *f=fopen("/proc/net/wireless","r");
   char buf[256];
@@ -132,39 +58,42 @@ static int if_getstats(char *ifname, iwstats *     stats)
                bp=strchr(bp,':');
                bp++;
                bp = strtok(bp, " .");
-               sscanf(bp, "%X", &stats->status);
+               sscanf(bp, "%X", (unsigned int *)&stats->status);
                bp = strtok(NULL, " .");
-               sscanf(bp, "%d", &stats->qual.qual);
+               sscanf(bp, "%d", (unsigned int *)&stats->qual.qual);
                bp = strtok(NULL, " .");
-               sscanf(bp, "%d", &stats->qual.level);
+               sscanf(bp, "%d", (unsigned int *)&stats->qual.level);
                bp = strtok(NULL, " .");
-               sscanf(bp, "%d", &stats->qual.noise);
+               sscanf(bp, "%d", (unsigned int *)&stats->qual.noise);
                bp = strtok(NULL, " .");
                sscanf(bp, "%d", &stats->discard.nwid);
                bp = strtok(NULL, " .");
-               sscanf(bp, "%d", &stats->discard.crypt);
+               sscanf(bp, "%d", &stats->discard.code);
                bp = strtok(NULL, " .");
                sscanf(bp, "%d", &stats->discard.misc);
                fclose(f);
-               return;
+               return 0;
        }
   }
   fclose(f);
   return 0;
 }
 
-/* Get wireless informations & config from the device driver */
+/*------------------------------------------------------------------*/
+/*
+ * Get wireless informations & config from the device driver
+ * We will call all the classical wireless ioctl on the driver through
+ * the socket to know what is supported and to get the settings...
+ */
 static int
-get_info(char *                        ifname,
+get_info(int                   skfd,
+        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)
@@ -187,31 +116,352 @@ get_info(char *                  ifname,
   if(ioctl(skfd, SIOCGIWFREQ, &wrq) >= 0)
     {
       info->has_freq = 1;
-      info->freq = wrq.u.freq;
+      info->freq = freq2float(&(wrq.u.freq));
     }
 
-  /* Get stats */
-  if(if_getstats(ifname, &(info->stats)) == 0)
+  /* Get sensitivity */
+  strcpy(wrq.ifr_name, ifname);
+  if(ioctl(skfd, SIOCGIWSENS, &wrq) >= 0)
     {
-      info->has_stats = 1;
+      info->has_sens = 1;
+      info->sens = wrq.u.sensitivity;
     }
 
-  /* Get ranges */
+   /* Get encryption information */
+   strcpy(wrq.ifr_name, ifname);
+   if(ioctl(skfd, SIOCGIWENCODE, &wrq) >= 0)
+     {
+       info->has_enc = 1;
+       info->enc_method = wrq.u.encoding.method;
+       info->enc_key = wrq.u.encoding.code;
+     }
+
+#if WIRELESS_EXT > 5
+  /* Get ESSID */
+  strcpy(wrq.ifr_name, ifname);
+  wrq.u.data.pointer = (caddr_t) info->essid;
+  wrq.u.data.length = 0;
+  wrq.u.data.flags = 0;
+  if(ioctl(skfd, SIOCGIWESSID, &wrq) >= 0)
+    {
+      info->has_essid = 1;
+      info->essid_on = wrq.u.data.flags;
+    }
+
+  /* Get AP address */
+  strcpy(wrq.ifr_name, ifname);
+  if(ioctl(skfd, SIOCGIWAP, &wrq) >= 0)
+    {
+      info->has_ap_addr = 1;
+      memcpy(&(info->ap_addr), &(wrq.u.ap_addr), sizeof (sockaddr));
+    }
+#endif /* WIRELESS_EXT > 5 */
+
+#if WIRELESS_EXT > 7
+  /* Get NickName */
   strcpy(wrq.ifr_name, ifname);
-  wrq.u.data.pointer = (caddr_t) &(info->range);
+  wrq.u.data.pointer = (caddr_t) info->nickname;
   wrq.u.data.length = 0;
   wrq.u.data.flags = 0;
-  if(ioctl(skfd, SIOCGIWRANGE, &wrq) >= 0)
+  if(ioctl(skfd, SIOCGIWNICKN, &wrq) >= 0)
+    if(wrq.u.data.length > 1)
+      info->has_nickname = 1;
+
+  /* Get bit rate */
+  strcpy(wrq.ifr_name, ifname);
+  if(ioctl(skfd, SIOCGIWRATE, &wrq) >= 0)
+    {
+      info->has_bitrate = 1;
+      info->bitrate_fixed = wrq.u.bitrate.fixed;
+      info->bitrate = wrq.u.bitrate.value;
+    }
+
+  /* Get RTS threshold */
+  strcpy(wrq.ifr_name, ifname);
+  if(ioctl(skfd, SIOCGIWRTS, &wrq) >= 0)
+    {
+      info->has_rts = 1;
+      info->rts_fixed = wrq.u.rts.fixed;
+      info->rts = wrq.u.rts.value;
+    }
+
+  /* Get fragmentation thershold */
+  strcpy(wrq.ifr_name, ifname);
+  if(ioctl(skfd, SIOCGIWFRAG, &wrq) >= 0)
+    {
+      info->has_frag = 1;
+      info->frag_fixed = wrq.u.frag.fixed;
+      info->frag = wrq.u.frag.value;
+    }
+#endif /* WIRELESS_EXT > 7 */
+
+  /* Get stats */
+  if(iw_getstats(ifname, &(info->stats)) == 0)
     {
-      info->has_range = 1;
+      info->has_stats = 1;
     }
 
+  /* Get ranges */
+  if(get_range_info(skfd, ifname, &(info->range)) >= 0)
+    info->has_range = 1;
+
   return(0);
 }
 
+/*------------------------------------------------------------------*/
+/*
+ * Print on the screen in a neat fashion all the info we have collected
+ * on a device.
+ */
+static void
+display_info(struct wireless_info *    info,
+            char *                     ifname)
+{
+  /* Display device name and wireless name (name of the protocol used) */
+  printf("%-8.8s  %s  ", ifname, info->name);
+
+  /* Display ESSID (extended network), if any */
+  if(info->has_essid)
+    {
+      if(info->essid_on)
+       printf("ESSID:\"%s\"  ", info->essid);
+      else
+       printf("ESSID:off  ");
+    }
+
+  /* Display NickName (station name), if any */
+  if(info->has_nickname)
+    printf("Nickname:\"%s\"", info->nickname);
+
+  /* Formatting */
+  if(info->has_essid || info->has_nickname)
+    printf("\n          ");
+
+  /* Display Network ID */
+  if(info->has_nwid)
+    {
+      /* Note : should display right number of digit according to info
+       * in range structure */
+      if(info->nwid_on)
+       printf("NWID:%lX  ", info->nwid);
+      else
+       printf("NWID:off/any  ");
+    }
+
+  /* Display frequency / channel */
+  if(info->has_freq)
+    {
+      if(info->freq < KILO)
+       printf("Channel:%g  ", 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);
+           }
+       }
+    }
+
+  /* Display sensitivity */
+  if(info->has_sens)
+    {
+      if(info->has_range)
+       /* Display in dBm ? */
+       if(info->sens < 0)
+         printf("Sensitivity:%d dBm  ", info->sens);
+       else
+         printf("Sensitivity:%d/%d  ", info->sens, info->range.sensitivity);
+      else
+       printf("Sensitivity:%d  ", info->sens);
+    }
+
+  /* Display the address of the current Access Point */
+  if(info->has_ap_addr)
+    {
+      /* A bit of clever formatting */
+      if((info->has_nwid + 2*info->has_freq + 2*info->has_sens
+         + !info->has_essid) > 3)
+       printf("\n          ");
+
+      printf("Access Point: %s", pr_ether(info->ap_addr.sa_data));
+    }
+
+  printf("\n          ");
+
+  /* Display the currently used/set bit-rate */
+  if(info->has_bitrate)
+    {
+      printf("Bit Rate:");
+      if(info->bitrate >= GIGA)
+       printf("%g Gb/s", info->bitrate / GIGA);
+      else
+       if(info->bitrate >= MEGA)
+         printf("%g Mb/s", info->bitrate / MEGA);
+       else
+         printf("%g kb/s", info->bitrate / KILO);
+
+      /* Fixed ? */
+      if(info->bitrate_fixed)
+       printf(" (f)   ");
+      else
+       printf("   ");
+    }
+
+  /* Display the RTS threshold */
+  if(info->has_rts)
+    {
+      printf("RTS thr:%ld B", info->rts);
+
+      /* Fixed ? */
+      if(info->rts_fixed)
+       printf(" (f)   ");
+      else
+       printf("   ");
+    }
+
+  /* Display the fragmentation threshold */
+  if(info->has_bitrate)
+    {
+      printf("Frag thr:%ld B", info->frag);
+
+      /* Fixed ? */
+      if(info->frag_fixed)
+       printf(" (f)   ");
+      else
+       printf("   ");
+    }
+
+  /* Formating */
+  if((info->has_bitrate) || (info->has_rts) || (info->has_bitrate))
+    printf("\n          ");
+
+  if(info->has_enc)
+    {
+      printf("Encryption key:");
+      if(info->enc_method)
+       {
+         int           i = 0;
+         u_short       parts[4];
+         long long     key = info->enc_key;
+
+         for(i = 3; i >= 0; i--)
+           {
+             parts[i] = key & 0xFFFF;
+             key >>= 16;
+           }
+
+         i = 0;
+         while((parts[i] == 0) && (i < 3))
+           i++;
+         for(; i < 3; i++)
+           printf("%.4X-", parts[i]);
+         printf("%.4X", parts[3]);
+
+         if(info->enc_method > 1)
+           printf(" (%d)", info->enc_method);
+         printf("\n          ");
+       }
+      else
+       printf("off\n          ");
+    }
+
+  if(info->has_stats)
+    {
+      if(info->has_range && (info->stats.qual.level != 0))
+       /* If the statistics are in dBm */
+       if(info->stats.qual.level > info->range.max_qual.level)
+         printf("Link quality:%d/%d  Signal level:%d dBm  Noise level:%d dBm\n",
+                info->stats.qual.qual, info->range.max_qual.qual,
+                info->stats.qual.level - 0x100,
+                info->stats.qual.noise - 0x100);
+       else
+         /* Statistics are relative values (0 -> max) */
+         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
+       /* We can't read the range, so we don't know... */
+       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.code,
+            info->stats.discard.misc);
+    }
+
+  printf("\n");
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Print on the screen in a neat fashion all the info we have collected
+ * on a device.
+ */
+static void
+print_info(int         skfd,
+          char *       ifname)
+{
+  struct wireless_info info;
+
+  if(get_info(skfd, ifname, &info) < 0)
+    {
+      fprintf(stderr, "%-8.8s  no wireless extensions.\n\n",
+             ifname);
+      return;
+    }
+
+  /* Display it ! */
+  display_info(&info, ifname);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Get info on all devices and print it on the screen
+ */
+static void
+print_devices(int      skfd)
+{
+  char buff[1024];
+  struct ifconf ifc;
+  struct ifreq *ifr;
+  int i;
+
+  /* Get list of active devices */
+  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;
+
+  /* Print them */
+  for(i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++)
+    print_info(skfd, ifr->ifr_name);
+}
+
+/************************* SETTING ROUTINES **************************/
 
+/*------------------------------------------------------------------*/
+/*
+ * Set the wireless options requested on command line
+ * This function is too long and probably should be split,
+ * because it look like the perfect definition of spaghetti code,
+ * but I'm way to lazy
+ */
 static int
-set_info(char *                args[],         /* Command line args */
+set_info(int           skfd,           /* The socket */
+        char *         args[],         /* Command line args */
         int            count,          /* Args count */
         char *         ifname)         /* Dev name */
 {
@@ -221,21 +471,41 @@ set_info(char *           args[],         /* Command line args */
   /* Set dev name */
   strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
 
+  /* if nothing after the device name */
+  if(count<1)
+    iw_usage();
+
   /* 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"))
+      /* ---------- Set network ID ---------- */
+      if((!strcasecmp(args[i], "nwid")) ||
+        (!strcasecmp(args[i], "domain")))
        {
-         if(++i >= count)
-           usage();
-         if(!strcasecmp(args[i], "off"))
+         i++;
+         if(i >= count)
+           iw_usage();
+         if((!strcasecmp(args[i], "off")) ||
+            (!strcasecmp(args[i], "any")))
            wrq.u.nwid.on = 0;
          else
-           if(sscanf(args[i], "%lX", &(wrq.u.nwid.nwid)) != 1)
-             usage();
+           if(!strcasecmp(args[i], "on"))
+             {
+               /* Get old nwid */
+               if(ioctl(skfd, SIOCGIWNWID, &wrq) < 0)
+                 {
+                   fprintf(stderr, "SIOCGIWNWID: %s\n", strerror(errno));
+                   return(-1);
+                 }
+               strcpy(wrq.ifr_name, ifname);
+               wrq.u.nwid.on = 1;
+             }
            else
-             wrq.u.nwid.on = 1;
+             if(sscanf(args[i], "%lX", (unsigned long *) &(wrq.u.nwid.nwid))
+                != 1)
+               iw_usage();
+             else
+               wrq.u.nwid.on = 1;
 
          if(ioctl(skfd, SIOCSIWNWID, &wrq) < 0)
            {
@@ -245,133 +515,356 @@ set_info(char *         args[],         /* Command line args */
          continue;
        }
 
-      /* Set frequency / channel */
+      /* ---------- Set frequency / channel ---------- */
       if((!strncmp(args[i], "freq", 4)) ||
         (!strcmp(args[i], "channel")))
        {
+         double                freq;
+
+         if(++i >= count)
+           iw_usage();
+         if(sscanf(args[i], "%lg", &(freq)) != 1)
+           iw_usage();
+         if(index(args[i], 'G')) freq *= GIGA;
+         if(index(args[i], 'M')) freq *= MEGA;
+         if(index(args[i], 'k')) freq *= KILO;
+
+         float2freq(freq, &(wrq.u.freq));
+
+         if(ioctl(skfd, SIOCSIWFREQ, &wrq) < 0)
+           {
+             fprintf(stderr, "SIOCSIWFREQ: %s\n", strerror(errno));
+             return(-1);
+           }
+         continue;
+       }
+
+      /* ---------- Set sensitivity ---------- */
+      if(!strncmp(args[i], "sens", 4))
+       {
+         if(++i >= count)
+           iw_usage();
+         if(sscanf(args[i], "%d", &(wrq.u.sensitivity)) != 1)
+           iw_usage();
+
+         if(ioctl(skfd, SIOCSIWSENS, &wrq) < 0)
+           {
+             fprintf(stderr, "SIOCSIWSENS: %s\n", strerror(errno));
+             return(-1);
+           }
+         continue;
+       }
+
+      /* ---------- Set encryption stuff ---------- */
+      if(!strncmp(args[i], "enc", 3 ))
+       {
+         unsigned long long    key = 0;
+
          if(++i >= count)
+           iw_usage();
+
+         if(!strcasecmp(args[i], "off"))
+           wrq.u.encoding.method = 0;
+         else
+           {
+             if(!strcasecmp(args[i], "on"))
+               {
+                 /* Get old encryption information */
+                 if(ioctl(skfd, SIOCGIWENCODE, &wrq) < 0)
+                   {
+                     fprintf(stderr, "SIOCGIWENCODE: %s\n", strerror(errno));
+                     return(-1);
+                   }
+                 strcpy(wrq.ifr_name, ifname);
+               }
+             else
+               {
+                 char *        buff;
+                 char *        p;
+                 u_long        temp;
+
+                 p = buff = malloc(strlen(args[i] + 1));
+                 strcpy(buff, args[i]);
+
+                 p = strtok(buff, "-:;.,*#");
+                 while(p != (char *) NULL)
+                   {
+                     key = key << 16;
+                     if(sscanf(p, "%lX", &temp) != 1)
+                       iw_usage();
+                     key += temp;
+                     p = strtok((char *) NULL, "-:;.,*#");
+                   }
+
+                 free(buff);
+                 wrq.u.encoding.code = key;
+               }
+             /* TODO : check for "(method)" in args list */
+             wrq.u.encoding.method = 1;
+           }
+
+         if(ioctl(skfd, SIOCSIWENCODE, &wrq) < 0)
            {
-             struct iw_range   range;
-             int               k;
+             fprintf(stderr, "SIOCSIWENCODE(%d): %s\n",
+                     errno, strerror(errno));
+             return(-1);
+           }
+         continue;
+       }
+
+#if WIRELESS_EXT > 5
+      /* ---------- Set ESSID ---------- */
+      if(!strcasecmp(args[i], "essid"))
+       {
+         char          essid[IW_ESSID_MAX_SIZE + 1];
 
-             wrq.u.data.pointer = (caddr_t) &range;
-             wrq.u.data.length = 0;
+         i++;
+         if(i >= count)
+           iw_usage();
+         if((!strcasecmp(args[i], "off")) ||
+            (!strcasecmp(args[i], "any")))
+           {
              wrq.u.data.flags = 0;
-             if(ioctl(skfd, SIOCGIWRANGE, &wrq) < 0)
+             essid[0] = '\0';
+           }
+         else
+           if(!strcasecmp(args[i], "on"))
+             {
+               /* Get old essid */
+               wrq.u.data.pointer = (caddr_t) essid;
+               wrq.u.data.length = 0;
+               wrq.u.data.flags = 0;
+               if(ioctl(skfd, SIOCGIWESSID, &wrq) < 0)
+                 {
+                   fprintf(stderr, "SIOCGIWESSID: %s\n", strerror(errno));
+                   return(-1);
+                 }
+               strcpy(wrq.ifr_name, ifname);
+               wrq.u.data.flags = 1;
+             }
+           else
+             if(strlen(args[i]) > IW_ESSID_MAX_SIZE)
                {
-                 fprintf(stderr, "SIOCGIWRANGE: %s\n", strerror(errno));
-                 return(-1);
+                 fprintf(stderr, "ESSID too long (max %d): ``%s''\n",
+                         IW_ESSID_MAX_SIZE, args[i]);
+                 iw_usage();
                }
+             else
+               {
+                 wrq.u.data.flags = 1;
+                 strcpy(essid, args[i]);
+               }
+
+         wrq.u.data.pointer = (caddr_t) essid;
+         wrq.u.data.length = strlen(essid) + 1;
+         if(ioctl(skfd, SIOCSIWESSID, &wrq) < 0)
+           {
+             fprintf(stderr, "SIOCSIWESSID: %s\n", strerror(errno));
+             return(-1);
+           }
+         continue;
+       }
+
+      /* ---------- Set AP address ---------- */
+      if(!strcasecmp(args[i], "ap"))
+       {
+         if(++i >= count)
+           iw_usage();
 
-             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 */
+         /* Check if we have valid address types */
+         if(check_addr_type(skfd, ifname) < 0)
+           {
+             fprintf(stderr, "%-8.8s  Interface doesn't support MAC & IP addresses\n", ifname);
+             return(-1);
            }
 
-         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;
+         /* Get the address */
+         if(in_addr(skfd, ifname, args[i++], &(wrq.u.ap_addr)) < 0)
+           iw_usage();
 
-         if(ioctl(skfd, SIOCSIWFREQ, &wrq) < 0)
+         if(ioctl(skfd, SIOCSIWAP, &wrq) < 0)
            {
-             fprintf(stderr, "SIOCSIWFREQ: %s\n", strerror(errno));
+             fprintf(stderr, "SIOCSIWAP: %s\n", strerror(errno));
              return(-1);
            }
          continue;
        }
+#endif /* WIRELESS_EXT > 5 */
 
-      /* Here we have an unrecognised arg... */
-      fprintf(stderr, "Invalid argument : %s\n", args[i]);
-      usage();
-      return(-1);
-    }          /* for(index ... */
-  return(0);
-}
+#if WIRELESS_EXT > 7
+      /* ---------- Set NickName ---------- */
+      if(!strncmp(args[i], "nick", 4))
+       {
+         i++;
+         if(i >= count)
+           iw_usage();
+         if(strlen(args[i]) > IW_ESSID_MAX_SIZE)
+           {
+             fprintf(stderr, "Name too long (max %d) : ``%s''\n",
+                     IW_ESSID_MAX_SIZE, args[i]);
+             iw_usage();
+           }
 
-static void
-print_devices(char *ifname)
-{
-  char buff[1024];
-  struct wireless_info info;
-  struct ifconf ifc;
-  struct ifreq *ifr;
-  int i;
+         wrq.u.data.pointer = (caddr_t) args[i];
+         wrq.u.data.length = strlen(args[i]) + 1;
+         if(ioctl(skfd, SIOCSIWNICKN, &wrq) < 0)
+           {
+             fprintf(stderr, "SIOCSIWNICKN: %s\n", strerror(errno));
+             return(-1);
+           }
+         continue;
+       }
 
-  if(ifname == (char *)NULL)
-    {
-      ifc.ifc_len = sizeof(buff);
-      ifc.ifc_buf = buff;
-      if(ioctl(skfd, SIOCGIFCONF, &ifc) < 0)
+      /* ---------- Set Bit-Rate ---------- */
+      if((!strncmp(args[i], "bit", 3)) ||
+        (!strcmp(args[i], "rate")))
        {
-         fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno));
-         return;
+         i++;
+         if(i >= count)
+           iw_usage();
+         if(!strcasecmp(args[i], "auto"))
+           {
+             wrq.u.bitrate.value = -1;
+             wrq.u.bitrate.fixed = 0;
+           }
+         else
+           {
+             if(!strcasecmp(args[i], "fixed"))
+               {
+                 /* Get old bitrate */
+                 if(ioctl(skfd, SIOCGIWRATE, &wrq) < 0)
+                   {
+                     fprintf(stderr, "SIOCGIWRATE: %s\n", strerror(errno));
+                     return(-1);
+                   }
+                 strcpy(wrq.ifr_name, ifname);
+               }
+             else                      /* Should be a numeric value */
+               {
+                 double                brate;
+
+                 if(sscanf(args[i], "%lg", &(brate)) != 1)
+                   iw_usage();
+                 if(index(args[i], 'G')) brate *= GIGA;
+                 if(index(args[i], 'M')) brate *= MEGA;
+                 if(index(args[i], 'k')) brate *= KILO;
+                 wrq.u.bitrate.value = (long) brate;
+               }
+             wrq.u.bitrate.fixed = 1;
+           }
+
+         if(ioctl(skfd, SIOCSIWRATE, &wrq) < 0)
+           {
+             fprintf(stderr, "SIOCSIWRATE: %s\n", strerror(errno));
+             return(-1);
+           }
+         continue;
        }
 
-      ifr = ifc.ifc_req;
-      for(i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++)
+      /* ---------- Set RTS threshold ---------- */
+      if(!strncmp(args[i], "rts", 3))
        {
-         if(get_info(ifr->ifr_name, &info) < 0)
+         i++;
+         if(i >= count)
+           iw_usage();
+         if(!strcasecmp(args[i], "auto"))
            {
-             /* Could skip this message ? */
-             fprintf(stderr, "%-8.8s  no wireless extensions.\n\n",
-                     ifr->ifr_name);
-             continue;
+             wrq.u.rts.value = -1;
+             wrq.u.rts.fixed = 0;
+           }
+         else
+           {
+             if(!strcasecmp(args[i], "fixed"))
+               {
+                 /* Get old RTS threshold */
+                 if(ioctl(skfd, SIOCGIWRTS, &wrq) < 0)
+                   {
+                     fprintf(stderr, "SIOCGIWRTS: %s\n", strerror(errno));
+                     return(-1);
+                   }
+                 strcpy(wrq.ifr_name, ifname);
+               }
+             else
+               if(!strcasecmp(args[i], "off"))
+                 wrq.u.rts.value = -1; /* i.e. max size */
+               else                    /* Should be a numeric value */
+                 if(sscanf(args[i], "%ld", (unsigned long *) &(wrq.u.rts.value))
+                    != 1)
+                   iw_usage();
+
+             wrq.u.rts.fixed = 1;
            }
 
-         print_info(&info);
+         if(ioctl(skfd, SIOCSIWRTS, &wrq) < 0)
+           {
+             fprintf(stderr, "SIOCSIWRTS: %s\n", strerror(errno));
+             return(-1);
+           }
+         continue;
        }
-    }
-  else
-    {
-      if(get_info(ifname, &info) < 0)
+
+      /* ---------- Set fragmentation threshold ---------- */
+      if(!strncmp(args[i], "frag", 4))
        {
-         fprintf(stderr, "%s: no wireless extensions.\n",
-                 ifname);
-         usage();
+         i++;
+         if(i >= count)
+           iw_usage();
+         if(!strcasecmp(args[i], "auto"))
+           {
+             wrq.u.frag.value = -1;
+             wrq.u.frag.fixed = 0;
+           }
+         else
+           {
+             if(!strcasecmp(args[i], "fixed"))
+               {
+                 /* Get old fragmentation threshold */
+                 if(ioctl(skfd, SIOCGIWFRAG, &wrq) < 0)
+                   {
+                     fprintf(stderr, "SIOCGIWFRAG: %s\n", strerror(errno));
+                     return(-1);
+                   }
+                 strcpy(wrq.ifr_name, ifname);
+               }
+             else
+               if(!strcasecmp(args[i], "off"))
+                 wrq.u.frag.value = -1;        /* i.e. max size */
+               else                    /* Should be a numeric value */
+                 if(sscanf(args[i], "%ld", (unsigned long *) &(wrq.u.frag.value))
+                    != 1)
+                   iw_usage();
+
+             wrq.u.frag.fixed = 1;
+           }
+
+         if(ioctl(skfd, SIOCSIWFRAG, &wrq) < 0)
+           {
+             fprintf(stderr, "SIOCSIWFRAG: %s\n", strerror(errno));
+             return(-1);
+           }
+         continue;
        }
-      else
-       print_info(&info);
-    }
+#endif /* WIRELESS_EXT > 7 */
+
+      /* Here we have an unrecognised arg... */
+      fprintf(stderr, "Invalid argument : %s\n", args[i]);
+      iw_usage();
+      return(-1);
+    }          /* for(index ... */
+  return(0);
 }
 
+/******************************* MAIN ********************************/
 
-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;
-}
-       
+/*------------------------------------------------------------------*/
+/*
+ * The main !
+ */
 int
 main(int       argc,
      char **   argv)
 {
+  int skfd = -1;               /* generic raw socket desc.     */
   int goterr = 0;
 
   /* Create a channel to the NET kernel. */
@@ -384,7 +877,16 @@ main(int   argc,
   /* No argument : show the list of all device + info */
   if(argc == 1)
     {
-      print_devices((char *)NULL);
+      print_devices(skfd);
+      close(skfd);
+      exit(0);
+    }
+
+  /* Special case for help... */
+  if((!strncmp(argv[1], "-h", 9)) ||
+     (!strcmp(argv[1], "--help")))
+    {
+      iw_usage();
       close(skfd);
       exit(0);
     }
@@ -392,16 +894,18 @@ main(int  argc,
   /* The device name must be the first argument */
   if(argc == 2)
     {
-      print_devices(argv[1]);
+      print_info(skfd, 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]);
+  goterr = set_info(skfd, argv + 2, argc - 2, argv[1]);
 
   /* Close the socket. */
   close(skfd);
 
   return(goterr);
 }
+
+
diff --git a/wireless_tools/iwpriv b/wireless_tools/iwpriv
new file mode 100644 (file)
index 0000000..4657f67
Binary files /dev/null and b/wireless_tools/iwpriv differ
diff --git a/wireless_tools/iwpriv.8 b/wireless_tools/iwpriv.8
new file mode 100644 (file)
index 0000000..8acc2e8
--- /dev/null
@@ -0,0 +1,113 @@
+.\" Jean II - HPLB - 96
+.\" iwpriv.8
+.\"
+.TH IWPRIV 8 "31 October 1996" "net-tools" "Linux Programmer's Manual"
+.\"
+.\" NAME part
+.\"
+.SH NAME
+iwpriv \- configure optionals (private) parameters of a wireless
+network interface
+.\"
+.\" SYNOPSIS part
+.\"
+.SH SYNOPSIS
+.BI "iwpriv [" interface ]
+.br
+.BI "iwpriv " interface " " private-command " [" private-parameters ]
+.br
+.BI "iwpriv " interface " roam " {on,off}
+.br
+.BI "iwpriv " interface " port " [ N ]
+.\"
+.\" DESCRIPTION part
+.\"
+.SH DESCRIPTION
+.B Iwpriv
+is the companion tool to
+.IR iwconfig (8).
+.B Iwpriv
+deals with parameters and setting specific to each driver (as opposed to
+.I iwconfig
+which deals with generic ones) and a few commands that doesn't fit well in
+.I iwconfig
+(like listing the available frequencies).
+.PP
+Without any argument,
+.B iwpriv
+list the available private commands available on each interface, and
+the parameters that they require. Using this information, the user may
+apply those interface specific commands on the specified interface.
+.PP
+In theory, the documentation of each device driver should indicate how
+to use those interface specific commands and their effect.
+.\"
+.\" PARAMETER part
+.\"
+.SH PARAMETERS
+.TP
+.B roam
+Enable or disable roaming, if supported. Call the private command
+.IR setroam .
+Found in the
+.I wavelan_cs
+driver.
+.TP
+.B port
+Read or configure the port type. Call the private commands
+.IR gport_type " and " sport_type .
+Found in the
+.IR wavelan2_cs " and " wvlan_cs " drivers."
+.TP
+.I private-command
+Execute the specified
+.I private-command
+on the interface. The command may take or require arguments, and may
+display information. Refer to the device driver documentation for
+information on how to use and the effect.
+.\"
+.\" DISPLAY part
+.\"
+.SH DISPLAY
+For each device which support private commands,
+.I iwpriv
+will display the list of private commands available.
+.PP
+This include the name of the private command, the number or arguments
+that may be set and their type, and the number or arguments that may
+be display and their type.
+.PP
+For example, you may have the following display :
+.br
+.B "eth0      Available private ioctl :"
+.br
+.B "          setqualthr (89F0) : set   1 byte & get   0"
+.br
+.B "          gethisto (89F7) : set   0      & get  16 int"
+.PP
+This indicate that you may set the quality threshold and display an
+histogram of up to 16 values with the following commands :
+.br
+.I "  iwpriv eth0 setqualthr 20"
+.br
+.I "  iwpriv eth0 gethisto"
+.\"
+.\" 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 iwconfig (8),
+.BR iwspy (8),
+.BR wavelan (4),
+.BR wavelan_cs (4),
+.BR xircnw_cs (4).
index 32034ba..3e22f4b 100644 (file)
 /*
- * Warning : this program need wireless extensions...
+ *     Wireless Tools
+ *
+ *             Jean II - HPLB '99
+ *
+ * Main code for "iwconfig". This is the generic tool for most
+ * manipulations...
+ * You need to link this code against "iwcommon.c" and "-lm".
  */
-#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()
+
+#include "iwcommon.h"          /* Header */
+
+/************************* MISC SUBROUTINES **************************/
+
+/*------------------------------------------------------------------*/
+/*
+ * Print usage string
+ */
+static void
+iw_usage(void)
 {
-       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;
+  fprintf(stderr, "Usage: iwpriv interface [private-command [private-arguments]]\n");
+  fprintf(stderr, "              interface [roam {on|off}]\n");
+  fprintf(stderr, "              interface [port [n]]\n");
+  exit(1);
 }
 
-int
-byte_size(args)
+/************************ GENERIC FUNCTIONS *************************/
+
+/*------------------------------------------------------------------*/
+/*
+ * Print on the screen in a neat fashion all the info we have collected
+ * on a device.
+ */
+static void
+print_priv_info(int            skfd,
+               char *          ifname)
 {
-  int  ret = args & IW_PRIV_SIZE_MASK;
+  int          k;
+  iwprivargs   priv[16];
+  int          n;
+  char *       argtype[] = { "    ", "byte", "char", "", "int", "float" };
 
-  if(((args & IW_PRIV_TYPE_MASK) == IW_PRIV_TYPE_INT) ||
-     ((args & IW_PRIV_TYPE_MASK) == IW_PRIV_TYPE_FLOAT))
-    ret <<= 2;
+  /* Read the private ioctls */
+  n = get_priv_info(skfd, ifname, priv);
+
+  /* Is there any ? */
+  if(n <= 0)
+    {
+      /* Could skip this message ? */
+      fprintf(stderr, "%-8.8s  no private ioctls.\n\n",
+             ifname);
+    }
+  else
+    {
+      printf("%-8.8s  Available private ioctl :\n", ifname);
+      /* Print the all */
+      for(k = 0; k < n; k++)
+       printf("          %s (%X) : 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]);
+      printf("\n");
+    }
+}
 
-  if((args & IW_PRIV_TYPE_MASK) == IW_PRIV_TYPE_NONE)
-    return 0;
+/*------------------------------------------------------------------*/
+/*
+ * Get info on all devices and print it on the screen
+ */
+static void
+print_priv_devices(int         skfd)
+{
+  char         buff[1024];
+  struct ifconf ifc;
+  struct ifreq *ifr;
+  int i;
+
+  /* Get list of active devices */
+  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;
 
-  return ret;
+  /* Print them */
+  for(i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++)
+    print_priv_info(skfd, ifr->ifr_name);
 }
 
-int
-main(int       argc,
-     char **   argv)
+/************************* SETTING ROUTINES **************************/
+
+/*------------------------------------------------------------------*/
+/*
+ * Execute a private command on the interface
+ */
+static int
+set_private(int                skfd,           /* Socket */
+           char *      args[],         /* Command line args */
+           int         count,          /* Args count */
+           char *      ifname)         /* Dev name */
 {
+  u_char       buffer[1024];
   struct iwreq         wrq;
-  char *               ifname = argv[1];
-  struct iw_priv_args  priv[16];
-  int                  k;
+  int          i = 0;          /* Start with first arg */
+  int          k;
+  iwprivargs   priv[16];
+  int          number;
 
-  if(argc < 2)
-    exit(0);
+  /* Read the private ioctls */
+  number = get_priv_info(skfd, ifname, priv);
 
-  /* Create a channel to the NET kernel. */
-  if((skfd = sockets_open()) < 0)
+  /* Is there any ? */
+  if(number <= 0)
     {
-      perror("socket");
-      exit(-1);
+      /* Could skip this message ? */
+      fprintf(stderr, "%-8.8s  no private ioctls.\n\n",
+             ifname);
+      return(-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)
+  /* Search the correct ioctl */
+  k = -1;
+  while((++k < number) && strcmp(priv[k].name, args[i]));
+
+  /* If not found... */
+  if(k == number)
     {
-      fprintf(stderr, "Interface doesn't provide private interface info...\n");
-      fprintf(stderr, "SIOCGIWPRIV: %s\n", strerror(errno));
+      fprintf(stderr, "Invalid command : %s\n", args[i]);
       return(-1);
     }
+         
+  /* Next arg */
+  i++;
 
-  /* If no args... */
-  if(argc < 3)
+  /* If we have to set some data */
+  if((priv[k].set_args & IW_PRIV_TYPE_MASK) &&
+     (priv[k].set_args & IW_PRIV_SIZE_MASK))
     {
-      char *   argtype[] = { "    ", "byte", "char", "", "int", "float" };
+      switch(priv[k].set_args & IW_PRIV_TYPE_MASK)
+       {
+       case IW_PRIV_TYPE_BYTE:
+         /* Number of args to fetch */
+         wrq.u.data.length = count - 1;
+         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 < wrq.u.data.length + 1; i++)
+           sscanf(args[i], "%d", (int *)(buffer + i - 1));
+         break;
+
+       case IW_PRIV_TYPE_INT:
+         /* Number of args to fetch */
+         wrq.u.data.length = count - 1;
+         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 < wrq.u.data.length + 1; i++)
+           sscanf(args[i], "%d", ((u_int *) buffer) + i - 1);
+         break;
+
+       case IW_PRIV_TYPE_CHAR:
+         if(i < count)
+           {
+             /* Size of the string to fetch */
+             wrq.u.data.length = strlen(args[i]) + 1;
+             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;
 
-      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]);
+             /* Fetch string */
+             memcpy(buffer, args[i], wrq.u.data.length);
+             buffer[sizeof(buffer) - 1] = '\0';
+             i++;
+           }
+         else
+           {
+             wrq.u.data.length = 1;
+             buffer[0] = '\0';
+           }
+         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
     {
-      u_char   buffer[1024];
+      wrq.u.data.pointer = (caddr_t) buffer;
+      wrq.u.data.flags = 0;
+    }
 
-      /* 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;
+  /* Perform the private ioctl */
+  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);
+    }
 
-         /* Warning : we may have no args to set... */
+  /* 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      j;
+      int      n = 0;          /* number of args */
 
-         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;
+      printf("%-8.8s  %s:", ifname, priv[k].name);
 
-             /* Fetch args */
-             for(i = 0; i < wrq.u.data.length; i++)
-               sscanf(argv[i + 3], "%d", buffer + i);
-             break;
+      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;
 
-           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;
+      switch(priv[k].get_args & IW_PRIV_TYPE_MASK)
+       {
+       case IW_PRIV_TYPE_BYTE:
+         /* Display args */
+         for(j = 0; j < n; j++)
+           printf("%d  ", buffer[j]);
+         printf("\n");
+         break;
+
+       case IW_PRIV_TYPE_INT:
+         /* Display args */
+         for(j = 0; j < n; j++)
+           printf("%d  ", ((u_int *) buffer)[i]);
+         printf("\n");
+         break;
+
+       case IW_PRIV_TYPE_CHAR:
+         /* Display args */
+         buffer[wrq.u.data.length - 1] = '\0';
+         printf("%s\n", buffer);
+         break;
+
+       default:
+         fprintf(stderr, "Not yet implemented...\n");
+         return(-1);
+       }
+    }  /* if args to set */
 
-             /* Fetch args */
-             for(i = 0; i < wrq.u.data.length; i++)
-               sscanf(argv[i + 3], "%d", ((u_int *) buffer) + i);
-             break;
+  return(0);
+}
 
-           default:
-             fprintf(stderr, "Not yet implemented...\n");
-             return(-1);
-           }
+/********************** PRIVATE IOCTLS MANIPS ***********************/
+/*
+ * Convenient access to some private ioctls of some devices
+ */
 
-         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
+/*------------------------------------------------------------------*/
+/*
+ * Set roaming mode on and off
+ * Found in wavelan_cs driver
+ */
+static int
+set_roaming(int                skfd,           /* Socket */
+           char *      args[],         /* Command line args */
+           int         count,          /* Args count */
+           char *      ifname)         /* Dev name */
+{
+  u_char       buffer[1024];
+  struct iwreq         wrq;
+  int          i = 0;          /* Start with first arg */
+  int          k;
+  iwprivargs   priv[16];
+  int          number;
+  char         RoamState;              /* buffer to hold new roam state */
+  char         ChangeRoamState=0;      /* whether or not we are going to
+                                          change roam states */
+
+  /* Read the private ioctls */
+  number = get_priv_info(skfd, ifname, priv);
+
+  /* Is there any ? */
+  if(number <= 0)
+    {
+      /* Could skip this message ? */
+      fprintf(stderr, "%-8.8s  no private ioctls.\n\n",
+             ifname);
+      return(-1);
+    }
+
+  if(count != 1)
+    iw_usage();
+
+  if(!strcasecmp(args[i], "on"))
+    {
+      printf("%-8.8s  enable roaming\n", ifname);
+      if(!number)
        {
-         wrq.u.data.length = 0L;
+         fprintf(stderr, "This device doesn't support roaming\n");
+         return(-1);
+       }
+      ChangeRoamState=1;
+      RoamState=1;
+    }
+  else
+    if(!strcasecmp(args[i], "off"))
+      {
+       i++;
+       printf("%-8.8s  disable roaming\n",  ifname);
+       if(!number)
+         {
+           fprintf(stderr, "This device doesn't support roaming\n");
+           return(-1);
+         }
+       ChangeRoamState=1;
+       RoamState=0;
+      }
+    else
+      {
+       iw_usage();
+       return(-1);
+      }
+
+  if(ChangeRoamState)
+    {
+      k = -1;
+      while((++k < number) && strcmp(priv[k].name, "setroam"));
+      if(k == number)
+       {
+         fprintf(stderr, "This device doesn't support roaming\n");
+         return(-1);
        }
-
       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
+      buffer[0]=RoamState;
+
+      memcpy(wrq.u.name, &buffer, IFNAMSIZ);
+
+      if(ioctl(skfd, priv[k].cmd, &wrq) < 0)
        {
-         wrq.u.data.pointer = (caddr_t) buffer;
-         wrq.u.data.flags = 0;
+         fprintf(stderr, "Roaming support is broken.\n");
+         exit(0);
        }
+    }
+  i++;
 
-      if(ioctl(skfd, priv[k].cmd, &wrq) < 0)
+  return(i);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Get and set the port type
+ * Found in wavelan2_cs and wvlan_cs drivers
+ */
+static int
+port_type(int          skfd,           /* Socket */
+         char *        args[],         /* Command line args */
+         int           count,          /* Args count */
+         char *        ifname)         /* Dev name */
+{
+  struct iwreq wrq;
+  int          i = 0;          /* Start with first arg */
+  int          k;
+  iwprivargs   priv[16];
+  int          number;
+  char         ptype = 0;
+
+  /* Read the private ioctls */
+  number = get_priv_info(skfd, ifname, priv);
+
+  /* Is there any ? */
+  if(number <= 0)
+    {
+      /* Could skip this message ? */
+      fprintf(stderr, "%-8.8s  no private ioctls.\n\n", ifname);
+      return(-1);
+    }
+
+  /* Arguments ? */
+  if(count == 0)
+    {
+      /* So, we just want to see the current value... */
+      k = -1;
+      while((++k < number) && strcmp(priv[k].name, "gport_type"));
+      if(k == number)
        {
-         fprintf(stderr, "Interface doesn't accept private ioctl...\n");
-         fprintf(stderr, "%X: %s\n", priv[k].cmd, strerror(errno));
+         fprintf(stderr, "This device doesn't support getting port type\n");
          return(-1);
        }
+      strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
 
-      /* If we have to get some data */
-      if((priv[k].get_args & IW_PRIV_TYPE_MASK) &&
-        (priv[k].get_args & IW_PRIV_SIZE_MASK))
+      /* Get it */
+      if(ioctl(skfd, priv[k].cmd, &wrq) < 0)
        {
-         int   i;
-         int   n;              /* number of args */
+         fprintf(stderr, "Port type support is broken.\n");
+         exit(0);
+       }
+      ptype = *wrq.u.name;
 
-         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;
+      /* Display it */
+      printf("%-8.8s  Port type is %d.\n\n", ifname, ptype);
 
-         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);
-           }
+      return(0);
+    }
+
+  if(count != 1)
+    iw_usage();
+
+  /* Read it */
+  if(sscanf(args[i], "%d", (int *) &ptype) != 1)
+    iw_usage();
+  
+  k = -1;
+  while((++k < number) && strcmp(priv[k].name, "sport_type"));
+  if(k == number)
+    {
+      fprintf(stderr, "This device doesn't support setting port type\n");
+      return(-1);
+    }
+  strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
+
+  *(wrq.u.name) = ptype;
+
+  if(ioctl(skfd, priv[k].cmd, &wrq) < 0)
+    {
+      fprintf(stderr, "Invalid port type\n");
+      exit(0);
+    }
+
+  i++;
+  return(i);
+}
+
+/******************************* MAIN ********************************/
+
+/*------------------------------------------------------------------*/
+/*
+ * The main !
+ */
+int
+main(int       argc,
+     char **   argv)
+{
+  int skfd = -1;               /* generic raw socket desc.     */
+  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_priv_devices(skfd);
+      close(skfd);
+      exit(0);
+    }
 
-       }       /* if args to set */
+  /* Special cases take one... */
+  /* Help */
+  if((!strncmp(argv[1], "-h", 9)) ||
+     (!strcmp(argv[1], "--help")))
+    {
+      iw_usage();
+      close(skfd);
+      exit(0);
+    }
+
+  /* The device name must be the first argument */
+  /* Name only : show for that device only */
+  if(argc == 2)
+    {
+      print_priv_info(skfd, argv[1]);
+      close(skfd);
+      exit(0);
+    }
+
+  /* Special cases take two... */
+  /* Roaming */
+  if(!strncmp(argv[2], "roam", 4))
+    {
+      goterr = set_roaming(skfd, argv + 3, argc - 3, argv[1]);
+      close(skfd);
+      exit(0);
+    }
+
+  /* Port type */
+  if(!strncmp(argv[2], "port", 4))
+    {
+      goterr = port_type(skfd, argv + 3, argc - 3, argv[1]);
+      close(skfd);
+      exit(0);
+    }
 
-    }  /* if ioctl list else ioctl exec */
+  /* Otherwise, it's a private ioctl */
+  goterr = set_private(skfd, argv + 2, argc - 2, argv[1]);
 
   /* Close the socket. */
   close(skfd);
diff --git a/wireless_tools/iwspy b/wireless_tools/iwspy
new file mode 100644 (file)
index 0000000..f857716
Binary files /dev/null and b/wireless_tools/iwspy differ
index 099e227..0a4c243 100644 (file)
@@ -13,9 +13,15 @@ iwspy \- Get wireless statistics from specific nodes
 .SH SYNOPSIS
 .BI "iwspy " interface
 .br
-.BI "iwspy " interface " [+] " IPADDR " | hw " HWADDR " [...]"
+.BI "iwspy " interface " [+] " IPADDR " | " HWADDR " [...]"
 .br
 .BI "iwspy " interface " off"
+.br
+.BI "iwspy " interface " freq"
+.br
+.BI "iwspy " interface " ap"
+.br
+.BI "iwspy " interface " rate"
 .\"
 .\" DESCRIPTION part
 .\"
@@ -29,6 +35,10 @@ information is the same as the one available in
 .PP
 This information is updated each time a new packet is received, so
 each address of the list add some overhead in the driver.
+.PP
+.B Iwspy
+Can also display the list of frequencies available for the device or the
+list of Access Points in range.
 .\"
 .\" PARAMETER part
 .\"
@@ -36,7 +46,8 @@ each address of the list add some overhead in the driver.
 You may set any number of addresses up to 8.
 .TP
 .B IPADDR
-Set an IP address. As the hardware work with hardware addresses,
+Set an IP address, or in some cases a domain name. As the hardware
+work with hardware addresses,
 .B iwspy
 will translate this address through
 .IR ARP .
@@ -46,9 +57,11 @@ will fail. In those case,
 .IR ping (8)
 this address and retry.
 .TP
-.B hw HWADDR
+.B HWADDR
 Set a hardware (MAC) address (this address is not translated & checked
-like the IP one).
+like the IP one). The address must contain a semicolon
+.RB ( : )
+to be recognised as a hardware address.
 .TP
 .B +
 Add the new set of addresses at the end of the current list instead of
@@ -56,7 +69,21 @@ 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
+Remove the current list of addresses and disable the spy functionality
+.TP
+.B freq
+Give the list of available frequencies in the device and the number of
+defined channels. Please note that usually the driver returns the
+total number of channels and only the frequencies available in the
+present locale, so there is no one to one mapping between frequencies
+displayed and channel numbers.
+.TP
+.B ap
+Give the list of Access Points in range, and optionally the quality of
+link to them.
+.TP
+.BR rate / bit [ rate ]
+List the bit-rates supported by the device.
 .\"
 .\" FILES part
 .\"
index 3e66a86..dd2d604 100644 (file)
 /*
- * Warning : this program need to be link against libsupport.a
- * in net-tools-1.2.0
- * This program need also wireless extensions...
+ *     Wireless Tools
+ *
+ *             Jean II - HPLB '99
+ *
+ * Main code for "iwconfig". This is the generic tool for most
+ * manipulations...
+ * You need to link this code against "iwcommon.c" and "-lm".
  */
-#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()
+
+#include "iwcommon.h"          /* Header */
+
+/************************* DISPLAY ROUTINES **************************/
+
+/*------------------------------------------------------------------*/
+/*
+ * Display the spy list of addresses and the associated stats
+ */
+static void
+print_spy_info(int     skfd,
+              char *   ifname)
 {
-       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;
+  struct iwreq         wrq;
+  char         buffer[(sizeof(struct iw_quality) +
+                       sizeof(struct sockaddr)) * IW_MAX_SPY];
+  struct sockaddr      hwa[IW_MAX_SPY];
+  struct iw_quality    qual[IW_MAX_SPY];
+  iwrange      range;
+  int          has_range = 0;
+  int          n;
+  int          i;
+
+  /* Collect stats */
+  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, "%-8.8s  Interface doesn't support wireless statistic collection\n\n", ifname);
+      return;
+    }
+
+  /* Number of addresses */
+  n = wrq.u.data.length;
+
+
+
+  /* Check if we have valid address types */
+  if(check_addr_type(skfd, ifname) < 0)
+    {
+      fprintf(stderr, "%-8.8s  Interface doesn't support MAC & IP addresses\n\n", ifname);
+      return;
+    }
+
+  /* Get range info if we can */
+  if(get_range_info(skfd, ifname, &(range)) >= 0)
+    has_range = 1;
+
+  /* Display it */
+  if(n == 0)
+    printf("%-8.8s  No statistics to collect\n", ifname);
+  else
+    printf("%-8.8s  Statistics collected:\n", ifname);
+  /* The two lists */
+
+  memcpy(hwa, buffer, n * sizeof(struct sockaddr));
+  memcpy(qual, buffer + n*sizeof(struct sockaddr), n*sizeof(struct iw_quality));
+
+  for(i = 0; i < n; i++)
+    {
+      if(has_range && (qual[i].level != 0))
+       /* If the statistics are in dBm */
+       if(qual[i].level > range.max_qual.level)
+         printf("    %s : Quality %d/%d ; Signal %d dBm ; Noise %d dBm %s\n",
+                pr_ether(hwa[i].sa_data),
+                qual[i].qual, range.max_qual.qual,
+                qual[i].level - 0x100, qual[i].noise - 0x100,
+                qual[i].updated & 0x7 ? "(updated)" : "");
+       else
+         printf("    %s : Quality %d/%d ; Signal %d/%d ; Noise %d/%d %s\n",
+                pr_ether(hwa[i].sa_data),
+                qual[i].qual, range.max_qual.qual,
+                qual[i].level, range.max_qual.level,
+                qual[i].noise, range.max_qual.noise,
+                qual[i].updated & 0x7 ? "(updated)" : "");
+      else
+       printf("    %s : Quality %d ; Signal %d ; Noise %d %s\n",
+              pr_ether(hwa[i].sa_data),
+              qual[i].qual, qual[i].level, qual[i].noise,
+              qual[i].updated & 0x7 ? "(updated)" : "");
+    }
+  printf("\n");
 }
 
-int
-main(int       argc,
-     char **   argv)
+/*------------------------------------------------------------------*/
+/*
+ * Get info on all devices and print it on the screen
+ */
+static void
+print_spy_devices(int          skfd)
+{
+  char         buff[1024];
+  struct ifconf ifc;
+  struct ifreq *ifr;
+  int i;
+
+  /* Get list of active devices */
+  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;
+
+  /* Print them */
+  for(i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++)
+    print_spy_info(skfd, ifr->ifr_name);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Print the number of channels and available frequency for the device
+ */
+static void
+print_freq_info(int            skfd,
+               char *          ifname)
 {
-  struct ifreq         ifr;
   struct iwreq         wrq;
-  struct aftype *ap;
-  struct hwtype *hw;
-  char *       ifname = argv[1];
+  float                        freq;
+  struct iw_range      range;
+  int                  k;
+
+  strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
+  wrq.u.data.pointer = (caddr_t) &range;
+  wrq.u.data.length = 0;
+  wrq.u.data.flags = 0;
+  if(ioctl(skfd, SIOCGIWRANGE, &wrq) < 0)
+      fprintf(stderr, "%-8.8s  no frequency information.\n\n",
+                     ifname);
+  else
+    {
+      if(range.num_frequency > 0)
+       {
+         printf("%-8.8s  %d channels in total; available frequencies :\n",
+                ifname, range.num_channels);
+         /* Print them all */
+         for(k = 0; k < range.num_frequency; k++)
+           {
+#if WIRELESS_EXT > 7
+               printf("\t  Channel %.2d : ", range.freq[k].i);
+#else
+               printf("\t  ");
+#endif
+             freq = freq2float(&(range.freq[k]));
+             if(freq >= GIGA)
+               printf("%g GHz\n", freq / GIGA);
+             else
+               if(freq >= MEGA)
+                 printf("%g MHz\n", freq / MEGA);
+               else
+                 printf("%g kHz\n", freq / KILO);
+           }
+         printf("\n\n");
+       }
+      else
+       printf("%-8.8s  %d channels\n\n",
+              ifname, range.num_channels);
+    }
+}
 
-  if(argc < 2)
-    exit(0);
+/*------------------------------------------------------------------*/
+/*
+ * Get frequency info on all devices and print it on the screen
+ */
+static void
+print_freq_devices(int         skfd)
+{
+  char         buff[1024];
+  struct ifconf ifc;
+  struct ifreq *ifr;
+  int i;
+
+  /* Get list of active devices */
+  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;
 
-  /* Create a channel to the NET kernel. */
-  if((skfd = sockets_open()) < 0)
+  /* Print them */
+  for(i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++)
+    print_freq_info(skfd, ifr->ifr_name);
+}
+
+#if WIRELESS_EXT > 5
+/*------------------------------------------------------------------*/
+/*
+ * Display the list of ap addresses and the associated stats
+ * Exacly the same as the spy list, only with different IOCTL and messages
+ */
+static void
+print_ap_info(int      skfd,
+              char *   ifname)
+{
+  struct iwreq         wrq;
+  char         buffer[(sizeof(struct iw_quality) +
+                       sizeof(struct sockaddr)) * IW_MAX_AP];
+  struct sockaddr *    hwa;
+  struct iw_quality *  qual;
+  iwrange      range;
+  int          has_range = 0;
+  int          has_qual = 0;
+  int          n;
+  int          i;
+
+  /* Collect stats */
+  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, SIOCGIWAPLIST, &wrq) < 0)
     {
-      perror("socket");
-      exit(-1);
+      fprintf(stderr, "%-8.8s  Interface doesn't have a list of Access Points\n\n", ifname);
+      return;
     }
 
-  /* 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))
+  /* Number of addresses */
+  n = wrq.u.data.length;
+  has_qual = wrq.u.data.flags;
+
+  /* The two lists */
+  hwa = (struct sockaddr *) buffer;
+  qual = (struct iw_quality *) (buffer + (sizeof(struct sockaddr) * n));
+
+  /* Check if we have valid address types */
+  if(check_addr_type(skfd, ifname) < 0)
     {
-      /* Deep trouble... */
-      fprintf(stderr, "Interface %s unavailable\n", ifname);
-      exit(0);
+      fprintf(stderr, "%-8.8s  Interface doesn't support MAC & IP addresses\n\n", ifname);
+      return;
     }
 
-#ifdef DEBUG
-  printf("Interface : %d - %s - %s\n", ifr.ifr_addr.sa_family,
-        ap->name, ap->sprint(&ifr.ifr_addr, 1));
-#endif
+  /* Get range info if we can */
+  if(get_range_info(skfd, ifname, &(range)) >= 0)
+    has_range = 1;
 
-  /* 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))
+  /* Display it */
+  if(n == 0)
+    printf("%-8.8s  No Access Point in range\n", ifname);
+  else
+    printf("%-8.8s  Access Points in range:\n", ifname);
+  for(i = 0; i < n; i++)
     {
-      /* Deep trouble... */
-      fprintf(stderr, "Unable to get hardware address of the interface %s\n",
-            ifname);
-      exit(0);
+      if(has_qual)
+       if(has_range)
+         /* If the statistics are in dBm */
+         if(qual[i].level > range.max_qual.level)
+           printf("    %s : Quality %d/%d ; Signal %d dBm ; Noise %d dBm %s\n",
+                  pr_ether(hwa[i].sa_data),
+                  qual[i].qual, range.max_qual.qual,
+                  qual[i].level - 0x100, qual[i].noise - 0x100,
+                  qual[i].updated & 0x7 ? "(updated)" : "");
+         else
+           printf("    %s : Quality %d/%d ; Signal %d/%d ; Noise %d/%d %s\n",
+                  pr_ether(hwa[i].sa_data),
+                  qual[i].qual, range.max_qual.qual,
+                  qual[i].level, range.max_qual.level,
+                  qual[i].noise, range.max_qual.noise,
+                  qual[i].updated & 0x7 ? "(updated)" : "");
+       else
+         printf("    %s : Quality %d ; Signal %d ; Noise %d %s\n",
+                pr_ether(hwa[i].sa_data),
+                qual[i].qual, qual[i].level, qual[i].noise,
+                qual[i].updated & 0x7 ? "(updated)" : "");
+      else
+       printf("    %s\n", pr_ether(hwa[i].sa_data));
     }
+  printf("\n");
+}
 
-#ifdef DEBUG
-  printf("Hardware : %d - %s - %s\n", ifr.ifr_hwaddr.sa_family,
-        hw->name, hw->print(ifr.ifr_hwaddr.sa_data));
-#endif
+/*------------------------------------------------------------------*/
+/*
+ * Get list of AP on all devices and print it on the screen
+ */
+static void
+print_ap_devices(int           skfd)
+{
+  char         buff[1024];
+  struct ifconf ifc;
+  struct ifreq *ifr;
+  int i;
+
+  /* Get list of active devices */
+  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;
+
+  /* Print them */
+  for(i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++)
+    print_ap_info(skfd, ifr->ifr_name);
+}
+#endif /* WIRELESS_EXT > 5 */
 
-  /* 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;
+#if WIRELESS_EXT > 7
+/*------------------------------------------------------------------*/
+/*
+ * Print the number of available bitrates for the device
+ */
+static void
+print_bitrate_info(int         skfd,
+                  char *       ifname)
+{
+  struct iwreq         wrq;
+  float                        bitrate;
+  struct iw_range      range;
+  int                  k;
+
+  strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
+  wrq.u.data.pointer = (caddr_t) &range;
+  wrq.u.data.length = 0;
+  wrq.u.data.flags = 0;
+  if(ioctl(skfd, SIOCGIWRANGE, &wrq) < 0)
+      fprintf(stderr, "%-8.8s  no bit-rate information.\n\n",
+                     ifname);
+  else
+    {
+      if((range.num_bitrates > 0) && (range.num_bitrates < IW_MAX_BITRATES))
+       {
+         printf("%-8.8s  %d available bit-rates :\n",
+                ifname, range.num_bitrates);
+         /* Print them all */
+         for(k = 0; k < range.num_bitrates; k++)
+           {
+             printf("\t  ");
+             bitrate = range.bitrate[k];
+             if(bitrate >= GIGA)
+               printf("%g Gb/s\n", bitrate / GIGA);
+             else
+               if(bitrate >= MEGA)
+                 printf("%g Mb/s\n", bitrate / MEGA);
+               else
+                 printf("%g kb/s\n", bitrate / KILO);
+           }
+         printf("\n\n");
+       }
+      else
+       printf("%-8.8s  No bit-rates ? Please update driver...\n\n", ifname);
+    }
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Get bit-rate info on all devices and print it on the screen
+ */
+static void
+print_bitrate_devices(int              skfd)
+{
+  char         buff[1024];
+  struct ifconf ifc;
+  struct ifreq *ifr;
+  int i;
+
+  /* Get list of active devices */
+  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;
+
+  /* Print them */
+  for(i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++)
+    print_bitrate_info(skfd, ifr->ifr_name);
+}
+#endif /* WIRELESS_EXT > 7 */
+
+/************************* SETTING ROUTINES **************************/
+
+/*------------------------------------------------------------------*/
+/*
+ * Set list of addresses specified on command line in the driver.
+ */
+static int
+set_spy_info(int               skfd,           /* The socket */
+            char *             args[],         /* Command line args */
+            int                count,          /* Args count */
+            char *             ifname)         /* Dev name */
+{
+  struct iwreq         wrq;
+  int                  i;
+  int                  nbr;            /* Number of valid addresses */
+  struct sockaddr      hw_address[IW_MAX_SPY];
+
+  /* Read command line */
+  i = 0;       /* first arg to read */
+  nbr = 0;     /* Number of args readen so far */
+
+  /* Check if we have valid address types */
+  if(check_addr_type(skfd, ifname) < 0)
+    {
+      fprintf(stderr, "%-8.8s  Interface doesn't support MAC & IP addresses\n", ifname);
+      return(-1);
+    }
+
+  /* "off" : disable functionality (set 0 addresses) */
+  if(!strcmp(args[0], "off"))
+    i = count; /* hack */
+
+  /* "+" : add all addresses already in the driver */
+  if(!strcmp(args[0], "+"))
+    {
+      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;
@@ -121,147 +436,162 @@ main(int        argc,
          return(-1);
        }
 
-      n = wrq.u.data.length;
+      /* Copy old addresses */
+      nbr = wrq.u.data.length;
+      memcpy(hw_address, buffer, nbr * sizeof(struct sockaddr));
 
-      hwa = (struct sockaddr *) buffer;
-      qual = (struct iw_quality *) (buffer + (sizeof(struct sockaddr) * n));
+      i = 1;   /* skip the "+" */
+    }
 
-      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)" : "");
+  /* Read other args on command line */
+  while((i < count) && (nbr < IW_MAX_SPY))
+    {
+      if(in_addr(skfd, ifname, args[i++], &(hw_address[nbr])) < 0)
+       continue;
+      nbr++;
     }
-  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));
+  /* Check the number of addresses */
+  if((nbr == 0) && strcmp(args[0], "off"))
+    {
+      fprintf(stderr, "No valid addresses found : exiting...\n");
+      exit(0);
+    }
 
-         i = 3;        /* skip the "+" */
-       }
+  /* Check if there is some remaining arguments */
+  if(i < count)
+    {
+      fprintf(stderr, "Got only the first %d addresses, remaining discarded\n", IW_MAX_SPY);
+    }
 
-      /* 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 */
+  /* 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);
+    }
 
+  return(0);
+}
 
-      /* Check the number of addresses */
-      if((nbr == 0) && strcmp(argv[2], "off"))
-       {
-         fprintf(stderr, "No valid addresses found : exiting...\n");
-         exit(0);
-       }
+/******************************* MAIN ********************************/
 
-      /* Check if there is some remaining arguments */
-      if(i < argc)
-       {
-         fprintf(stderr, "Got only the first %d addresses, remaining discarded\n", IW_MAX_SPY);
-       }
+/*------------------------------------------------------------------*/
+/*
+ * The main !
+ */
+int
+main(int       argc,
+     char **   argv)
+{
+  int skfd = -1;               /* generic raw socket desc.     */
+  int goterr = 0;
 
-      /* 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);
-       }
+  /* 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_spy_devices(skfd);
+      close(skfd);
+      exit(0);
+    }
+
+  /* Special cases take one... */
+  /* Help */
+  if((!strncmp(argv[1], "-h", 9)) ||
+     (!strcmp(argv[1], "--help")))
+    {
+      fprintf(stderr, "Usage: iwspy interface [+] [MAC address] [IP address]\n");
+      fprintf(stderr, "             interface [freq]\n");
+      fprintf(stderr, "             interface [ap]\n");
+      close(skfd);
+      exit(0);
     }
 
+  /* Frequency list */
+  if((!strncmp(argv[1], "freq", 4)) ||
+     (!strncmp(argv[1], "channel", 7)))
+    {
+      print_freq_devices(skfd);
+      close(skfd);
+      exit(0);
+    }
+
+#if WIRELESS_EXT > 5
+  /* Access Point list */
+  if(!strcasecmp(argv[1], "ap"))
+    {
+      print_ap_devices(skfd);
+      close(skfd);
+      exit(0);
+    }
+#endif /* WIRELESS_EXT > 5 */
+
+#if WIRELESS_EXT > 7
+  /* Bit-rate list */
+  if((!strncmp(argv[1], "bit", 3)) ||
+     (!strcmp(argv[1], "rate")))
+    {
+      print_bitrate_devices(skfd);
+      close(skfd);
+      exit(0);
+    }
+#endif /* WIRELESS_EXT > 7 */
+
+  /* The device name must be the first argument */
+  /* Name only : show spy list for that device only */
+  if(argc == 2)
+    {
+      print_spy_info(skfd, argv[1]);
+      close(skfd);
+      exit(0);
+    }
+
+  /* Special cases take two... */
+  /* Frequency list */
+  if((!strncmp(argv[2], "freq", 4)) ||
+     (!strncmp(argv[2], "channel", 7)))
+    {
+      print_freq_info(skfd, argv[1]);
+      close(skfd);
+      exit(0);
+    }
+
+#if WIRELESS_EXT > 5
+  /* Access Point  list */
+  if(!strcasecmp(argv[2], "ap"))
+    {
+      print_ap_info(skfd, argv[1]);
+      close(skfd);
+      exit(0);
+    }
+#endif /* WIRELESS_EXT > 5 */
+
+#if WIRELESS_EXT > 7
+  /* Access Point  list */
+  if((!strncmp(argv[2], "bit", 3)) ||
+     (!strcmp(argv[2], "rate")))
+    {
+      print_bitrate_info(skfd, argv[1]);
+      close(skfd);
+      exit(0);
+    }
+#endif /* WIRELESS_EXT > 7 */
+
+  /* Otherwise, it's a list of address to set in the spy list */
+  goterr = set_spy_info(skfd, argv + 2, argc - 2, argv[1]);
+
   /* Close the socket. */
   close(skfd);
 
diff --git a/wireless_tools/wireless.h b/wireless_tools/wireless.h
new file mode 100644 (file)
index 0000000..0be1d51
--- /dev/null
@@ -0,0 +1,347 @@
+/*
+ * This file define a set of standard wireless extensions
+ *
+ * Version :   7       23.4.99
+ *
+ * Authors :   Jean Tourrilhes - HPLB - <jt@hplb.hpl.hp.com>
+ */
+
+#ifndef _LINUX_WIRELESS_H
+#define _LINUX_WIRELESS_H
+
+/************************** DOCUMENTATION **************************/
+/*
+ * Basically, the wireless extensions are for now a set of standard ioctl
+ * call + /proc/net/wireless
+ *
+ * The entry /proc/net/wireless give statistics and information on the
+ * driver.
+ * This is better than having each driver having its entry because
+ * its centralised and we may remove the driver module safely.
+ *
+ * Ioctl are used to configure the driver and issue commands.  This is
+ * better than command line options of insmod because we may want to
+ * change dynamically (while the driver is running) some parameters.
+ *
+ * The ioctl mechanimsm are copied from standard devices ioctl.
+ * We have the list of command plus a structure descibing the
+ * data exchanged...
+ * Note that to add these ioctl, I was obliged to modify :
+ *     net/core/dev.c (two place + add include)
+ *     net/ipv4/af_inet.c (one place + add include)
+ *
+ * /proc/net/wireless is a copy of /proc/net/dev.
+ * We have a structure for data passed from the driver to /proc/net/wireless
+ * Too add this, I've modified :
+ *     net/core/dev.c (two other places)
+ *     include/linux/netdevice.h (one place)
+ *     include/linux/proc_fs.h (one place)
+ *
+ * Do not add here things that are redundant with other mechanisms
+ * (drivers init, ifconfig, /proc/net/dev, ...) and with are not
+ * wireless specific.
+ *
+ * These wireless extensions are not magic : each driver has to provide
+ * support for them...
+ *
+ * IMPORTANT NOTE : As everything in the kernel, this is very much a
+ * work in progress. Contact me if you have ideas of improvements...
+ */
+
+/***************************** INCLUDES *****************************/
+
+#if 0
+#include <linux/types.h>               /* for "caddr_t" et al          */
+#include <linux/socket.h>              /* for "struct sockaddr" et al  */
+#include <linux/if.h>                  /* for IFNAMSIZ and co... */
+#endif
+
+/**************************** CONSTANTS ****************************/
+
+/* --------------------------- VERSION --------------------------- */
+/*
+ * This constant is used to know the availability of the wireless
+ * extensions and to know which version of wireless extensions it is
+ * (there is some stuff that will be added in the future...)
+ * I just plan to increment with each new version.
+ */
+#define WIRELESS_EXT   6
+
+/*
+ * Changes :
+ *
+ * V2 to V3
+ * --------
+ *     Alan Cox start some incompatibles changes. I've integrated a bit more.
+ *     - Encryption renamed to Encode to avoid US regulation problems
+ *     - Frequency changed from float to struct to avoid problems on old 386
+ *
+ * V3 to V4
+ * --------
+ *     - Add sensitivity
+ *
+ * V4 to V5
+ * --------
+ *     - Missing encoding definitions in range
+ *     - Access points stuff
+ *
+ * V5 to V6
+ * --------
+ *     - 802.11 support (ESSID ioctls)
+ *
+ * V6 to V7
+ * --------
+ *     - define IW_ESSID_MAX_SIZE and IW_MAX_AP
+ */
+
+/* -------------------------- IOCTL LIST -------------------------- */
+
+/* Basic operations */
+#define SIOCSIWNAME    0x8B00          /* Unused ??? */
+#define SIOCGIWNAME    0x8B01          /* get name */
+#define SIOCSIWNWID    0x8B02          /* set network id */
+#define SIOCGIWNWID    0x8B03          /* get network id */
+#define SIOCSIWFREQ    0x8B04          /* set channel/frequency */
+#define SIOCGIWFREQ    0x8B05          /* get channel/frequency */
+#define SIOCSIWENCODE  0x8B06          /* set encoding info */
+#define SIOCGIWENCODE  0x8B07          /* get encoding info */
+#define SIOCSIWSENS    0x8B08          /* set sensitivity */
+#define SIOCGIWSENS    0x8B09          /* get sensitivity */
+
+/* Informative stuff */
+#define SIOCSIWRANGE   0x8B0A          /* Unused ??? */
+#define SIOCGIWRANGE   0x8B0B          /* Get range of parameters */
+#define SIOCSIWPRIV    0x8B0C          /* Unused ??? */
+#define SIOCGIWPRIV    0x8B0D          /* get private ioctl interface info */
+
+/* Mobile IP support */
+#define SIOCSIWSPY     0x8B10          /* set spy addresses */
+#define SIOCGIWSPY     0x8B11          /* get spy info (quality of link) */
+
+/* Access Point manipulation */
+#define SIOCSIWAP      0x8B14          /* set access point hardware addresses */
+#define SIOCGIWAP      0x8B15          /* get access point hardware addresses */
+#define SIOCGIWAPLIST  0x8B17          /* get list of access point in range */
+
+/* 802.11 specific support */
+#define SIOCSIWESSID   0x8B1A          /* set ESSID (network name) */
+#define SIOCGIWESSID   0x8B1B          /* get ESSID */
+/* As the ESSID is a string up to 32 bytes long, it doesn't fit within the
+ * 'iwreq' structure, so we need to use the 'data' member to point to a
+ * string in user space, like it is done for RANGE...
+ * The "flags" member indicate if the ESSID is active or not.
+ */
+
+/* ------------------------- IOCTL STUFF ------------------------- */
+
+/* The first and the last (range) */
+#define SIOCIWFIRST    0x8B00
+#define SIOCIWLAST     0x8B1B
+
+/* Even : get (world access), odd : set (root access) */
+#define IW_IS_SET(cmd) (!((cmd) & 0x1))
+#define IW_IS_GET(cmd) ((cmd) & 0x1)
+
+/* ------------------------- PRIVATE INFO ------------------------- */
+/*
+ * The following is used with SIOCGIWPRIV. It allow a driver to define
+ * the interface (name, type of data) for its private ioctl.
+ * Privates ioctl are SIOCDEVPRIVATE -> SIOCDEVPRIVATE + 0xF
+ */
+
+#define IW_PRIV_TYPE_MASK      0x7000  /* Type of arguments */
+#define IW_PRIV_TYPE_NONE      0x0000
+#define IW_PRIV_TYPE_BYTE      0x1000  /* Char as number */
+#define IW_PRIV_TYPE_CHAR      0x2000  /* Char as character */
+#define IW_PRIV_TYPE_INT       0x4000  /* 32 bits int */
+#define IW_PRIV_TYPE_FLOAT     0x5000
+
+#define IW_PRIV_SIZE_FIXED     0x0800  /* Variable or fixed nuber of args */
+
+#define IW_PRIV_SIZE_MASK      0x07FF  /* Max number of those args */
+
+/*
+ * Note : if the number of args is fixed and the size < 16 octets,
+ * instead of passing a pointer we will put args in the iwreq struct...
+ */
+
+/* ----------------------- OTHER CONSTANTS ----------------------- */
+
+/* Maximum frequencies in the range struct */
+#define IW_MAX_FREQUENCIES     16
+/* Note : if you have something like 80 frequencies,
+ * don't increase this constant and don't fill the frequency list.
+ * The user will be able to set by channel anyway... */
+
+/* Maximum of address that you may set with SPY */
+#define IW_MAX_SPY             8
+
+/* Maximum of address that you may get in the
+   list of access points in range */
+#define IW_MAX_AP              8
+
+/* Maximum size of the ESSID string */
+#define IW_ESSID_MAX_SIZE      32
+
+/****************************** TYPES ******************************/
+
+/* --------------------------- SUBTYPES --------------------------- */
+/*
+ *     A frequency
+ *     For numbers lower than 10^9, we encode the number in 'mant' and
+ *     set 'exp' to 0
+ *     For number greater than 10^9, we divide it by a power of 10.
+ *     The power of 10 is in 'exp', the result is in 'mant'.
+ */
+struct iw_freq
+{
+       __u32           m;              /* Mantissa */
+       __u16           e;              /* Exponent */
+};
+
+/*
+ *     Quality of the link
+ */
+struct iw_quality
+{
+       __u8            qual;           /* link quality (SNR or better...) */
+       __u8            level;          /* signal level */
+       __u8            noise;          /* noise level */
+       __u8            updated;        /* Flags to know if updated */
+};
+
+/*
+ *     Packet discarded in the wireless adapter due to
+ *     "wireless" specific problems...
+ */
+struct iw_discarded
+{
+       __u32           nwid;           /* Wrong nwid */
+       __u32           code;           /* Unable to code/decode */
+       __u32           misc;           /* Others cases */
+};
+
+/*
+ *     Encoding information (setting and so on)
+ *     Encoding might be hardware encryption, scrambing or others
+ */
+struct iw_encoding
+{
+  __u8 method;                 /* Algorithm number / key used */
+  __u64        code;                   /* Data/key used for algorithm */
+};
+
+
+/* ------------------------ WIRELESS STATS ------------------------ */
+/*
+ * Wireless statistics (used for /proc/net/wireless)
+ */
+struct iw_statistics
+{
+       __u8            status;         /* Status
+                                        * - device dependent for now */
+
+       struct iw_quality       qual;           /* Quality of the link
+                                                * (instant/mean/max) */
+       struct iw_discarded     discard;        /* Packet discarded counts */
+};
+
+/* ------------------------ IOCTL REQUEST ------------------------ */
+/*
+ * The structure to exchange data for ioctl.
+ * This structure is the same as 'struct ifreq', but (re)defined for
+ * convenience...
+ *
+ * Note that it should fit on the same memory footprint !
+ * You should check this when increasing the above structures (16 octets)
+ * 16 octets = 128 bits. Warning, pointers might be 64 bits wide...
+ */
+struct iwreq 
+{
+       union
+       {
+               char    ifrn_name[IFNAMSIZ];    /* if name, e.g. "en0" */
+       } ifr_ifrn;
+
+       /* Data part */
+       union
+       {
+               /* Config - generic */
+               char    name[IFNAMSIZ];
+               /* Name : used to verify the presence of  wireless extensions.
+                * Name of the protocol/provider... */
+
+               struct          /* network id (or domain) : used to to */
+               {               /* create logical channels on the air */
+                       __u32   nwid;           /* value */
+                       __u8    on;             /* active/unactive nwid */
+               }       nwid;
+
+               struct iw_freq  freq;   /* frequency or channel :
+                                        * 0-1000 = channel
+                                        * > 1000 = frequency in Hz */
+
+               struct iw_encoding      encoding;       /* Encoding stuff */
+
+               __u32   sensitivity;            /* signal level threshold */
+
+               struct sockaddr ap_addr;        /* Access point address */
+
+               struct          /* For all data bigger than 16 octets */
+               {
+                       caddr_t pointer;        /* Pointer to the data
+                                                * (in user space) */
+                       __u16   length;         /* fields or byte size */
+                       __u16   flags;          /* Optional params */
+               }       data;
+       }       u;
+};
+
+/* -------------------------- IOCTL DATA -------------------------- */
+/*
+ *     For those ioctl which want to exchange mode data that what could
+ *     fit in the above structure...
+ */
+
+/*
+ *     Range of parameters
+ */
+
+struct iw_range
+{
+       /* Informative stuff (to choose between different interface) */
+       __u32           throughput;     /* To give an idea... */
+
+       /* NWID (or domain id) */
+       __u32           min_nwid;       /* Minimal NWID we are able to set */
+       __u32           max_nwid;       /* Maximal NWID we are able to set */
+
+       /* Frequency */
+       __u16           num_channels;   /* Number of channels [0; num - 1] */
+       __u8            num_frequency;  /* Number of entry in the list */
+       struct iw_freq  freq[IW_MAX_FREQUENCIES];       /* list */
+       /* Note : this frequency list doesn't need to fit channel numbers */
+
+       /* signal level threshold range */
+       __u32   sensitivity;
+
+       /* Quality of link & SNR stuff */
+       struct iw_quality       max_qual;       /* Quality of the link */
+
+       /* Encoder stuff */
+       struct iw_encoding      max_encoding;   /* Encoding max range */
+};
+
+/*
+ * Private ioctl interface information
+ */
+struct iw_priv_args
+{
+       __u32           cmd;            /* Number of the ioctl to issue */
+       __u16           set_args;       /* Type and number of args */
+       __u16           get_args;       /* Type and number of args */
+       char            name[IFNAMSIZ]; /* Name of the extension */
+};
+
+#endif /* _LINUX_WIRELESS_H */
diff --git a/wireless_tools/xwireless.c b/wireless_tools/xwireless.c
new file mode 100644 (file)
index 0000000..dca0d48
--- /dev/null
@@ -0,0 +1,241 @@
+/* Xwireless.c, status: experimental, do not distribute!! */
+#include <stdio.h>
+#include <getopt.h>
+#include <sys/types.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/cursorfont.h>
+#include <X11/Xaw/Form.h>
+#include <X11/Xaw/Label.h>
+#include <X11/Xaw/Scrollbar.h>
+
+#include <linux/wireless.h>
+
+char* status[] = { "Scanning","Registering","Best AP","Good AP",
+                         "Poor AP","Active Beacon Search","Static Load Balance",
+                         "Balance Search" };
+
+typedef struct privateData {
+       char    *ifname;
+       Pixel   currentColor;
+       Pixel   highColor;
+       Pixel   lowColor;
+       Pixel   criticalColor;
+       Pixel   foreground;
+       int     highValue;
+       int     lowValue;
+       int     delay;
+       String  geometry;
+       struct  iw_statistics stats;
+       struct  iw_range range;
+} privateData;
+
+static XtAppContext          app_context;
+static Widget                scrollbar;
+static Widget                topLevel;
+static Widget                label;
+static XtIntervalId          timerId;
+static privateData    priv;
+
+static int getstats(char *ifname, struct iw_statistics *stats)
+{
+       struct iwreq wrq;
+       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.code);
+                       bp = strtok(NULL, " .");
+                       sscanf(bp, "%d", &stats->discard.misc);
+                       fclose(f);
+                       return 0;
+               } else {
+                       stats->status = -1;
+                       stats->qual.qual = 0;
+                       stats->qual.level = 0;
+                       stats->qual.noise = 0;
+               }
+       }
+       fclose(f);
+
+       /*strcpy(wrq.ifr_name, ifname);
+       wrq.u.data.pointer = (caddr_t) &range;
+       wrq.u.data.length = 0;
+       wrq.u.data.flags = 0;
+       if(ioctl(skfd, SIOCGIWRANGE, &wrq) >= 0) {
+               info->has_range = 1;
+    }*/
+       
+       return 0;
+}
+
+static void update( XtPointer client_data, XtIntervalId *id )
+{
+       char       buf[128];
+       static int pixel           = -1;
+       static int lpixel          = -1;
+       static int bpixel          = -1;
+
+       getstats( priv.ifname, &(priv.stats));
+
+       if(status < 8)
+         sprintf( buf, "%s", status[priv.stats.status] );
+       else
+         sprintf( buf, "%s", "buggy" );
+       XtVaSetValues( label, XtNlabel, buf, NULL );
+
+       if (priv.stats.qual.qual <= priv.lowValue) {
+               if (pixel != priv.criticalColor)
+                       XtVaSetValues( scrollbar, XtNforeground,
+                                                  pixel = priv.criticalColor, NULL );
+               if (bpixel != priv.criticalColor)
+                       XtVaSetValues( scrollbar, XtNborderColor,
+                                                  bpixel = priv.criticalColor, NULL );
+       } else if (priv.stats.qual.qual <= priv.highValue) {
+               if (pixel != priv.lowColor)
+                       XtVaSetValues( scrollbar, 
+                                                  XtNforeground, pixel = priv.lowColor, NULL );
+               if (bpixel != priv.foreground)
+                       XtVaSetValues( scrollbar, XtNborderColor,
+                                                  bpixel = priv.foreground, NULL );
+       } else {
+               if (pixel != priv.highColor )
+                       XtVaSetValues( scrollbar, 
+                                                  XtNforeground, pixel = priv.highColor, NULL );
+       }
+       
+       XawScrollbarSetThumb( scrollbar, 0.0, priv.stats.qual.qual / 255.0 );
+       timerId = XtAppAddTimeOut( app_context, 1000 , update, app_context );
+}
+
+#define offset(field) XtOffsetOf( privateData, field )
+static XtResource resources[] = {
+       { "highColor", XtCForeground, XtRPixel, sizeof(Pixel),
+         offset(highColor), XtRString, "green" },
+       { "lowColor", XtCForeground, XtRPixel, sizeof(Pixel),
+         offset(lowColor), XtRString, "orange" },
+       { "criticalColor", XtCForeground, XtRPixel, sizeof(Pixel),
+         offset(criticalColor), XtRString, "red" },
+       { XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
+         offset(foreground), XtRString, XtDefaultForeground },
+       { "highValue", XtCValue, XtRInt, sizeof(int),
+         offset(highValue), XtRImmediate, (XtPointer)50 },
+       { "lowValue", XtCValue, XtRInt, sizeof(int),
+         offset(lowValue), XtRImmediate, (XtPointer)10 },
+       { "geometry", XtCString, XtRString, sizeof( String ),
+         offset(geometry), XtRString, (XtPointer)"10x100" },
+       { "delay", XtCValue, XtRInt, sizeof(int),
+         offset(delay), XtRImmediate, (XtPointer)1 },
+};
+
+int main( int argc, char **argv ) {
+       Cursor           cursor;
+       int              c;
+       Widget           form;
+       XFontStruct      *fs;
+       int              fontWidth, fontHeight;
+       int              width = 120;
+       
+       /* The device name must be the first argument */
+       if(argc < 2) {
+               printf("Hmm\n");                
+    }
+       priv.ifname = argv[1];
+
+       if( priv.ifname == (char *) NULL) {
+               printf("Usage: xwireless <interface>\n");
+               exit(-1);
+       }
+
+       topLevel = XtVaAppInitialize( &app_context, "Xwireless",
+                                                                 NULL, 0,
+                                                                 &argc, argv, NULL, NULL );
+
+       XtGetApplicationResources( topLevel,
+                                                          &priv,
+                                                          resources,
+                                                          XtNumber( resources ),
+                                                          NULL, 0 );
+       priv.lowValue = 85;
+       priv.highValue = 170;
+
+/*     printf( "highColor = %ld\n",     priv.highColor );
+       printf( "lowColor = %ld\n",      priv.lowColor );
+       printf( "criticalColor = %ld\n", priv.criticalColor );
+       printf( "foreground = %ld\n",    priv.foreground );
+       printf( "highValue = %d\n",      priv.highValue );
+       printf( "lowValue = %d\n",       priv.lowValue );
+       printf( "geometry = %s\n",       priv.geometry );*/
+
+       cursor = XCreateFontCursor( XtDisplay( topLevel ), XC_top_left_arrow );
+       
+       form = XtVaCreateManagedWidget( "form",
+                                                                       formWidgetClass, topLevel,
+                                                                       XtNorientation, XtorientHorizontal,
+                                                                       XtNborderWidth, 0,
+                                                                       XtNdefaultDistance, 2,
+                                                                       NULL );
+   
+    label = XtVaCreateManagedWidget( "label",
+                                                                        labelWidgetClass, form,
+                                                                        XtNleft, XtChainLeft,
+                                                                        XtNinternalHeight, 0,
+                                                                        XtNinternalWidth, 0,
+                                                                        XtNborderWidth, 0,
+                                                                        XtNlabel, "Status",
+                                                                        NULL );
+       
+       XtVaGetValues( label, XtNfont, &fs, NULL );
+       fontWidth  = fs->max_bounds.width;
+       fontHeight = fs->max_bounds.ascent + fs->max_bounds.descent;
+       XtVaSetValues( label, XtNwidth, fontWidth * 8, NULL );
+       
+       scrollbar = XtVaCreateManagedWidget( "scrollbar",
+                                                                                scrollbarWidgetClass, form,
+                                                                                XtNhorizDistance, 3,
+                                                                                XtNfromHoriz, label,
+                                                                                XtNorientation, XtorientHorizontal,
+                                                                                XtNscrollHCursor, cursor,
+                                                                                XtNthickness, fontHeight,
+                                                                                XtNlength, (width > fontWidth*4 - 6)
+                                                                                ? width - fontWidth * 4 - 6
+                                                                                : fontWidth * 4,
+                                                                                NULL );
+       
+       XawScrollbarSetThumb( scrollbar, 0.0, 0.0 );
+/*     XtVaSetValues( scrollbar,
+                                  XtNtranslations, XtParseTranslationTable( "" ), NULL );
+                                  */
+       XtRealizeWidget( topLevel );
+       timerId = XtAppAddTimeOut( app_context, 0, update, app_context );
+       XtAppMainLoop( app_context );
+       
+       return 0;
+}
diff --git a/wireless_tools/xwireless.make b/wireless_tools/xwireless.make
new file mode 100644 (file)
index 0000000..758d827
--- /dev/null
@@ -0,0 +1,53 @@
+# Makefile for Xwireless
+CC = gcc
+RM = rm -f
+
+RM_CMD = $(RM) *.BAK *.bak *.o ,* *~ *.a
+
+INCLUDES =     $(SYS_INCLUDES) $(LOCAL_INCLUDES)
+LIBRARIES =    $(LOCAL_LIBRARIES) $(SYS_LIBRARIES)
+LIBPATH = $(SYS_LIBPATH) $(LOCAL_LIBPATH)
+
+#
+# System stuff
+#
+SYS_INCLUDES = -I/usr/include  -I/usr/X11R6/include
+SYS_LIBRARIES = -lXaw -lXmu -lXt -lXext  -lSM -lICE -lX11      
+SYS_LIBPATH = -L/usr/lib -L/usr/local/lib -L/usr/X11R6/lib
+
+#
+# Local stuff
+#
+LOCAL_INCLUDES = 
+LOCAL_LIBRARIES        = 
+LOCAL_LIBPATH = 
+
+XTRACFLAGS=-Wall -pipe -I.
+
+# Uncomment these lines for a production compile
+#CFLAGS=-O3 -m486 -fomit-frame-pointer
+#LDFLAGS=-s
+CFLAGS=-g
+
+#
+# Files to make
+#
+PROGS=xwireless
+
+SRCS = $(PROGS).c
+OBJS = $(PROGS).o
+
+all:: $(PROGS)
+
+xwireless: $(OBJS)
+       $(CC) $(CFLAGS) -o $@ $(OBJS) $(INCLUDES) $(LIBPATH) $(LIBRARIES) 
+
+.c.o:
+       $(CC) $(CFLAGS) $(XTRACFLAGS) -c $(INCLUDES) -DNARROWPROTO $<
+
+clean::
+       $(RM_CMD) 
+
+depend::
+       makedepend -s "# DO NOT DELETE" -- $(INCLUDES) -- $(SRCS)
+# DO NOT DELETE