OSDN Git Service

v10
authorchris-kirby <chris.kirby@hpe.com>
Tue, 11 Oct 2016 20:35:24 +0000 (14:35 -0600)
committerchris-kirby <chris.kirby@hpe.com>
Tue, 11 Oct 2016 20:35:24 +0000 (14:35 -0600)
wireless_tools/iwconfig.8 [new file with mode: 0644]
wireless_tools/iwconfig.c [new file with mode: 0644]
wireless_tools/iwpriv.c [new file with mode: 0644]
wireless_tools/iwspy.8 [new file with mode: 0644]
wireless_tools/iwspy.c [new file with mode: 0644]

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