OSDN Git Service

v24
[android-x86/external-wireless-tools.git] / wireless_tools / iwconfig.c
index c65f92e..73e7ec1 100644 (file)
@@ -1,22 +1,17 @@
 /*
  *     Wireless Tools
  *
- *             Jean II - HPLB '99
+ *             Jean II - HPLB 97->99 - HPL 99->01
  *
  * Main code for "iwconfig". This is the generic tool for most
  * manipulations...
- * You need to link this code against "iwcommon.c" and "-lm".
+ * You need to link this code against "iwlib.c" and "-lm".
+ *
+ * This file is released under the GPL license.
+ *     Copyright (c) 1997-2002 Jean Tourrilhes <jt@hpl.hp.com>
  */
 
-#include "iwcommon.h"          /* Header */
-
-/**************************** VARIABLES ****************************/
-char * operation_mode[] = { "Auto",
-                            "Ad-Hoc",
-                            "Managed",
-                            "Master",
-                            "Repeater",
-                            "Secondary" };
+#include "iwlib.h"             /* Header */
 
 /************************* MISC SUBROUTINES **************************/
 
@@ -37,7 +32,9 @@ iw_usage(void)
   fprintf(stderr, "                          [rts {N|auto|fixed|off}]\n");
   fprintf(stderr, "                          [frag {N|auto|fixed|off}]\n");
   fprintf(stderr, "                          [enc NNNN-NNNN]\n");
-  exit(1);
+  fprintf(stderr, "                          [power { period N|timeout N}]\n");
+  fprintf(stderr, "                          [txpower N {mW|dBm}]\n");
+  fprintf(stderr, "                          [commit]\n");
 }
 
 
@@ -45,69 +42,6 @@ iw_usage(void)
 
 /*------------------------------------------------------------------*/
 /*
- * 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];
-  char *       bp;
-  int          t;
-  if(f==NULL)
-    return -1;
-  /* Loop on all devices */
-  while(fgets(buf,255,f))
-    {
-      bp=buf;
-      while(*bp&&isspace(*bp))
-       bp++;
-      /* Is it the good device ? */
-      if(strncmp(bp,ifname,strlen(ifname))==0 && bp[strlen(ifname)]==':')
-       {
-         /* Skip ethX: */
-         bp=strchr(bp,':');
-         bp++;
-         /* -- status -- */
-         bp = strtok(bp, " ");
-         sscanf(bp, "%X", &t);
-         stats->status = (unsigned short) t;
-         /* -- link quality -- */
-         bp = strtok(NULL, " ");
-         if(strchr(bp,'.') != NULL)
-           stats->qual.updated |= 1;
-         sscanf(bp, "%d", &t);
-         stats->qual.qual = (unsigned char) t;
-         /* -- signal level -- */
-         bp = strtok(NULL, " ");
-         if(strchr(bp,'.') != NULL)
-           stats->qual.updated |= 2;
-         sscanf(bp, "%d", &t);
-         stats->qual.level = (unsigned char) t;
-         /* -- noise level -- */
-         bp = strtok(NULL, " ");
-         if(strchr(bp,'.') != NULL)
-           stats->qual.updated += 4;
-         sscanf(bp, "%d", &t);
-         stats->qual.noise = (unsigned char) t;
-         /* -- discarded packets -- */
-         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;
-       }
-    }
-  fclose(f);
-  return -1;
-}
-
-/*------------------------------------------------------------------*/
-/*
  * 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...
@@ -122,43 +56,51 @@ get_info(int                       skfd,
   memset((char *) info, 0, sizeof(struct wireless_info));
 
   /* Get wireless name */
-  strcpy(wrq.ifr_name, ifname);
-  if(ioctl(skfd, SIOCGIWNAME, &wrq) < 0)
-    /* If no wireless name : no wireless extensions */
-    return(-1);
+  if(iw_get_ext(skfd, ifname, SIOCGIWNAME, &wrq) < 0)
+    {
+      /* If no wireless name : no wireless extensions */
+      /* But let's check if the interface exists at all */
+      struct ifreq ifr;
+
+      strcpy(ifr.ifr_name, ifname);
+      if(ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0)
+       return(-ENODEV);
+      else
+       return(-ENOTSUP);
+    }
   else
     strcpy(info->name, wrq.u.name);
 
+  /* Get ranges */
+  if(iw_get_range_info(skfd, ifname, &(info->range)) >= 0)
+    info->has_range = 1;
+
   /* Get network ID */
-  strcpy(wrq.ifr_name, ifname);
-  if(ioctl(skfd, SIOCGIWNWID, &wrq) >= 0)
+  if(iw_get_ext(skfd, ifname, SIOCGIWNWID, &wrq) >= 0)
     {
       info->has_nwid = 1;
       memcpy(&(info->nwid), &(wrq.u.nwid), sizeof(iwparam));
     }
 
   /* Get frequency / channel */
-  strcpy(wrq.ifr_name, ifname);
-  if(ioctl(skfd, SIOCGIWFREQ, &wrq) >= 0)
+  if(iw_get_ext(skfd, ifname, SIOCGIWFREQ, &wrq) >= 0)
     {
       info->has_freq = 1;
-      info->freq = freq2float(&(wrq.u.freq));
+      info->freq = iw_freq2float(&(wrq.u.freq));
     }
 
   /* Get sensitivity */
-  strcpy(wrq.ifr_name, ifname);
-  if(ioctl(skfd, SIOCGIWSENS, &wrq) >= 0)
+  if(iw_get_ext(skfd, ifname, SIOCGIWSENS, &wrq) >= 0)
     {
       info->has_sens = 1;
       memcpy(&(info->sens), &(wrq.u.sens), sizeof(iwparam));
     }
 
   /* Get encryption information */
-  strcpy(wrq.ifr_name, ifname);
   wrq.u.data.pointer = (caddr_t) info->key;
-  wrq.u.data.length = 0;
+  wrq.u.data.length = IW_ENCODING_TOKEN_MAX;
   wrq.u.data.flags = 0;
-  if(ioctl(skfd, SIOCGIWENCODE, &wrq) >= 0)
+  if(iw_get_ext(skfd, ifname, SIOCGIWENCODE, &wrq) >= 0)
     {
       info->has_key = 1;
       info->key_size = wrq.u.data.length;
@@ -166,84 +108,91 @@ get_info(int                      skfd,
     }
 
   /* Get ESSID */
-  strcpy(wrq.ifr_name, ifname);
   wrq.u.essid.pointer = (caddr_t) info->essid;
-  wrq.u.essid.length = 0;
+  wrq.u.essid.length = IW_ESSID_MAX_SIZE;
   wrq.u.essid.flags = 0;
-  if(ioctl(skfd, SIOCGIWESSID, &wrq) >= 0)
+  if(iw_get_ext(skfd, ifname, 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)
+  if(iw_get_ext(skfd, ifname, SIOCGIWAP, &wrq) >= 0)
     {
       info->has_ap_addr = 1;
       memcpy(&(info->ap_addr), &(wrq.u.ap_addr), sizeof (sockaddr));
     }
 
   /* Get NickName */
-  strcpy(wrq.ifr_name, ifname);
   wrq.u.essid.pointer = (caddr_t) info->nickname;
-  wrq.u.essid.length = 0;
+  wrq.u.essid.length = IW_ESSID_MAX_SIZE;
   wrq.u.essid.flags = 0;
-  if(ioctl(skfd, SIOCGIWNICKN, &wrq) >= 0)
+  if(iw_get_ext(skfd, ifname, 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)
+  if(iw_get_ext(skfd, ifname, SIOCGIWRATE, &wrq) >= 0)
     {
       info->has_bitrate = 1;
       memcpy(&(info->bitrate), &(wrq.u.bitrate), sizeof(iwparam));
     }
 
   /* Get RTS threshold */
-  strcpy(wrq.ifr_name, ifname);
-  if(ioctl(skfd, SIOCGIWRTS, &wrq) >= 0)
+  if(iw_get_ext(skfd, ifname, SIOCGIWRTS, &wrq) >= 0)
     {
       info->has_rts = 1;
       memcpy(&(info->rts), &(wrq.u.rts), sizeof(iwparam));
     }
 
   /* Get fragmentation threshold */
-  strcpy(wrq.ifr_name, ifname);
-  if(ioctl(skfd, SIOCGIWFRAG, &wrq) >= 0)
+  if(iw_get_ext(skfd, ifname, SIOCGIWFRAG, &wrq) >= 0)
     {
       info->has_frag = 1;
       memcpy(&(info->frag), &(wrq.u.frag), sizeof(iwparam));
     }
 
   /* Get operation mode */
-  strcpy(wrq.ifr_name, ifname);
-  if(ioctl(skfd, SIOCGIWMODE, &wrq) >= 0)
+  if(iw_get_ext(skfd, ifname, SIOCGIWMODE, &wrq) >= 0)
     {
-      if((wrq.u.mode < 6) && (wrq.u.mode >= 0))
-       info->has_mode = 1;
       info->mode = wrq.u.mode;
+      if((info->mode < IW_NUM_OPER_MODE) && (info->mode >= 0))
+       info->has_mode = 1;
     }
 
   /* Get Power Management settings */
-  strcpy(wrq.ifr_name, ifname);
-  if(ioctl(skfd, SIOCGIWPOWER, &wrq) >= 0)
+  wrq.u.power.flags = 0;
+  if(iw_get_ext(skfd, ifname, SIOCGIWPOWER, &wrq) >= 0)
     {
       info->has_power = 1;
       memcpy(&(info->power), &(wrq.u.power), sizeof(iwparam));
     }
 
+#if WIRELESS_EXT > 9
+  /* Get Transmit Power */
+  if(iw_get_ext(skfd, ifname, SIOCGIWTXPOW, &wrq) >= 0)
+    {
+      info->has_txpower = 1;
+      memcpy(&(info->txpower), &(wrq.u.txpower), sizeof(iwparam));
+    }
+#endif
+
+#if WIRELESS_EXT > 10
+  /* Get retry limit/lifetime */
+  if(iw_get_ext(skfd, ifname, SIOCGIWRETRY, &wrq) >= 0)
+    {
+      info->has_retry = 1;
+      memcpy(&(info->retry), &(wrq.u.retry), sizeof(iwparam));
+    }
+#endif /* WIRELESS_EXT > 10 */
+
   /* Get stats */
-  if(iw_getstats(ifname, &(info->stats)) >= 0)
+  if(iw_get_stats(skfd, ifname, &(info->stats)) >= 0)
     {
       info->has_stats = 1;
     }
 
-  /* Get ranges */
-  if(get_range_info(skfd, ifname, &(info->range)) >= 0)
-    info->has_range = 1;
-
   return(0);
 }
 
@@ -256,6 +205,11 @@ static void
 display_info(struct wireless_info *    info,
             char *                     ifname)
 {
+  char         buffer[128];    /* Temporary buffer */
+
+  /* One token is more of less 5 characters, 14 tokens per line */
+  int  tokens = 3;     /* For name */
+
   /* Display device name and wireless name (name of the protocol used) */
   printf("%-8.8s  %s  ", ifname, info->name);
 
@@ -263,9 +217,16 @@ display_info(struct wireless_info *        info,
   if(info->has_essid)
     {
       if(info->essid_on)
-       printf("ESSID:\"%s\"  ", info->essid);
+       {
+         /* Does it have an ESSID index ? */
+         if((info->essid_on & IW_ENCODE_INDEX) > 1)
+           printf("ESSID:\"%s\" [%d]  ", info->essid,
+                  (info->essid_on & IW_ENCODE_INDEX));
+         else
+           printf("ESSID:\"%s\"  ", info->essid);
+       }
       else
-       printf("ESSID:off  ");
+       printf("ESSID:off/any  ");
     }
 
   /* Display NickName (station name), if any */
@@ -274,41 +235,121 @@ display_info(struct wireless_info *      info,
 
   /* Formatting */
   if(info->has_essid || info->has_nickname)
-    printf("\n          ");
+    {
+      printf("\n          ");
+      tokens = 0;
+    }
 
   /* Display Network ID */
   if(info->has_nwid)
     {
-      /* Note : should display right number of digit according to info
+      /* Note : should display proper number of digit according to info
        * in range structure */
       if(info->nwid.disabled)
        printf("NWID:off/any  ");
       else
        printf("NWID:%X  ", info->nwid.value);
+      tokens +=2;
+    }
+
+  /* Display the current mode of operation */
+  if(info->has_mode)
+    {
+      printf("Mode:%s  ", iw_operation_mode[info->mode]);
+      tokens +=3;
     }
 
   /* Display frequency / channel */
   if(info->has_freq)
     {
-      if(info->freq < KILO)
-       printf("Channel:%g  ", info->freq);
+      iw_print_freq(buffer, info->freq);
+      printf("%s  ", buffer);
+      tokens +=4;
+    }
+
+  /* Display the address of the current Access Point */
+  if(info->has_ap_addr)
+    {
+      /* A bit of clever formatting */
+      if(tokens > 8)
+       {
+         printf("\n          ");
+         tokens = 0;
+       }
+      tokens +=6;
+
+      /* Oups ! No Access Point in Ad-Hoc mode */
+      if((info->has_mode) && (info->mode == IW_MODE_ADHOC))
+       printf("Cell:");
       else
+       printf("Access Point:");
+      printf(" %s", iw_pr_ether(buffer, info->ap_addr.sa_data));
+    }
+
+  /* Display the currently used/set bit-rate */
+  if(info->has_bitrate)
+    {
+      /* A bit of clever formatting */
+      if(tokens > 11)
        {
-         if(info->freq >= GIGA)
-           printf("Frequency:%gGHz  ", info->freq / GIGA);
+         printf("\n          ");
+         tokens = 0;
+       }
+      tokens +=3;
+
+      /* Display it */
+      iw_print_bitrate(buffer, info->bitrate.value);
+      printf("Bit Rate%c%s   ", (info->bitrate.fixed ? '=' : ':'), buffer);
+    }
+
+#if WIRELESS_EXT > 9
+  /* Display the Transmit Power */
+  if(info->has_txpower)
+    {
+      /* A bit of clever formatting */
+      if(tokens > 11)
+       {
+         printf("\n          ");
+         tokens = 0;
+       }
+      tokens +=3;
+
+      /* Disabled ? */
+      if(info->txpower.disabled)
+       printf("Tx-Power:off   ");
+      else
+       {
+         int           dbm;
+
+         /* Fixed ? */
+         if(info->txpower.fixed)
+           printf("Tx-Power=");
          else
-           {
-             if(info->freq >= MEGA)
-               printf("Frequency:%gMHz  ", info->freq / MEGA);
-             else
-               printf("Frequency:%gkHz  ", info->freq / KILO);
-           }
+           printf("Tx-Power:");
+
+         /* Convert everything to dBm */
+         if(info->txpower.flags & IW_TXPOW_MWATT)
+           dbm = iw_mwatt2dbm(info->txpower.value);
+         else
+           dbm = info->txpower.value;
+
+         /* Display */
+         printf("%d dBm   ", dbm);
        }
     }
+#endif
 
   /* Display sensitivity */
   if(info->has_sens)
     {
+      /* A bit of clever formatting */
+      if(tokens > 10)
+       {
+         printf("\n          ");
+         tokens = 0;
+       }
+      tokens +=4;
+
       /* Fixed ? */
       if(info->sens.fixed)
        printf("Sensitivity=");
@@ -325,48 +366,35 @@ display_info(struct wireless_info *       info,
        printf("%d  ", info->sens.value);
     }
 
-  /* Display the current mode of operation */
-  if(info->has_mode)
-    {
-      /* A bit of clever formatting */
-      if((info->has_nwid + 2*info->has_freq + 2*info->has_sens
-         + !info->has_essid) > 4)
-       printf("\n          ");
-
-      printf("Mode:%s  ", operation_mode[info->mode]);
-    }
-
-  /* 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_mode + !info->has_essid) > 3)
-       printf("\n          ");
-
-      printf("Access Point: %s", pr_ether(info->ap_addr.sa_data));
-    }
-
   printf("\n          ");
+  tokens = 0;
 
-  /* Display the currently used/set bit-rate */
-  if(info->has_bitrate)
-    {
-      /* Fixed ? */
-      if(info->bitrate.fixed)
-       printf("Bit Rate=");
+#if WIRELESS_EXT > 10
+  /* Display retry limit/lifetime information */
+  if(info->has_retry)
+    { 
+      printf("Retry");
+      /* Disabled ? */
+      if(info->retry.disabled)
+       printf(":off");
       else
-       printf("Bit Rate:");
+       {
+         /* Let's check the value and its type */
+         if(info->retry.flags & IW_RETRY_TYPE)
+           {
+             iw_print_retry_value(buffer,
+                                  info->retry.value, info->retry.flags);
+             printf("%s", buffer);
+           }
 
-      if(info->bitrate.value >= GIGA)
-       printf("%gGb/s", info->bitrate.value / GIGA);
-      else
-       if(info->bitrate.value >= MEGA)
-         printf("%gMb/s", info->bitrate.value / MEGA);
-       else
-         printf("%gkb/s", info->bitrate.value / KILO);
+         /* Let's check if nothing (simply on) */
+         if(info->retry.flags == IW_RETRY_ON)
+           printf(":on");
+       }
       printf("   ");
+      tokens += 5;     /* Between 3 and 5, depend on flags */
     }
+#endif /* WIRELESS_EXT > 10 */
 
   /* Display the RTS threshold */
   if(info->has_rts)
@@ -384,14 +412,23 @@ display_info(struct wireless_info *       info,
 
          printf("%d B   ", info->rts.value);
        }
+      tokens += 3;
     }
 
   /* Display the fragmentation threshold */
   if(info->has_frag)
     {
+      /* A bit of clever formatting */
+      if(tokens > 10)
+       {
+         printf("\n          ");
+         tokens = 0;
+       }
+      tokens +=4;
+
       /* Disabled ? */
       if(info->frag.disabled)
-       printf("Fragment thr:off   ");
+       printf("Fragment thr:off");
       else
        {
          /* Fixed ? */
@@ -405,11 +442,11 @@ display_info(struct wireless_info *       info,
     }
 
   /* Formating */
-  if((info->has_bitrate) || (info->has_rts) || (info->has_bitrate))
+  if(tokens > 0)
     printf("\n          ");
 
   /* Display encryption information */
-  /* Note : we display only the "current" key, use iwspy to list all keys */
+  /* Note : we display only the "current" key, use iwlist to list all keys */
   if(info->has_key)
     {
       printf("Encryption key:");
@@ -417,15 +454,9 @@ display_info(struct wireless_info *        info,
        printf("off\n          ");
       else
        {
-         int   i;
-
-         printf("%.2X", info->key[0]);
-         for(i = 1; i < info->key_size; i++)
-           {
-             if((i & 0x1) == 0)
-               printf("-");
-             printf("%.2X", info->key[i]);
-           }
+         /* Display the key */
+         iw_print_key(buffer, info->key, info->key_size, info->key_flags);
+         printf("%s", buffer);
 
          /* Other info... */
          if((info->key_flags & IW_ENCODE_INDEX) > 1)
@@ -440,7 +471,7 @@ display_info(struct wireless_info * info,
 
   /* Display Power Management information */
   /* Note : we display only one parameter, period or timeout. If a device
-   * (such as HiperLan) has both, we would need to be a bit more clever... */
+   * (such as HiperLan) has both, the user need to use iwlist... */
   if(info->has_power)  /* I hope the device has power ;-) */
     { 
       printf("Power Management");
@@ -452,42 +483,13 @@ display_info(struct wireless_info *       info,
          /* Let's check the value and its type */
          if(info->power.flags & IW_POWER_TYPE)
            {
-             /* Type */
-             if(info->power.flags & IW_POWER_TIMEOUT)
-               printf(" timeout:");
-             else
-               printf(" period:");
-
-             /* Display value with units */
-             if(info->power.value >= (int) MEGA)
-               printf("%gs  ", ((double) info->power.value) / MEGA);
-             else
-               if(info->power.value  >= (int) KILO)
-                 printf("%gms  ", ((double) info->power.value) / KILO);
-               else
-                 printf("%dus  ", info->power.value);
+             iw_print_pm_value(buffer, info->power.value, info->power.flags);
+             printf("%s  ", buffer);
            }
 
          /* Let's check the mode */
-         switch(info->power.flags & IW_POWER_MODE)
-           {
-           case IW_POWER_UNICAST_R:
-             printf(" mode:Unicast received");
-             break;
-           case IW_POWER_MULTICAST_R:
-             printf(" mode:Multicast received");
-             break;
-           case IW_POWER_ALL_R:
-             printf(" mode:All packets received");
-             break;
-           case IW_POWER_FORCE_S:
-             printf(" mode:Force sending");
-             break;
-           case IW_POWER_REPEATER:
-             printf(" mode:Repeat multicasts");
-             break;
-           default:
-           }
+         iw_print_pm_mode(buffer, info->power.flags);
+         printf("%s", buffer);
 
          /* Let's check if nothing (simply on) */
          if(info->power.flags == IW_POWER_ON)
@@ -496,32 +498,27 @@ display_info(struct wireless_info *       info,
        }
     }
 
+  /* Display statistics */
   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);
+      info->stats.qual.updated = 0x0;  /* Not that reliable, disable */
+      iw_print_stats(buffer, &info->stats.qual, &info->range, info->has_range);
+      printf("Link %s\n", buffer);
 
+#if WIRELESS_EXT > 11
+      printf("          Rx invalid nwid:%d  Rx invalid crypt:%d  Rx invalid frag:%d\n          Tx excessive retries:%d  Invalid misc:%d   Missed beacon:%d\n",
+            info->stats.discard.nwid,
+            info->stats.discard.code,
+            info->stats.discard.fragment,
+            info->stats.discard.retries,
+            info->stats.discard.misc,
+            info->stats.miss.beacon);
+#else /* WIRELESS_EXT > 11 */
       printf("          Rx invalid nwid:%d  invalid crypt:%d  invalid misc:%d\n",
             info->stats.discard.nwid,
             info->stats.discard.code,
             info->stats.discard.misc);
+#endif /* WIRELESS_EXT > 11 */
     }
 
   printf("\n");
@@ -532,51 +529,98 @@ display_info(struct wireless_info *       info,
  * Print on the screen in a neat fashion all the info we have collected
  * on a device.
  */
-static void
+static int
 print_info(int         skfd,
-          char *       ifname)
+          char *       ifname,
+          char *       args[],
+          int          count)
 {
   struct wireless_info info;
+  int                  rc;
+
+  /* Avoid "Unused parameter" warning */
+  args = args; count = count;
 
-  if(get_info(skfd, ifname, &info) < 0)
+  rc = get_info(skfd, ifname, &info);
+  switch(rc)
     {
+    case 0:    /* Success */
+      /* Display it ! */
+      display_info(&info, ifname);
+      break;
+
+    case -ENOTSUP:
       fprintf(stderr, "%-8.8s  no wireless extensions.\n\n",
              ifname);
-      return;
-    }
+      break;
 
-  /* Display it ! */
-  display_info(&info, ifname);
+    default:
+      fprintf(stderr, "%-8.8s  %s\n\n", ifname, strerror(-rc));
+    }
+  return(rc);
 }
 
+/************************* SETTING ROUTINES **************************/
+
 /*------------------------------------------------------------------*/
 /*
- * Get info on all devices and print it on the screen
+ * Macro to handle errors when setting WE
+ * Print a nice error message and exit...
+ * We define them as macro so that "return" do the right thing.
+ * The "do {...} while(0)" is a standard trick
  */
-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;
+#define ERR_SET_EXT(rname, request) \
+       fprintf(stderr, "Error for wireless request \"%s\" (%X) :\n", \
+               rname, request)
+
+#define ABORT_ARG_NUM(rname, request) \
+       do { \
+               ERR_SET_EXT(rname, request); \
+               fprintf(stderr, "    too few arguments.\n"); \
+               return(-1); \
+       } while(0)
+
+#define ABORT_ARG_TYPE(rname, request, arg) \
+       do { \
+               ERR_SET_EXT(rname, request); \
+               fprintf(stderr, "    invalid argument \"%s\".\n", arg); \
+               return(-2); \
+       } while(0)
+
+#define ABORT_ARG_SIZE(rname, request, max) \
+       do { \
+               ERR_SET_EXT(rname, request); \
+               fprintf(stderr, "    argument too big (max %d)\n", max); \
+               return(-3); \
+       } while(0)
 
-  /* Print them */
-  for(i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++)
-    print_info(skfd, ifr->ifr_name);
-}
+/*------------------------------------------------------------------*/
+/*
+ * Wrapper to push some Wireless Parameter in the driver
+ * Use standard wrapper and add pretty error message if fail...
+ */
+#define IW_SET_EXT_ERR(skfd, ifname, request, wrq, rname) \
+       do { \
+       if(iw_set_ext(skfd, ifname, request, wrq) < 0) { \
+               ERR_SET_EXT(rname, request); \
+               fprintf(stderr, "    SET failed on device %-1.8s ; %s.\n", \
+                       ifname, strerror(errno)); \
+               return(-5); \
+       } } while(0)
 
-/************************* SETTING ROUTINES **************************/
+/*------------------------------------------------------------------*/
+/*
+ * Wrapper to extract some Wireless Parameter out of the driver
+ * Use standard wrapper and add pretty error message if fail...
+ */
+#define IW_GET_EXT_ERR(skfd, ifname, request, wrq, rname) \
+       do { \
+       if(iw_get_ext(skfd, ifname, request, wrq) < 0) { \
+               ERR_SET_EXT(rname, request); \
+               fprintf(stderr, "    GET failed on device %-1.8s ; %s.\n", \
+                       ifname, strerror(errno)); \
+               return(-6); \
+       } } while(0)
 
 /*------------------------------------------------------------------*/
 /*
@@ -594,23 +638,32 @@ set_info(int              skfd,           /* The socket */
   struct iwreq         wrq;
   int                  i;
 
-  /* Set dev name */
-  strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
-
-  /* if nothing after the device name */
-  if(count<1)
-    iw_usage();
+  /* if nothing after the device name - will never happen */
+  if(count < 1)
+    {
+      fprintf(stderr, "Error : too few arguments.\n");
+      return(-1);
+    }
 
   /* The other args on the line specify options to be set... */
   for(i = 0; i < count; i++)
     {
+      /* ---------- Commit changes to driver ---------- */
+      if(!strncmp(args[i], "commit", 6))
+       {
+         /* No args */
+         IW_SET_EXT_ERR(skfd, ifname, SIOCSIWCOMMIT, &wrq,
+                        "Commit changes");
+         continue;
+       }
+
       /* ---------- Set network ID ---------- */
       if((!strcasecmp(args[i], "nwid")) ||
         (!strcasecmp(args[i], "domain")))
        {
          i++;
          if(i >= count)
-           iw_usage();
+           ABORT_ARG_NUM("Set NWID", SIOCSIWNWID);
          if((!strcasecmp(args[i], "off")) ||
             (!strcasecmp(args[i], "any")))
            wrq.u.nwid.disabled = 1;
@@ -618,27 +671,21 @@ set_info(int              skfd,           /* The socket */
            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);
+               IW_GET_EXT_ERR(skfd, ifname, SIOCGIWNWID, &wrq,
+                              "Set NWID");
                wrq.u.nwid.disabled = 0;
              }
            else
              if(sscanf(args[i], "%lX", (unsigned long *) &(wrq.u.nwid.value))
                 != 1)
-               iw_usage();
+               ABORT_ARG_TYPE("Set NWID", SIOCSIWNWID, args[i]);
              else
                wrq.u.nwid.disabled = 0;
          wrq.u.nwid.fixed = 1;
 
-         if(ioctl(skfd, SIOCSIWNWID, &wrq) < 0)
-           {
-             fprintf(stderr, "SIOCSIWNWID: %s\n", strerror(errno));
-             return(-1);
-           }
+         /* Set new nwid */
+         IW_SET_EXT_ERR(skfd, ifname, SIOCSIWNWID, &wrq,
+                        "Set NWID");
          continue;
        }
 
@@ -649,20 +696,17 @@ set_info(int              skfd,           /* The socket */
          double                freq;
 
          if(++i >= count)
-           iw_usage();
+           ABORT_ARG_NUM("Set Frequency", SIOCSIWFREQ);
          if(sscanf(args[i], "%lg", &(freq)) != 1)
-           iw_usage();
+           ABORT_ARG_TYPE("Set Frequency", SIOCSIWFREQ, args[i]);
          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));
+         iw_float2freq(freq, &(wrq.u.freq));
 
-         if(ioctl(skfd, SIOCSIWFREQ, &wrq) < 0)
-           {
-             fprintf(stderr, "SIOCSIWFREQ: %s\n", strerror(errno));
-             return(-1);
-           }
+         IW_SET_EXT_ERR(skfd, ifname, SIOCSIWFREQ, &wrq,
+                        "Set Frequency");
          continue;
        }
 
@@ -670,15 +714,12 @@ set_info(int              skfd,           /* The socket */
       if(!strncmp(args[i], "sens", 4))
        {
          if(++i >= count)
-           iw_usage();
+           ABORT_ARG_NUM("Set Sensitivity", SIOCSIWSENS);
          if(sscanf(args[i], "%d", &(wrq.u.sens.value)) != 1)
-           iw_usage();
+           ABORT_ARG_TYPE("Set Sensitivity", SIOCSIWSENS, args[i]);
 
-         if(ioctl(skfd, SIOCSIWSENS, &wrq) < 0)
-           {
-             fprintf(stderr, "SIOCSIWSENS: %s\n", strerror(errno));
-             return(-1);
-           }
+         IW_SET_EXT_ERR(skfd, ifname, SIOCSIWSENS, &wrq,
+                        "Set Sensitivity");
          continue;
        }
 
@@ -689,7 +730,7 @@ set_info(int                skfd,           /* The socket */
          unsigned char key[IW_ENCODING_TOKEN_MAX];
 
          if(++i >= count)
-           iw_usage();
+           ABORT_ARG_NUM("Set Encode", SIOCSIWENCODE);
 
          if(!strcasecmp(args[i], "on"))
            {
@@ -697,67 +738,29 @@ set_info(int              skfd,           /* The socket */
              wrq.u.data.pointer = (caddr_t) key;
              wrq.u.data.length = 0;
              wrq.u.data.flags = 0;
-             if(ioctl(skfd, SIOCGIWENCODE, &wrq) < 0)
-               {
-                 fprintf(stderr, "SIOCGIWENCODE: %s\n", strerror(errno));
-                 return(-1);
-               }
-             strcpy(wrq.ifr_name, ifname);
+             IW_GET_EXT_ERR(skfd, ifname, SIOCGIWENCODE, &wrq,
+                            "Set Encode");
              wrq.u.data.flags &= ~IW_ENCODE_DISABLED;  /* Enable */
            }
          else
            {
-             char *    buff;
-             char *    p;
-             int               temp;
-             int               k = 0;
-             int               gotone = 1;
+             int       gotone = 1;
+             int       keylen;
+             int       temp;
 
              wrq.u.data.pointer = (caddr_t) NULL;
              wrq.u.data.flags = 0;
              wrq.u.data.length = 0;
 
              /* -- Check for the key -- */
-             if(!strncmp(args[i], "s:", 2))
+             keylen = iw_in_key(args[i], key);
+             if(keylen > 0)
                {
-                 /* First case : as an ASCII string */
-                 wrq.u.data.length = strlen(args[i] + 2);
-                 if(wrq.u.data.length > IW_ENCODING_TOKEN_MAX)
-                   wrq.u.data.length = IW_ENCODING_TOKEN_MAX;
-                 strncpy(key, args[i] + 2, wrq.u.data.length);
+                 wrq.u.data.length = keylen;
                  wrq.u.data.pointer = (caddr_t) key;
                  ++i;
                  gotone = 1;
                }
-             else
-               {
-                 /* Second case : has hexadecimal digits */
-                 p = buff = malloc(strlen(args[i]) + 1);
-                 strcpy(buff, args[i]);
-
-                 p = strtok(buff, "-:;.,");
-                 while(p != (char *) NULL)
-                   {
-                     if(sscanf(p, "%2X", &temp) != 1)
-                       {
-                         gotone = 0;
-                         break;
-                       }
-                     key[k++] = (unsigned char) (temp & 0xFF);
-                     if(strlen(p) > 2) /* Token not finished yet */
-                       p += 2;
-                     else
-                       p = strtok((char *) NULL, "-:;.,");
-                   }
-                 free(buff);
-
-                 if(gotone)
-                   {
-                     ++i;
-                     wrq.u.data.length = k;
-                     wrq.u.data.pointer = (caddr_t) key;
-                   }
-               }
 
              /* -- Check for token index -- */
              if((i < count) &&
@@ -784,18 +787,17 @@ set_info(int              skfd,           /* The socket */
                      gotone = 1;
                    }
                }
+             /* Pointer is absent in new API */
+             if(wrq.u.data.pointer == NULL)
+               wrq.u.data.flags |= IW_ENCODE_NOKEY;
 
              if(!gotone)
-               iw_usage();
+               ABORT_ARG_TYPE("Set Encode", SIOCSIWENCODE, args[i]);
              --i;
            }
 
-         if(ioctl(skfd, SIOCSIWENCODE, &wrq) < 0)
-           {
-             fprintf(stderr, "SIOCSIWENCODE(%d): %s\n",
-                     errno, strerror(errno));
-             return(-1);
-           }
+         IW_SET_EXT_ERR(skfd, ifname, SIOCSIWENCODE, &wrq,
+                        "Set Encode");
          continue;
        }
 
@@ -806,7 +808,7 @@ set_info(int                skfd,           /* The socket */
 
          i++;
          if(i >= count)
-           iw_usage();
+           ABORT_ARG_NUM("Set ESSID", SIOCSIWESSID);
          if((!strcasecmp(args[i], "off")) ||
             (!strcasecmp(args[i], "any")))
            {
@@ -820,34 +822,36 @@ set_info(int              skfd,           /* The socket */
                wrq.u.essid.pointer = (caddr_t) essid;
                wrq.u.essid.length = 0;
                wrq.u.essid.flags = 0;
-               if(ioctl(skfd, SIOCGIWESSID, &wrq) < 0)
-                 {
-                   fprintf(stderr, "SIOCGIWESSID: %s\n", strerror(errno));
-                   return(-1);
-                 }
-               strcpy(wrq.ifr_name, ifname);
+               IW_GET_EXT_ERR(skfd, ifname, SIOCGIWESSID, &wrq,
+                              "Set ESSID");
                wrq.u.essid.flags = 1;
              }
            else
+             /* Check the size of what the user passed us to avoid
+              * buffer overflows */
              if(strlen(args[i]) > IW_ESSID_MAX_SIZE)
-               {
-                 fprintf(stderr, "ESSID too long (max %d): ``%s''\n",
-                         IW_ESSID_MAX_SIZE, args[i]);
-                 iw_usage();
-               }
+               ABORT_ARG_SIZE("Set ESSID", SIOCSIWESSID, IW_ESSID_MAX_SIZE);
              else
                {
+                 int           temp;
+
                  wrq.u.essid.flags = 1;
-                 strcpy(essid, args[i]);
+                 strcpy(essid, args[i]);       /* Size checked, all clear */
+
+                 /* Check for ESSID index */
+                 if(((i+1) < count) &&
+                    (sscanf(args[i+1], "[%d]", &temp) == 1) &&
+                    (temp > 0) && (temp < IW_ENCODE_INDEX))
+                   {
+                     wrq.u.essid.flags = temp;
+                     ++i;
+                   }
                }
 
          wrq.u.essid.pointer = (caddr_t) essid;
          wrq.u.essid.length = strlen(essid) + 1;
-         if(ioctl(skfd, SIOCSIWESSID, &wrq) < 0)
-           {
-             fprintf(stderr, "SIOCSIWESSID: %s\n", strerror(errno));
-             return(-1);
-           }
+         IW_SET_EXT_ERR(skfd, ifname, SIOCSIWESSID, &wrq,
+                        "Set ESSID");
          continue;
        }
 
@@ -855,24 +859,31 @@ set_info(int              skfd,           /* The socket */
       if(!strcasecmp(args[i], "ap"))
        {
          if(++i >= count)
-           iw_usage();
+           ABORT_ARG_NUM("Set AP Address", SIOCSIWAP);
 
-         /* Check if we have valid address types */
-         if(check_addr_type(skfd, ifname) < 0)
+         if((!strcasecmp(args[i], "auto")) ||
+            (!strcasecmp(args[i], "any")))
            {
-             fprintf(stderr, "%-8.8s  Interface doesn't support MAC & IP addresses\n", ifname);
-             return(-1);
+             /* Send a broadcast address */
+             iw_broad_ether(&(wrq.u.ap_addr));
            }
-
-         /* Get the address */
-         if(in_addr(skfd, ifname, args[i++], &(wrq.u.ap_addr)) < 0)
-           iw_usage();
-
-         if(ioctl(skfd, SIOCSIWAP, &wrq) < 0)
+         else
            {
-             fprintf(stderr, "SIOCSIWAP: %s\n", strerror(errno));
-             return(-1);
+             if(!strcasecmp(args[i], "off"))
+               {
+                 /* Send a NULL address */
+                 iw_null_ether(&(wrq.u.ap_addr));
+               }
+             else
+               {
+                 /* Get the address and check if the interface supports it */
+                 if(iw_in_addr(skfd, ifname, args[i++], &(wrq.u.ap_addr)) < 0)
+                   ABORT_ARG_TYPE("Set AP Address", SIOCSIWAP, args[i-1]);
+               }
            }
+
+         IW_SET_EXT_ERR(skfd, ifname, SIOCSIWAP, &wrq,
+                        "Set AP Address");
          continue;
        }
 
@@ -881,21 +892,14 @@ set_info(int              skfd,           /* The socket */
        {
          i++;
          if(i >= count)
-           iw_usage();
+           ABORT_ARG_NUM("Set Nickname", SIOCSIWNICKN);
          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();
-           }
+           ABORT_ARG_SIZE("Set Nickname", SIOCSIWNICKN, IW_ESSID_MAX_SIZE);
 
          wrq.u.essid.pointer = (caddr_t) args[i];
          wrq.u.essid.length = strlen(args[i]) + 1;
-         if(ioctl(skfd, SIOCSIWNICKN, &wrq) < 0)
-           {
-             fprintf(stderr, "SIOCSIWNICKN: %s\n", strerror(errno));
-             return(-1);
-           }
+         IW_SET_EXT_ERR(skfd, ifname, SIOCSIWNICKN, &wrq,
+                        "Set Nickname");
          continue;
        }
 
@@ -904,7 +908,7 @@ set_info(int                skfd,           /* The socket */
         (!strcmp(args[i], "rate")))
        {
          if(++i >= count)
-           iw_usage();
+           ABORT_ARG_NUM("Set Bit Rate", SIOCSIWRATE);
          if(!strcasecmp(args[i], "auto"))
            {
              wrq.u.bitrate.value = -1;
@@ -915,12 +919,8 @@ set_info(int               skfd,           /* The socket */
              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);
+                 IW_GET_EXT_ERR(skfd, ifname, SIOCGIWRATE, &wrq,
+                                "Set Bit Rate");
                  wrq.u.bitrate.fixed = 1;
                }
              else                      /* Should be a numeric value */
@@ -928,7 +928,7 @@ set_info(int                skfd,           /* The socket */
                  double                brate;
 
                  if(sscanf(args[i], "%lg", &(brate)) != 1)
-                   iw_usage();
+                   ABORT_ARG_TYPE("Set Bit Rate", SIOCSIWRATE, args[i]);
                  if(index(args[i], 'G')) brate *= GIGA;
                  if(index(args[i], 'M')) brate *= MEGA;
                  if(index(args[i], 'k')) brate *= KILO;
@@ -942,14 +942,17 @@ set_info(int              skfd,           /* The socket */
                      wrq.u.bitrate.fixed = 0;
                      ++i;
                    }
+                 if(((i+1) < count) &&
+                    (!strcasecmp(args[i+1], "fixed")))
+                   {
+                     wrq.u.bitrate.fixed = 1;
+                     ++i;
+                   }
                }
            }
 
-         if(ioctl(skfd, SIOCSIWRATE, &wrq) < 0)
-           {
-             fprintf(stderr, "SIOCSIWRATE: %s\n", strerror(errno));
-             return(-1);
-           }
+         IW_SET_EXT_ERR(skfd, ifname, SIOCSIWRATE, &wrq,
+                        "Set Bit Rate");
          continue;
        }
 
@@ -958,7 +961,7 @@ set_info(int                skfd,           /* The socket */
        {
          i++;
          if(i >= count)
-           iw_usage();
+           ABORT_ARG_NUM("Set RTS Threshold", SIOCSIWRTS);
          wrq.u.rts.value = -1;
          wrq.u.rts.fixed = 1;
          wrq.u.rts.disabled = 0;
@@ -972,25 +975,18 @@ set_info(int              skfd,           /* The socket */
                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);
+                   IW_GET_EXT_ERR(skfd, ifname, SIOCGIWRTS, &wrq,
+                                  "Set RTS Threshold");
                    wrq.u.rts.fixed = 1;
                  }
                else                    /* Should be a numeric value */
                  if(sscanf(args[i], "%ld", (unsigned long *) &(wrq.u.rts.value))
                     != 1)
-                   iw_usage();
+                   ABORT_ARG_TYPE("Set RTS Threshold", SIOCSIWRTS, args[i]);
            }
 
-         if(ioctl(skfd, SIOCSIWRTS, &wrq) < 0)
-           {
-             fprintf(stderr, "SIOCSIWRTS: %s\n", strerror(errno));
-             return(-1);
-           }
+         IW_SET_EXT_ERR(skfd, ifname, SIOCSIWRTS, &wrq,
+                        "Set RTS Threshold");
          continue;
        }
 
@@ -999,7 +995,7 @@ set_info(int                skfd,           /* The socket */
        {
          i++;
          if(i >= count)
-           iw_usage();
+           ABORT_ARG_NUM("Set Fragmentation Threshold", SIOCSIWFRAG);
          wrq.u.frag.value = -1;
          wrq.u.frag.fixed = 1;
          wrq.u.frag.disabled = 0;
@@ -1013,25 +1009,20 @@ set_info(int            skfd,           /* The socket */
                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);
+                   IW_GET_EXT_ERR(skfd, ifname, SIOCGIWFRAG, &wrq,
+                                  "Set Fragmentation Threshold");
                    wrq.u.frag.fixed = 1;
                  }
                else                    /* Should be a numeric value */
-                 if(sscanf(args[i], "%ld", (unsigned long *) &(wrq.u.frag.value))
+                 if(sscanf(args[i], "%ld",
+                           (unsigned long *) &(wrq.u.frag.value))
                     != 1)
-                   iw_usage();
+                   ABORT_ARG_TYPE("Set Fragmentation Threshold", SIOCSIWFRAG,
+                                  args[i]);
            }
 
-         if(ioctl(skfd, SIOCSIWFRAG, &wrq) < 0)
-           {
-             fprintf(stderr, "SIOCSIWFRAG: %s\n", strerror(errno));
-             return(-1);
-           }
+         IW_SET_EXT_ERR(skfd, ifname, SIOCSIWFRAG, &wrq,
+                        "Set Fragmentation Threshold");
          continue;
        }
 
@@ -1042,23 +1033,21 @@ set_info(int            skfd,           /* The socket */
 
          i++;
          if(i >= count)
-           iw_usage();
+           ABORT_ARG_NUM("Set Mode", SIOCSIWMODE);
 
          if(sscanf(args[i], "%d", &k) != 1)
            {
              k = 0;
-             while(k < 6 && strncasecmp(args[i], operation_mode[k], 3))
+             while((k < IW_NUM_OPER_MODE) &&
+                   strncasecmp(args[i], iw_operation_mode[k], 3))
                k++;
            }
-         if((k > 5) || (k < 0))
-           iw_usage();
+         if((k >= IW_NUM_OPER_MODE) || (k < 0))
+           ABORT_ARG_TYPE("Set Mode", SIOCSIWMODE, args[i]);
 
          wrq.u.mode = k;
-         if(ioctl(skfd, SIOCSIWMODE, &wrq) < 0)
-           {
-             fprintf(stderr, "SIOCSIWMODE: %s\n", strerror(errno));
-             return(-1);
-           }
+         IW_SET_EXT_ERR(skfd, ifname, SIOCSIWMODE, &wrq,
+                        "Set Mode");
          continue;
        }
 
@@ -1066,7 +1055,7 @@ set_info(int              skfd,           /* The socket */
       if(!strncmp(args[i], "power", 3))
        {
          if(++i >= count)
-           iw_usage();
+           ABORT_ARG_NUM("Set Power Management", SIOCSIWPOWER);
 
          if(!strcasecmp(args[i], "off"))
            wrq.u.power.disabled = 1;   /* i.e. max size */
@@ -1074,12 +1063,8 @@ set_info(int             skfd,           /* The socket */
            if(!strcasecmp(args[i], "on"))
              {
                /* Get old Power info */
-               if(ioctl(skfd, SIOCGIWPOWER, &wrq) < 0)
-                 {
-                   fprintf(stderr, "SIOCGIWFRAG: %s\n", strerror(errno));
-                   return(-1);
-                 }
-               strcpy(wrq.ifr_name, ifname);
+               IW_GET_EXT_ERR(skfd, ifname, SIOCGIWPOWER, &wrq,
+                              "Set Power Management");
                wrq.u.power.disabled = 0;
              }
            else
@@ -1091,18 +1076,33 @@ set_info(int            skfd,           /* The socket */
                wrq.u.power.disabled = 0;
 
                /* Check value modifier */
+               if(!strcasecmp(args[i], "min"))
+                 {
+                   wrq.u.power.flags |= IW_POWER_MIN;
+                   if(++i >= count)
+                     ABORT_ARG_NUM("Set Power Management", SIOCSIWPOWER);
+                 }
+               else
+                 if(!strcasecmp(args[i], "max"))
+                   {
+                     wrq.u.power.flags |= IW_POWER_MAX;
+                     if(++i >= count)
+                       ABORT_ARG_NUM("Set Power Management", SIOCSIWPOWER);
+                   }
+
+               /* Check value type */
                if(!strcasecmp(args[i], "period"))
                  {
-                   wrq.u.power.flags = IW_POWER_PERIOD;
+                   wrq.u.power.flags |= IW_POWER_PERIOD;
                    if(++i >= count)
-                     iw_usage();
+                     ABORT_ARG_NUM("Set Power Management", SIOCSIWPOWER);
                  }
                else
                  if(!strcasecmp(args[i], "timeout"))
                    {
-                     wrq.u.power.flags = IW_POWER_TIMEOUT;
+                     wrq.u.power.flags |= IW_POWER_TIMEOUT;
                      if(++i >= count)
-                       iw_usage();
+                       ABORT_ARG_NUM("Set Power Management", SIOCSIWPOWER);
                    }
 
                /* Is there any value to grab ? */
@@ -1112,8 +1112,8 @@ set_info(int              skfd,           /* The socket */
                    if(index(args[i], 'u')) temp /= MEGA;
                    if(index(args[i], 'm')) temp /= KILO;
                    wrq.u.power.value = (long) temp;
-                   if(wrq.u.power.flags == IW_POWER_ON)
-                     wrq.u.power.flags = IW_POWER_PERIOD;
+                   if((wrq.u.power.flags & IW_POWER_TYPE) == 0)
+                     wrq.u.power.flags |= IW_POWER_PERIOD;
                    ++i;
                    gotone = 1;
                  }
@@ -1138,23 +1138,173 @@ set_info(int           skfd,           /* The socket */
                      }
                  }
                if(!gotone)
-                 iw_usage();
+                 ABORT_ARG_TYPE("Set Power Management", SIOCSIWPOWER,
+                                args[i]);
                --i;
              }
 
-         if(ioctl(skfd, SIOCSIWPOWER, &wrq) < 0)
+         IW_SET_EXT_ERR(skfd, ifname, SIOCSIWPOWER, &wrq,
+                      "Set Power Management");
+         continue;
+       }
+
+#if WIRELESS_EXT > 9
+      /* ---------- Set Transmit-Power ---------- */
+      if(!strncmp(args[i], "txpower", 3))
+       {
+         struct iw_range       range;
+
+         if(++i >= count)
+           ABORT_ARG_NUM("Set Tx Power", SIOCSIWTXPOW);
+
+         /* Extract range info */
+         if(iw_get_range_info(skfd, ifname, &range) < 0)
+           memset(&range, 0, sizeof(range));
+
+         /* Prepare the request */
+         wrq.u.txpower.value = -1;
+         wrq.u.txpower.fixed = 1;
+         wrq.u.txpower.disabled = 0;
+         wrq.u.data.flags = IW_TXPOW_DBM;
+         if(!strcasecmp(args[i], "off"))
+           wrq.u.txpower.disabled = 1; /* i.e. turn radio off */
+         else
+           if(!strcasecmp(args[i], "auto"))
+             wrq.u.txpower.fixed = 0;  /* i.e. use power control */
+           else
+             {
+               if(!strcasecmp(args[i], "fixed"))
+                 {
+                   /* Get old tx-power */
+                   IW_GET_EXT_ERR(skfd, ifname, SIOCGIWTXPOW, &wrq,
+                                  "Set Tx Power");
+                   wrq.u.txpower.fixed = 1;
+                 }
+               else                    /* Should be a numeric value */
+                 {
+                   int         power;
+                   int         ismwatt = 0;
+
+                   /* Get the value */
+                   if(sscanf(args[i], "%ld",
+                             (unsigned long *) &(power)) != 1)
+                     ABORT_ARG_TYPE("Set Tx Power", SIOCSIWTXPOW, args[i]);
+
+                   /* Check if milliwatt */
+                   ismwatt = (index(args[i], 'm') != NULL);
+
+                   /* Convert */
+                   if(range.txpower_capa & IW_TXPOW_MWATT)
+                     {
+                       if(!ismwatt)
+                         power = iw_dbm2mwatt(power);
+                       wrq.u.data.flags = IW_TXPOW_MWATT;
+                     }
+                   else
+                     {
+                       if(ismwatt)
+                         power = iw_mwatt2dbm(power);
+                       wrq.u.data.flags = IW_TXPOW_DBM;
+                     }
+                   wrq.u.bitrate.value = power;
+
+                   /* Check for an additional argument */
+                   if(((i+1) < count) &&
+                      (!strcasecmp(args[i+1], "auto")))
+                     {
+                       wrq.u.txpower.fixed = 0;
+                       ++i;
+                     }
+                   if(((i+1) < count) &&
+                      (!strcasecmp(args[i+1], "fixed")))
+                     {
+                       wrq.u.txpower.fixed = 1;
+                       ++i;
+                     }
+                 }
+             }
+
+         IW_SET_EXT_ERR(skfd, ifname, SIOCSIWTXPOW, &wrq,
+                        "Set Tx Power");
+         continue;
+       }
+#endif
+
+#if WIRELESS_EXT > 10
+      /* ---------- Set Retry limit ---------- */
+      if(!strncmp(args[i], "retry", 3))
+       {
+         double                temp;
+         int           gotone = 0;
+
+         if(++i >= count)
+           ABORT_ARG_NUM("Set Retry Limit", SIOCSIWRETRY);
+
+         /* Default - nope */
+         wrq.u.retry.flags = IW_RETRY_LIMIT;
+         wrq.u.retry.disabled = 0;
+
+         /* Check value modifier */
+         if(!strcasecmp(args[i], "min"))
+           {
+             wrq.u.retry.flags |= IW_RETRY_MIN;
+             if(++i >= count)
+               ABORT_ARG_NUM("Set Retry Limit", SIOCSIWRETRY);
+           }
+         else
+           if(!strcasecmp(args[i], "max"))
+             {
+               wrq.u.retry.flags |= IW_RETRY_MAX;
+               if(++i >= count)
+                 ABORT_ARG_NUM("Set Retry Limit", SIOCSIWRETRY);
+             }
+
+         /* Check value type */
+         if(!strcasecmp(args[i], "limit"))
+           {
+             wrq.u.retry.flags |= IW_RETRY_LIMIT;
+             if(++i >= count)
+               ABORT_ARG_NUM("Set Retry Limit", SIOCSIWRETRY);
+           }
+         else
+           if(!strncasecmp(args[i], "lifetime", 4))
+             {
+               wrq.u.retry.flags |= IW_RETRY_LIFETIME;
+               if(++i >= count)
+                 ABORT_ARG_NUM("Set Retry Limit", SIOCSIWRETRY);
+             }
+
+         /* Is there any value to grab ? */
+         if(sscanf(args[i], "%lg", &(temp)) == 1)
            {
-             fprintf(stderr, "SIOCSIWPOWER(%d): %s\n",
-                     errno, strerror(errno));
-             return(-1);
+             /* Limit is absolute, on the other hand lifetime is seconds */
+             if(!(wrq.u.retry.flags & IW_RETRY_LIMIT))
+               {
+                 /* Normalise lifetime */
+                 temp *= MEGA; /* default = s */
+                 if(index(args[i], 'u')) temp /= MEGA;
+                 if(index(args[i], 'm')) temp /= KILO;
+               }
+             wrq.u.retry.value = (long) temp;
+             ++i;
+             gotone = 1;
            }
+
+         if(!gotone)
+           ABORT_ARG_TYPE("Set Retry Limit", SIOCSIWRETRY, args[i]);
+         --i;
+
+         IW_SET_EXT_ERR(skfd, ifname, SIOCSIWRETRY, &wrq,
+                        "Set Retry Limit");
          continue;
-       }
+       }
+
+#endif /* WIRELESS_EXT > 10 */
 
       /* ---------- Other ---------- */
       /* Here we have an unrecognised arg... */
-      fprintf(stderr, "Invalid argument : %s\n", args[i]);
-      iw_usage();
+      fprintf(stderr, "Error : unrecognised wireless request \"%s\"\n",
+             args[i]);
       return(-1);
     }          /* for(index ... */
   return(0);
@@ -1170,11 +1320,11 @@ int
 main(int       argc,
      char **   argv)
 {
-  int skfd = -1;               /* generic raw socket desc.     */
+  int skfd;            /* generic raw socket desc.     */
   int goterr = 0;
 
   /* Create a channel to the NET kernel. */
-  if((skfd = sockets_open()) < 0)
+  if((skfd = iw_sockets_open()) < 0)
     {
       perror("socket");
       exit(-1);
@@ -1182,36 +1332,22 @@ main(int        argc,
 
   /* No argument : show the list of all device + info */
   if(argc == 1)
-    {
-      print_devices(skfd);
-      close(skfd);
-      exit(0);
-    }
-
-  /* Special case for help... */
-  if((!strncmp(argv[1], "-h", 9)) ||
-     (!strcmp(argv[1], "--help")))
-    {
+    iw_enum_devices(skfd, &print_info, NULL, 0);
+  else
+    /* Special case for 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 */
-  if(argc == 2)
-    {
-      print_info(skfd, argv[1]);
-      close(skfd);
-      exit(0);
-    }
-
-  /* The other args on the line specify options to be set... */
-  goterr = set_info(skfd, argv + 2, argc - 2, argv[1]);
+    else
+      /* The device name must be the first argument */
+      if(argc == 2)
+       print_info(skfd, argv[1], NULL, 0);
+      else
+       /* The other args on the line specify options to be set... */
+       goterr = set_info(skfd, argv + 2, argc - 2, argv[1]);
 
   /* Close the socket. */
   close(skfd);
 
   return(goterr);
 }
-
-