OSDN Git Service

Update to v30-pre9
[android-x86/external-wireless-tools.git] / wireless_tools / iwconfig.c
index b70c049..0780424 100644 (file)
 /*
  *     Wireless Tools
  *
- *             Jean II - HPLB 97->99 - HPL 99->01
+ *             Jean II - HPLB 97->99 - HPL 99->07
  *
  * 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-2007 Jean Tourrilhes <jt@hpl.hp.com>
  */
 
-#include "iwcommon.h"          /* Header */
+#include "iwlib-private.h"             /* Private header */
 
-/**************************** VARIABLES ****************************/
-char * operation_mode[] = { "Auto",
-                            "Ad-Hoc",
-                            "Managed",
-                            "Master",
-                            "Repeater",
-                            "Secondary" };
-
-/************************* MISC SUBROUTINES **************************/
+/**************************** CONSTANTS ****************************/
 
-/*------------------------------------------------------------------*/
 /*
- * Print usage string
+ * Error codes defined for setting args
  */
-static void
-iw_usage(void)
-{
-  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");
-  fprintf(stderr, "                          [power { period N|timeout N}]\n");
-  fprintf(stderr, "                          [txpower N {mW|dBm}]\n");
-  exit(1);
-}
-
+#define IWERR_ARG_NUM          -2
+#define IWERR_ARG_TYPE         -3
+#define IWERR_ARG_SIZE         -4
+#define IWERR_ARG_CONFLICT     -5
+#define IWERR_SET_EXT          -6
+#define IWERR_GET_EXT          -7
 
-/************************* DISPLAY ROUTINES **************************/
+/**************************** VARIABLES ****************************/
 
-/*------------------------------------------------------------------*/
 /*
- * Read /proc/net/wireless to get the latest statistics
+ * Ugly, but deal with errors in set_info() efficiently...
  */
-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;
-}
+static int     errarg;
+static int     errmax;
+
+/************************* DISPLAY ROUTINES **************************/
 
 /*------------------------------------------------------------------*/
 /*
@@ -125,149 +50,103 @@ 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);
-  else
-    strcpy(info->name, wrq.u.name);
-
-  /* Get ranges */
-  if(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)
-    {
-      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)
-    {
-      info->has_freq = 1;
-      info->freq = freq2float(&(wrq.u.freq));
-    }
-
-  /* Get sensitivity */
-  strcpy(wrq.ifr_name, ifname);
-  if(ioctl(skfd, SIOCGIWSENS, &wrq) >= 0)
+  /* Get basic information */
+  if(iw_get_basic_config(skfd, ifname, &(info->b)) < 0)
     {
-      info->has_sens = 1;
-      memcpy(&(info->sens), &(wrq.u.sens), sizeof(iwparam));
-    }
+      /* If no wireless name : no wireless extensions */
+      /* But let's check if the interface exists at all */
+      struct ifreq ifr;
 
-  /* Get encryption information */
-  strcpy(wrq.ifr_name, ifname);
-  wrq.u.data.pointer = (caddr_t) info->key;
-  wrq.u.data.length = 0;
-  wrq.u.data.flags = 0;
-  if(ioctl(skfd, SIOCGIWENCODE, &wrq) >= 0)
-    {
-      info->has_key = 1;
-      info->key_size = wrq.u.data.length;
-      info->key_flags = wrq.u.data.flags;
+      strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
+      if(ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0)
+       return(-ENODEV);
+      else
+       return(-ENOTSUP);
     }
 
-  /* Get ESSID */
-  strcpy(wrq.ifr_name, ifname);
-  wrq.u.essid.pointer = (caddr_t) info->essid;
-  wrq.u.essid.length = 0;
-  wrq.u.essid.flags = 0;
-  if(ioctl(skfd, SIOCGIWESSID, &wrq) >= 0)
-    {
-      info->has_essid = 1;
-      info->essid_on = wrq.u.data.flags;
-    }
+  /* Get ranges */
+  if(iw_get_range_info(skfd, ifname, &(info->range)) >= 0)
+    info->has_range = 1;
 
   /* 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.flags = 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)
+  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)
+  /* Get Power Management settings */
+  wrq.u.power.flags = 0;
+  if(iw_get_ext(skfd, ifname, SIOCGIWPOWER, &wrq) >= 0)
     {
-      info->has_rts = 1;
-      memcpy(&(info->rts), &(wrq.u.rts), sizeof(iwparam));
+      info->has_power = 1;
+      memcpy(&(info->power), &(wrq.u.power), sizeof(iwparam));
     }
 
-  /* Get fragmentation threshold */
-  strcpy(wrq.ifr_name, ifname);
-  if(ioctl(skfd, SIOCGIWFRAG, &wrq) >= 0)
+  /* Get stats */
+  if(iw_get_stats(skfd, ifname, &(info->stats),
+                 &info->range, info->has_range) >= 0)
     {
-      info->has_frag = 1;
-      memcpy(&(info->frag), &(wrq.u.frag), sizeof(iwparam));
+      info->has_stats = 1;
     }
 
-  /* Get operation mode */
-  strcpy(wrq.ifr_name, ifname);
-  if(ioctl(skfd, SIOCGIWMODE, &wrq) >= 0)
+#ifndef WE_ESSENTIAL
+  /* Get NickName */
+  wrq.u.essid.pointer = (caddr_t) info->nickname;
+  wrq.u.essid.length = IW_ESSID_MAX_SIZE + 2;
+  wrq.u.essid.flags = 0;
+  if(iw_get_ext(skfd, ifname, SIOCGIWNICKN, &wrq) >= 0)
+    if(wrq.u.data.length > 1)
+      info->has_nickname = 1;
+
+  if((info->has_range) && (info->range.we_version_compiled > 9))
     {
-      if((wrq.u.mode < 6) && (wrq.u.mode >= 0))
-       info->has_mode = 1;
-      info->mode = wrq.u.mode;
+      /* Get Transmit Power */
+      if(iw_get_ext(skfd, ifname, SIOCGIWTXPOW, &wrq) >= 0)
+       {
+         info->has_txpower = 1;
+         memcpy(&(info->txpower), &(wrq.u.txpower), sizeof(iwparam));
+       }
     }
 
-  /* Get Power Management settings */
-  strcpy(wrq.ifr_name, ifname);
-  wrq.u.power.flags = 0;
-  if(ioctl(skfd, SIOCGIWPOWER, &wrq) >= 0)
+  /* Get sensitivity */
+  if(iw_get_ext(skfd, ifname, SIOCGIWSENS, &wrq) >= 0)
     {
-      info->has_power = 1;
-      memcpy(&(info->power), &(wrq.u.power), sizeof(iwparam));
+      info->has_sens = 1;
+      memcpy(&(info->sens), &(wrq.u.sens), sizeof(iwparam));
     }
 
-#if WIRELESS_EXT > 9
-  /* Get Transmit Power */
-  strcpy(wrq.ifr_name, ifname);
-  if(ioctl(skfd, SIOCGIWTXPOW, &wrq) >= 0)
+  if((info->has_range) && (info->range.we_version_compiled > 10))
     {
-      info->has_txpower = 1;
-      memcpy(&(info->txpower), &(wrq.u.txpower), sizeof(iwparam));
+      /* 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
 
-#if WIRELESS_EXT > 10
-  /* Get retry limit/lifetime */
-  strcpy(wrq.ifr_name, ifname);
-  if(ioctl(skfd, SIOCGIWRETRY, &wrq) >= 0)
+  /* Get RTS threshold */
+  if(iw_get_ext(skfd, ifname, SIOCGIWRTS, &wrq) >= 0)
     {
-      info->has_retry = 1;
-      memcpy(&(info->retry), &(wrq.u.retry), sizeof(iwparam));
+      info->has_rts = 1;
+      memcpy(&(info->rts), &(wrq.u.rts), sizeof(iwparam));
     }
-#endif /* WIRELESS_EXT > 10 */
 
-  /* Get stats */
-  if(iw_getstats(ifname, &(info->stats)) >= 0)
+  /* Get fragmentation threshold */
+  if(iw_get_ext(skfd, ifname, SIOCGIWFRAG, &wrq) >= 0)
     {
-      info->has_stats = 1;
+      info->has_frag = 1;
+      memcpy(&(info->frag), &(wrq.u.frag), sizeof(iwparam));
     }
+#endif /* WE_ESSENTIAL */
 
   return(0);
 }
@@ -281,75 +160,79 @@ static void
 display_info(struct wireless_info *    info,
             char *                     ifname)
 {
-  /* One token is more of less 5 character, 14 tokens per line */
+  char         buffer[256];    /* 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);
+  printf("%-8.16s  %s  ", ifname, info->b.name);
 
   /* Display ESSID (extended network), if any */
-  if(info->has_essid)
+  if(info->b.has_essid)
     {
-      if(info->essid_on)
+      if(info->b.essid_on)
        {
+         /* Escape the non-printable characters */
+         iw_essid_escape(buffer, info->b.essid, info->b.essid_len);
          /* 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));
+         if((info->b.essid_on & IW_ENCODE_INDEX) > 1)
+           printf("ESSID:\"%s\" [%d]  ", buffer,
+                  (info->b.essid_on & IW_ENCODE_INDEX));
          else
-           printf("ESSID:\"%s\"  ", info->essid);
+           printf("ESSID:\"%s\"  ", buffer);
        }
       else
-       printf("ESSID:off  ");
+       printf("ESSID:off/any  ");
     }
 
+#ifndef WE_ESSENTIAL
   /* Display NickName (station name), if any */
   if(info->has_nickname)
     printf("Nickname:\"%s\"", info->nickname);
+#endif /* WE_ESSENTIAL */
 
   /* Formatting */
-  if(info->has_essid || info->has_nickname)
+  if(info->b.has_essid || info->has_nickname)
     {
       printf("\n          ");
       tokens = 0;
     }
 
+#ifndef WE_ESSENTIAL
   /* Display Network ID */
-  if(info->has_nwid)
+  if(info->b.has_nwid)
     {
-      /* Note : should display right number of digit according to info
+      /* Note : should display proper number of digits according to info
        * in range structure */
-      if(info->nwid.disabled)
+      if(info->b.nwid.disabled)
        printf("NWID:off/any  ");
       else
-       printf("NWID:%X  ", info->nwid.value);
+       printf("NWID:%X  ", info->b.nwid.value);
       tokens +=2;
     }
+#endif /* WE_ESSENTIAL */
 
   /* Display the current mode of operation */
-  if(info->has_mode)
+  if(info->b.has_mode)
     {
-      printf("Mode:%s  ", operation_mode[info->mode]);
+      printf("Mode:%s  ", iw_operation_mode[info->b.mode]);
       tokens +=3;
     }
 
   /* Display frequency / channel */
-  if(info->has_freq)
+  if(info->b.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);
-           }
-       }
+      double           freq = info->b.freq;    /* Frequency/channel */
+      int              channel = -1;           /* Converted to channel */
+      /* Some drivers insist of returning channel instead of frequency.
+       * This fixes them up. Note that, driver should still return
+       * frequency, because other tools depend on it. */
+      if(info->has_range && (freq < KILO))
+       channel = iw_channel_to_freq((int) freq, &freq, &info->range);
+      /* Display */
+      iw_print_freq(buffer, sizeof(buffer), freq, -1, info->b.freq_flags);
+      printf("%s  ", buffer);
       tokens +=4;
     }
 
@@ -365,11 +248,11 @@ display_info(struct wireless_info *       info,
       tokens +=6;
 
       /* Oups ! No Access Point in Ad-Hoc mode */
-      if((info->has_mode) && (info->mode == IW_MODE_ADHOC))
+      if((info->b.has_mode) && (info->b.mode == IW_MODE_ADHOC))
        printf("Cell:");
       else
        printf("Access Point:");
-      printf(" %s", pr_ether(info->ap_addr.sa_data));
+      printf(" %s   ", iw_sawap_ntop(&info->ap_addr, buffer));
     }
 
   /* Display the currently used/set bit-rate */
@@ -383,23 +266,12 @@ display_info(struct wireless_info *       info,
        }
       tokens +=3;
 
-      /* Fixed ? */
-      if(info->bitrate.fixed)
-       printf("Bit Rate=");
-      else
-       printf("Bit Rate:");
-
-      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);
-      printf("   ");
+      /* Display it */
+      iw_print_bitrate(buffer, sizeof(buffer), info->bitrate.value);
+      printf("Bit Rate%c%s   ", (info->bitrate.fixed ? '=' : ':'), buffer);
     }
 
-#if WIRELESS_EXT > 9
+#ifndef WE_ESSENTIAL
   /* Display the Transmit Power */
   if(info->has_txpower)
     {
@@ -411,30 +283,10 @@ display_info(struct wireless_info *       info,
        }
       tokens +=3;
 
-      /* Disabled ? */
-      if(info->txpower.disabled)
-       printf("Tx-Power:off   ");
-      else
-       {
-         int           dbm;
-
-         /* Fixed ? */
-         if(info->txpower.fixed)
-           printf("Tx-Power=");
-         else
-           printf("Tx-Power:");
-
-         /* Convert everything to dBm */
-         if(info->txpower.flags & IW_TXPOW_MWATT)
-           dbm = mwatt2dbm(info->txpower.value);
-         else
-           dbm = info->txpower.value;
-
-         /* Display */
-         printf("%d dBm   ", dbm);
-       }
+      /* Display it */
+      iw_print_txpower(buffer, sizeof(buffer), &info->txpower);
+      printf("Tx-Power%c%s   ", (info->txpower.fixed ? '=' : ':'), buffer);
     }
-#endif
 
   /* Display sensitivity */
   if(info->has_sens)
@@ -448,10 +300,7 @@ display_info(struct wireless_info *        info,
       tokens +=4;
 
       /* Fixed ? */
-      if(info->sens.fixed)
-       printf("Sensitivity=");
-      else
-       printf("Sensitivity:");
+      printf("Sensitivity%c", info->sens.fixed ? '=' : ':');
 
       if(info->has_range)
        /* Display in dBm ? */
@@ -462,11 +311,12 @@ display_info(struct wireless_info *       info,
       else
        printf("%d  ", info->sens.value);
     }
+#endif /* WE_ESSENTIAL */
 
   printf("\n          ");
   tokens = 0;
 
-#if WIRELESS_EXT > 10
+#ifndef WE_ESSENTIAL
   /* Display retry limit/lifetime information */
   if(info->has_retry)
     { 
@@ -478,7 +328,12 @@ display_info(struct wireless_info *        info,
        {
          /* Let's check the value and its type */
          if(info->retry.flags & IW_RETRY_TYPE)
-           print_retry_value(stdout, info->retry.value, info->retry.flags);
+           {
+             iw_print_retry_value(buffer, sizeof(buffer),
+                                  info->retry.value, info->retry.flags,
+                                  info->range.we_version_compiled);
+             printf("%s", buffer);
+           }
 
          /* Let's check if nothing (simply on) */
          if(info->retry.flags == IW_RETRY_ON)
@@ -487,7 +342,6 @@ display_info(struct wireless_info * info,
       printf("   ");
       tokens += 5;     /* Between 3 and 5, depend on flags */
     }
-#endif /* WIRELESS_EXT > 10 */
 
   /* Display the RTS threshold */
   if(info->has_rts)
@@ -498,12 +352,9 @@ display_info(struct wireless_info *        info,
       else
        {
          /* Fixed ? */
-         if(info->rts.fixed)
-           printf("RTS thr=");
-         else
-           printf("RTS thr:");
-
-         printf("%d B   ", info->rts.value);
+         printf("RTS thr%c%d B   ",
+                info->rts.fixed ? '=' : ':',
+                info->rts.value);
        }
       tokens += 3;
     }
@@ -525,40 +376,40 @@ display_info(struct wireless_info *       info,
       else
        {
          /* Fixed ? */
-         if(info->frag.fixed)
-           printf("Fragment thr=");
-         else
-           printf("Fragment thr:");
-
-         printf("%d B   ", info->frag.value);
+         printf("Fragment thr%c%d B   ",
+                info->frag.fixed ? '=' : ':',
+                info->frag.value);
        }
     }
 
   /* Formating */
   if(tokens > 0)
     printf("\n          ");
+#endif /* WE_ESSENTIAL */
 
   /* Display encryption information */
   /* Note : we display only the "current" key, use iwlist to list all keys */
-  if(info->has_key)
+  if(info->b.has_key)
     {
       printf("Encryption key:");
-      if((info->key_flags & IW_ENCODE_DISABLED) || (info->key_size == 0))
-       printf("off\n          ");
+      if((info->b.key_flags & IW_ENCODE_DISABLED) || (info->b.key_size == 0))
+       printf("off");
       else
        {
          /* Display the key */
-         print_key(stdout, info->key, info->key_size, info->key_flags);
+         iw_print_key(buffer, sizeof(buffer),
+                      info->b.key, info->b.key_size, info->b.key_flags);
+         printf("%s", buffer);
 
          /* Other info... */
-         if((info->key_flags & IW_ENCODE_INDEX) > 1)
-           printf(" [%d]", info->key_flags & IW_ENCODE_INDEX);
-         if(info->key_flags & IW_ENCODE_RESTRICTED)
-           printf("   Encryption mode:restricted");
-         if(info->key_flags & IW_ENCODE_OPEN)
-           printf("   Encryption mode:open");
-         printf("\n          ");
+         if((info->b.key_flags & IW_ENCODE_INDEX) > 1)
+           printf(" [%d]", info->b.key_flags & IW_ENCODE_INDEX);
+         if(info->b.key_flags & IW_ENCODE_RESTRICTED)
+           printf("   Security mode:restricted");
+         if(info->b.key_flags & IW_ENCODE_OPEN)
+           printf("   Security mode:open");
        }
+      printf("\n          ");
     }
 
   /* Display Power Management information */
@@ -569,34 +420,49 @@ display_info(struct wireless_info *       info,
       printf("Power Management");
       /* Disabled ? */
       if(info->power.disabled)
-       printf(":off\n          ");
+       printf(":off");
       else
        {
          /* Let's check the value and its type */
          if(info->power.flags & IW_POWER_TYPE)
-           print_pm_value(stdout, info->power.value, info->power.flags);
+           {
+             iw_print_pm_value(buffer, sizeof(buffer),
+                               info->power.value, info->power.flags,
+                               info->range.we_version_compiled);
+             printf("%s  ", buffer);
+           }
 
          /* Let's check the mode */
-         print_pm_mode(stdout, info->power.flags);
+         iw_print_pm_mode(buffer, sizeof(buffer), info->power.flags);
+         printf("%s", buffer);
 
          /* Let's check if nothing (simply on) */
          if(info->power.flags == IW_POWER_ON)
            printf(":on");
-         printf("\n          ");
        }
+      printf("\n          ");
     }
 
   /* Display statistics */
   if(info->has_stats)
     {
-      info->stats.qual.updated = 0x0;  /* Not that reliable, disable */
-      printf("Link ");
-      print_stats(stdout, &info->stats.qual, &info->range, info->has_range);
-
-      printf("          Rx invalid nwid:%d  invalid crypt:%d  invalid misc:%d\n",
-            info->stats.discard.nwid,
-            info->stats.discard.code,
-            info->stats.discard.misc);
+      iw_print_stats(buffer, sizeof(buffer),
+                    &info->stats.qual, &info->range, info->has_range);
+      printf("Link %s\n", buffer);
+
+      if(info->range.we_version_compiled > 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
+       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");
@@ -607,826 +473,1444 @@ 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)
     {
-      fprintf(stderr, "%-8.8s  no wireless extensions.\n\n",
+    case 0:    /* Success */
+      /* Display it ! */
+      display_info(&info, ifname);
+      break;
+
+    case -ENOTSUP:
+      fprintf(stderr, "%-8.16s  no wireless extensions.\n\n",
              ifname);
-      return;
-    }
+      break;
 
-  /* Display it ! */
-  display_info(&info, ifname);
+    default:
+      fprintf(stderr, "%-8.16s  %s\n\n", ifname, strerror(-rc));
+    }
+  return(rc);
 }
 
+/****************** COMMAND LINE MODIFIERS PARSING ******************/
+/*
+ * Factor out the parsing of command line modifiers.
+ */
+
 /*------------------------------------------------------------------*/
 /*
- * Get info on all devices and print it on the screen
+ * Map command line modifiers to the proper flags...
  */
-static void
-print_devices(int      skfd)
+typedef struct iwconfig_modifier {
+  const char *         cmd;            /* Command line shorthand */
+  __u16                        flag;           /* Flags to add */
+  __u16                        exclude;        /* Modifiers to exclude */
+} iwconfig_modifier;
+
+/*------------------------------------------------------------------*/
+/*
+ * Modifiers for Power
+ */
+static const struct iwconfig_modifier  iwmod_power[] = {
+  { "min",     IW_POWER_MIN,           IW_POWER_MAX },
+  { "max",     IW_POWER_MAX,           IW_POWER_MIN },
+  { "period",  IW_POWER_PERIOD,        IW_POWER_TIMEOUT | IW_POWER_SAVING },
+  { "timeout", IW_POWER_TIMEOUT,       IW_POWER_PERIOD | IW_POWER_SAVING },
+  { "saving",  IW_POWER_SAVING,        IW_POWER_TIMEOUT | IW_POWER_PERIOD },
+};
+#define IWMOD_POWER_NUM        (sizeof(iwmod_power)/sizeof(iwmod_power[0]))
+
+/*------------------------------------------------------------------*/
+/*
+ * Modifiers for Retry
+ */
+#ifndef WE_ESSENTIAL
+static const struct iwconfig_modifier  iwmod_retry[] = {
+  { "min",     IW_RETRY_MIN,           IW_RETRY_MAX },
+  { "max",     IW_RETRY_MAX,           IW_RETRY_MIN },
+  { "short",   IW_RETRY_SHORT,         IW_RETRY_LONG },
+  { "long",    IW_RETRY_LONG,          IW_RETRY_SHORT },
+  { "limit",   IW_RETRY_LIMIT,         IW_RETRY_LIFETIME },
+  { "lifetime",        IW_RETRY_LIFETIME,      IW_RETRY_LIMIT },
+};
+#define IWMOD_RETRY_NUM        (sizeof(iwmod_retry)/sizeof(iwmod_retry[0]))
+#endif /* WE_ESSENTIAL */
+
+/*------------------------------------------------------------------*/
+/*
+ * Parse command line modifiers.
+ * Return error or number arg parsed.
+ * Modifiers must be at the beggining of command line.
+ */
+static int
+parse_modifiers(char *         args[],         /* Command line args */
+               int             count,          /* Args count */
+               __u16 *         pout,           /* Flags to write */
+               const struct iwconfig_modifier  modifier[],
+               int             modnum)
 {
-  char buff[1024];
-  struct ifconf ifc;
-  struct ifreq *ifr;
-  int i;
+  int          i = 0;
+  int          k = 0;
+  __u16                result = 0;     /* Default : no flag set */
 
-  /* Get list of active devices */
-  ifc.ifc_len = sizeof(buff);
-  ifc.ifc_buf = buff;
-  if(ioctl(skfd, SIOCGIFCONF, &ifc) < 0)
+  /* Get all modifiers and value types on the command line */
+  do
     {
-      fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno));
-      return;
+      for(k = 0; k < modnum; k++)
+       {
+         /* Check if matches */
+         if(!strcasecmp(args[i], modifier[k].cmd))
+           {
+             /* Check for conflicting flags */
+             if(result & modifier[k].exclude)
+               {
+                 errarg = i;
+                 return(IWERR_ARG_CONFLICT);
+               }
+             /* Just add it */
+             result |= modifier[k].flag;
+             ++i;
+             break;
+           }
+       }
     }
-  ifr = ifc.ifc_req;
+  /* For as long as current arg matched and not out of args */
+  while((i < count) && (k < modnum));
 
-  /* Print them */
-  for(i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++)
-    print_info(skfd, ifr->ifr_name);
+  /* Check there remains one arg for value */
+  if(i >= count)
+    return(IWERR_ARG_NUM);
+
+  /* Return result */
+  *pout = result;
+  return(i);
 }
 
-/************************* SETTING ROUTINES **************************/
+
+/*********************** SETTING SUB-ROUTINES ***********************/
+/*
+ * The following functions are use to set some wireless parameters and
+ * are called by the set dispatcher set_info().
+ * They take as arguments the remaining of the command line, with
+ * arguments processed already removed.
+ * An error is indicated by a negative return value.
+ * 0 and positive return values indicate the number of args consumed.
+ */
 
 /*------------------------------------------------------------------*/
 /*
- * 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
+ * Set ESSID
  */
 static int
-set_info(int           skfd,           /* The socket */
-        char *         args[],         /* Command line args */
-        int            count,          /* Args count */
-        char *         ifname)         /* Dev name */
+set_essid_info(int             skfd,
+              char *           ifname,
+              char *           args[],         /* Command line args */
+              int              count)          /* Args count */
 {
   struct iwreq         wrq;
-  int                  i;
+  int                  i = 1;
+  char                 essid[4*IW_ESSID_MAX_SIZE + 1];
+  int                  essid_len;
+  int                  essid_index;
+  int                  we_kernel_version;
+
+  if((!strcasecmp(args[0], "off")) ||
+     (!strcasecmp(args[0], "any")))
+    {
+      wrq.u.essid.flags = 0;
+      essid[0] = '\0';
+      essid_len = 0;
+    }
+  else
+    if(!strcasecmp(args[0], "on"))
+      {
+       /* Get old essid */
+       memset(essid, '\0', sizeof(essid));
+       wrq.u.essid.pointer = (caddr_t) essid;
+       wrq.u.essid.length = IW_ESSID_MAX_SIZE + 2;
+       wrq.u.essid.flags = 0;
+       if(iw_get_ext(skfd, ifname, SIOCGIWESSID, &wrq) < 0)
+         return(IWERR_GET_EXT);
+       wrq.u.essid.flags = 1;
+       essid_len = wrq.u.essid.length;
+      }
+    else
+      {
+       i = 0;
+
+       /* '-' or '--' allow to escape the ESSID string, allowing
+        * to set it to the string "any" or "off".
+        * This is a big ugly, but it will do for now */
+       if((!strcmp(args[0], "-")) || (!strcmp(args[0], "--")))
+         {
+           if(++i >= count)
+             return(IWERR_ARG_NUM);
+           essid_len = strlen(args[i]);
+         }
+
+       /* First size check : check if ot fits in our internal buffer.
+        * We do a two pass size check because of unescaping */
+       if(strlen(args[i]) > (4*IW_ESSID_MAX_SIZE))
+         {
+           errmax = IW_ESSID_MAX_SIZE;
+           return(IWERR_ARG_SIZE);
+         }
+
+       /* Unescape the ESSID to allow the user to enter weird chars */
+       essid_len = iw_essid_unescape(essid, args[i]);
+
+       /* Check the size to see if it fits the API. */
+       if(essid_len > IW_ESSID_MAX_SIZE)
+         {
+           errmax = IW_ESSID_MAX_SIZE;
+           return(IWERR_ARG_SIZE);
+         }
+
+       wrq.u.essid.flags = 1;
+       i++;
+
+       /* Check for ESSID index */
+       if((i < count) &&
+          (sscanf(args[i], "[%i]", &essid_index) == 1) &&
+          (essid_index > 0) && (essid_index < IW_ENCODE_INDEX))
+         {
+           wrq.u.essid.flags = essid_index;
+           ++i;
+         }
+      }
+
+  /* Get version from kernel, device may not have range... */
+  we_kernel_version = iw_get_kernel_we_version();
+
+  /* Finally set the ESSID value */
+  wrq.u.essid.pointer = (caddr_t) essid;
+  wrq.u.essid.length = essid_len;
+  if(we_kernel_version < 21)
+    wrq.u.essid.length++;
+
+  if(iw_set_ext(skfd, ifname, SIOCSIWESSID, &wrq) < 0)
+    return(IWERR_SET_EXT);
+
+  /* Var args */
+  return(i);
+}
 
-  /* Set dev name */
-  strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
+/*------------------------------------------------------------------*/
+/*
+ * Set Mode
+ */
+static int
+set_mode_info(int              skfd,
+             char *            ifname,
+             char *            args[],         /* Command line args */
+             int               count)          /* Args count */
+{
+  struct iwreq         wrq;
+  unsigned int         k;              /* Must be unsigned */
 
-  /* if nothing after the device name */
-  if(count<1)
-    iw_usage();
+  /* Avoid "Unused parameter" warning */
+  count = count;
 
-  /* The other args on the line specify options to be set... */
-  for(i = 0; i < count; i++)
+  /* Check if it is a uint, otherwise get is as a string */
+  if(sscanf(args[0], "%i", &k) != 1)
     {
-      /* ---------- Set network ID ---------- */
-      if((!strcasecmp(args[i], "nwid")) ||
-        (!strcasecmp(args[i], "domain")))
-       {
-         i++;
-         if(i >= count)
-           iw_usage();
-         if((!strcasecmp(args[i], "off")) ||
-            (!strcasecmp(args[i], "any")))
-           wrq.u.nwid.disabled = 1;
-         else
-           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.disabled = 0;
-             }
-           else
-             if(sscanf(args[i], "%lX", (unsigned long *) &(wrq.u.nwid.value))
-                != 1)
-               iw_usage();
-             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);
-           }
-         continue;
-       }
+      k = 0;
+      while((k < IW_NUM_OPER_MODE) &&
+           strncasecmp(args[0], iw_operation_mode[k], 3))
+       k++;
+    }
+  if(k >= IW_NUM_OPER_MODE)
+    {
+      errarg = 0;
+      return(IWERR_ARG_TYPE);
+    }
 
-      /* ---------- Set frequency / channel ---------- */
-      if((!strncmp(args[i], "freq", 4)) ||
-        (!strcmp(args[i], "channel")))
-       {
-         double                freq;
+  wrq.u.mode = k;
+  if(iw_set_ext(skfd, ifname, SIOCSIWMODE, &wrq) < 0)
+    return(IWERR_SET_EXT);
 
-         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;
+  /* 1 arg */
+  return(1);
+}
 
-         float2freq(freq, &(wrq.u.freq));
+/*------------------------------------------------------------------*/
+/*
+ * Set frequency/channel
+ */
+static int
+set_freq_info(int              skfd,
+             char *            ifname,
+             char *            args[],         /* Command line args */
+             int               count)          /* Args count */
+{
+  struct iwreq         wrq;
+  int                  i = 1;
 
-         if(ioctl(skfd, SIOCSIWFREQ, &wrq) < 0)
-           {
-             fprintf(stderr, "SIOCSIWFREQ: %s\n", strerror(errno));
-             return(-1);
-           }
-         continue;
+  if(!strcasecmp(args[0], "auto"))
+    {
+      wrq.u.freq.m = -1;
+      wrq.u.freq.e = 0;
+      wrq.u.freq.flags = 0;
+    }
+  else
+    {
+      if(!strcasecmp(args[0], "fixed"))
+       {
+         /* Get old frequency */
+         if(iw_get_ext(skfd, ifname, SIOCGIWFREQ, &wrq) < 0)
+           return(IWERR_GET_EXT);
+         wrq.u.freq.flags = IW_FREQ_FIXED;
        }
-
-      /* ---------- Set sensitivity ---------- */
-      if(!strncmp(args[i], "sens", 4))
+      else                     /* Should be a numeric value */
        {
-         if(++i >= count)
-           iw_usage();
-         if(sscanf(args[i], "%d", &(wrq.u.sens.value)) != 1)
-           iw_usage();
+         double                freq;
+         char *                unit;
 
-         if(ioctl(skfd, SIOCSIWSENS, &wrq) < 0)
+         freq = strtod(args[0], &unit);
+         if(unit == args[0])
            {
-             fprintf(stderr, "SIOCSIWSENS: %s\n", strerror(errno));
-             return(-1);
+             errarg = 0;
+             return(IWERR_ARG_TYPE);
+           }
+         if(unit != NULL)
+           {
+             if(unit[0] == 'G') freq *= GIGA;
+             if(unit[0] == 'M') freq *= MEGA;
+             if(unit[0] == 'k') freq *= KILO;
            }
-         continue;
-       }
 
-      /* ---------- Set encryption stuff ---------- */
-      if((!strncmp(args[i], "enc", 3)) ||
-        (!strcmp(args[i], "key")))
-       {
-         unsigned char key[IW_ENCODING_TOKEN_MAX];
+         iw_float2freq(freq, &(wrq.u.freq));
 
-         if(++i >= count)
-           iw_usage();
+         wrq.u.freq.flags = IW_FREQ_FIXED;
 
-         if(!strcasecmp(args[i], "on"))
+         /* Check for an additional argument */
+         if((i < count) && (!strcasecmp(args[i], "auto")))
            {
-             /* Get old encryption information */
-             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);
-             wrq.u.data.flags &= ~IW_ENCODE_DISABLED;  /* Enable */
+             wrq.u.freq.flags = 0;
+             ++i;
            }
-         else
+         if((i < count) && (!strcasecmp(args[i], "fixed")))
            {
-             char *    buff;
-             char *    p;
-             int               temp;
-             int               k = 0;
-             int               gotone = 1;
-
-             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))
-               {
-                 /* 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.pointer = (caddr_t) key;
-                 ++i;
-                 gotone = 1;
-               }
-             else
-               {
-                 /* Second case : has hexadecimal digits */
-                 p = buff = malloc(strlen(args[i]) + 1);
-                 strcpy(buff, args[i]);
+             wrq.u.freq.flags = IW_FREQ_FIXED;
+             ++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(iw_set_ext(skfd, ifname, SIOCSIWFREQ, &wrq) < 0)
+    return(IWERR_SET_EXT);
 
-                 if(gotone)
-                   {
-                     ++i;
-                     wrq.u.data.length = k;
-                     wrq.u.data.pointer = (caddr_t) key;
-                   }
-               }
+  /* Var args */
+  return(i);
+}
 
-             /* -- Check for token index -- */
-             if((i < count) &&
-                (sscanf(args[i], "[%d]", &temp) == 1) &&
-                (temp > 0) && (temp < IW_ENCODE_INDEX))
-               {
-                 wrq.u.encoding.flags |= temp;
-                 ++i;
-                 gotone = 1;
-               }
+/*------------------------------------------------------------------*/
+/*
+ * Set Bit Rate
+ */
+static int
+set_bitrate_info(int           skfd,
+                char *         ifname,
+                char *         args[],         /* Command line args */
+                int            count)          /* Args count */
+{
+  struct iwreq         wrq;
+  int                  i = 1;
 
-             /* -- Check the various flags -- */
-             if(i < count)
-               {
-                 if(!strcasecmp(args[i], "off"))
-                   wrq.u.data.flags |= IW_ENCODE_DISABLED;
-                 if(!strcasecmp(args[i], "open"))
-                   wrq.u.data.flags |= IW_ENCODE_OPEN;
-                 if(!strncasecmp(args[i], "restricted", 5))
-                   wrq.u.data.flags |= IW_ENCODE_RESTRICTED;
-                 if(wrq.u.data.flags & IW_ENCODE_FLAGS)
-                   {
-                     ++i;
-                     gotone = 1;
-                   }
-               }
+  wrq.u.bitrate.flags = 0;
+  if(!strcasecmp(args[0], "auto"))
+    {
+      wrq.u.bitrate.value = -1;
+      wrq.u.bitrate.fixed = 0;
+    }
+  else
+    {
+      if(!strcasecmp(args[0], "fixed"))
+       {
+         /* Get old bitrate */
+         if(iw_get_ext(skfd, ifname, SIOCGIWRATE, &wrq) < 0)
+           return(IWERR_GET_EXT);
+         wrq.u.bitrate.fixed = 1;
+       }
+      else                     /* Should be a numeric value */
+       {
+         double                brate;
+         char *                unit;
 
-             if(!gotone)
-               iw_usage();
-             --i;
+         brate = strtod(args[0], &unit);
+         if(unit == args[0])
+           {
+             errarg = 0;
+             return(IWERR_ARG_TYPE);
            }
-
-         if(ioctl(skfd, SIOCSIWENCODE, &wrq) < 0)
+         if(unit != NULL)
            {
-             fprintf(stderr, "SIOCSIWENCODE(%d): %s\n",
-                     errno, strerror(errno));
-             return(-1);
+             if(unit[0] == 'G') brate *= GIGA;
+             if(unit[0] == 'M') brate *= MEGA;
+             if(unit[0] == 'k') brate *= KILO;
            }
-         continue;
-       }
-
-      /* ---------- Set ESSID ---------- */
-      if(!strcasecmp(args[i], "essid"))
-       {
-         char          essid[IW_ESSID_MAX_SIZE + 1];
+         wrq.u.bitrate.value = (long) brate;
+         wrq.u.bitrate.fixed = 1;
 
-         i++;
-         if(i >= count)
-           iw_usage();
-         if((!strcasecmp(args[i], "off")) ||
-            (!strcasecmp(args[i], "any")))
+         /* Check for an additional argument */
+         if((i < count) && (!strcasecmp(args[i], "auto")))
            {
-             wrq.u.essid.flags = 0;
-             essid[0] = '\0';
+             wrq.u.bitrate.fixed = 0;
+             ++i;
            }
-         else
-           if(!strcasecmp(args[i], "on"))
-             {
-               /* Get old essid */
-               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);
-               wrq.u.essid.flags = 1;
-             }
-           else
-             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();
-               }
-             else
-               {
-                 int           temp;
-
-                 wrq.u.essid.flags = 1;
-                 strcpy(essid, args[i]);
-
-                 /* 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)
+         if((i < count) && (!strcasecmp(args[i], "fixed")))
            {
-             fprintf(stderr, "SIOCSIWESSID: %s\n", strerror(errno));
-             return(-1);
+             wrq.u.bitrate.fixed = 1;
+             ++i;
            }
-         continue;
-       }
-
-      /* ---------- Set AP address ---------- */
-      if(!strcasecmp(args[i], "ap"))
-       {
-         if(++i >= count)
-           iw_usage();
-
-         /* Check if we have valid address types */
-         if(check_addr_type(skfd, ifname) < 0)
+         if((i < count) && (!strcasecmp(args[i], "unicast")))
            {
-             fprintf(stderr, "%-8.8s  Interface doesn't support MAC & IP addresses\n", ifname);
-             return(-1);
+             wrq.u.bitrate.flags |= IW_BITRATE_UNICAST;
+             ++i;
            }
-
-         /* Get the address */
-         if(in_addr(skfd, ifname, args[i++], &(wrq.u.ap_addr)) < 0)
-           iw_usage();
-
-         if(ioctl(skfd, SIOCSIWAP, &wrq) < 0)
+         if((i < count) && (!strcasecmp(args[i], "broadcast")))
            {
-             fprintf(stderr, "SIOCSIWAP: %s\n", strerror(errno));
-             return(-1);
+             wrq.u.bitrate.flags |= IW_BITRATE_BROADCAST;
+             ++i;
            }
-         continue;
        }
+    }
+
+  if(iw_set_ext(skfd, ifname, SIOCSIWRATE, &wrq) < 0)
+    return(IWERR_SET_EXT);
 
-      /* ---------- Set NickName ---------- */
-      if(!strncmp(args[i], "nick", 4))
+  /* Var args */
+  return(i);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Set encryption
+ */
+static int
+set_enc_info(int               skfd,
+            char *             ifname,
+            char *             args[],         /* Command line args */
+            int                count)          /* Args count */
+{
+  struct iwreq         wrq;
+  int                  i = 1;
+  unsigned char                key[IW_ENCODING_TOKEN_MAX];
+
+  if(!strcasecmp(args[0], "on"))
+    {
+      /* Get old encryption information */
+      wrq.u.data.pointer = (caddr_t) key;
+      wrq.u.data.length = IW_ENCODING_TOKEN_MAX;
+      wrq.u.data.flags = 0;
+      if(iw_get_ext(skfd, ifname, SIOCGIWENCODE, &wrq) < 0)
+       return(IWERR_GET_EXT);
+      wrq.u.data.flags &= ~IW_ENCODE_DISABLED; /* Enable */
+    }
+  else
+    {
+      int      gotone = 0;
+      int      oldone;
+      int      keylen;
+      int      temp;
+
+      wrq.u.data.pointer = (caddr_t) NULL;
+      wrq.u.data.flags = 0;
+      wrq.u.data.length = 0;
+      i = 0;
+
+      /* Allow arguments in any order (it's safe) */
+      do
        {
-         i++;
-         if(i >= count)
-           iw_usage();
-         if(strlen(args[i]) > IW_ESSID_MAX_SIZE)
+         oldone = gotone;
+
+         /* -- Check for the key -- */
+         if(i < count)
            {
-             fprintf(stderr, "Name too long (max %d) : ``%s''\n",
-                     IW_ESSID_MAX_SIZE, args[i]);
-             iw_usage();
+             keylen = iw_in_key_full(skfd, ifname,
+                                     args[i], key, &wrq.u.data.flags);
+             if(keylen > 0)
+               {
+                 wrq.u.data.length = keylen;
+                 wrq.u.data.pointer = (caddr_t) key;
+                 ++i;
+                 gotone++;
+               }
            }
 
-         wrq.u.essid.pointer = (caddr_t) args[i];
-         wrq.u.essid.length = strlen(args[i]) + 1;
-         if(ioctl(skfd, SIOCSIWNICKN, &wrq) < 0)
+         /* -- Check for token index -- */
+         if((i < count) &&
+            (sscanf(args[i], "[%i]", &temp) == 1) &&
+            (temp > 0) && (temp < IW_ENCODE_INDEX))
            {
-             fprintf(stderr, "SIOCSIWNICKN: %s\n", strerror(errno));
-             return(-1);
+             wrq.u.encoding.flags |= temp;
+             ++i;
+             gotone++;
            }
-         continue;
-       }
 
-      /* ---------- Set Bit-Rate ---------- */
-      if((!strncmp(args[i], "bit", 3)) ||
-        (!strcmp(args[i], "rate")))
-       {
-         if(++i >= count)
-           iw_usage();
-         if(!strcasecmp(args[i], "auto"))
+         /* -- Check the various flags -- */
+         if((i < count) && (!strcasecmp(args[i], "off")))
            {
-             wrq.u.bitrate.value = -1;
-             wrq.u.bitrate.fixed = 0;
+             wrq.u.data.flags |= IW_ENCODE_DISABLED;
+             ++i;
+             gotone++;
            }
-         else
+         if((i < count) && (!strcasecmp(args[i], "open")))
            {
-             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);
-                 wrq.u.bitrate.fixed = 1;
-               }
-             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;
-
-                 /* Check for an additional argument */
-                 if(((i+1) < count) &&
-                    (!strcasecmp(args[i+1], "auto")))
-                   {
-                     wrq.u.bitrate.fixed = 0;
-                     ++i;
-                   }
-                 if(((i+1) < count) &&
-                    (!strcasecmp(args[i+1], "fixed")))
-                   {
-                     wrq.u.bitrate.fixed = 1;
-                     ++i;
-                   }
-               }
+             wrq.u.data.flags |= IW_ENCODE_OPEN;
+             ++i;
+             gotone++;
            }
-
-         if(ioctl(skfd, SIOCSIWRATE, &wrq) < 0)
+         if((i < count) && (!strncasecmp(args[i], "restricted", 5)))
            {
-             fprintf(stderr, "SIOCSIWRATE: %s\n", strerror(errno));
-             return(-1);
-           }
-         continue;
-       }
-
-      /* ---------- Set RTS threshold ---------- */
-      if(!strncasecmp(args[i], "rts", 3))
-       {
-         i++;
-         if(i >= count)
-           iw_usage();
-         wrq.u.rts.value = -1;
-         wrq.u.rts.fixed = 1;
-         wrq.u.rts.disabled = 0;
-         if(!strcasecmp(args[i], "off"))
-           wrq.u.rts.disabled = 1;     /* i.e. max size */
-         else
-           if(!strcasecmp(args[i], "auto"))
-             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);
-                   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();
+             wrq.u.data.flags |= IW_ENCODE_RESTRICTED;
+             ++i;
+             gotone++;
            }
-
-         if(ioctl(skfd, SIOCSIWRTS, &wrq) < 0)
+         if((i < count) && (!strncasecmp(args[i], "temporary", 4)))
            {
-             fprintf(stderr, "SIOCSIWRTS: %s\n", strerror(errno));
-             return(-1);
+             wrq.u.data.flags |= IW_ENCODE_TEMP;
+             ++i;
+             gotone++;
            }
-         continue;
        }
+      while(gotone != oldone);
 
-      /* ---------- Set fragmentation threshold ---------- */
-      if(!strncmp(args[i], "frag", 4))
+      /* Pointer is absent in new API */
+      if(wrq.u.data.pointer == NULL)
+       wrq.u.data.flags |= IW_ENCODE_NOKEY;
+
+      /* Check if we have any invalid argument */
+      if(!gotone)
        {
-         i++;
-         if(i >= count)
-           iw_usage();
-         wrq.u.frag.value = -1;
-         wrq.u.frag.fixed = 1;
-         wrq.u.frag.disabled = 0;
-         if(!strcasecmp(args[i], "off"))
-           wrq.u.frag.disabled = 1;    /* i.e. max size */
-         else
-           if(!strcasecmp(args[i], "auto"))
-             wrq.u.frag.fixed = 0;
+         errarg = 0;
+         return(IWERR_ARG_TYPE);
+       }
+    }
+
+  if(iw_set_ext(skfd, ifname, SIOCSIWENCODE, &wrq) < 0)
+    return(IWERR_SET_EXT);
+
+  /* Var arg */
+  return(i);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Set Power Management
+ */
+static int
+set_power_info(int             skfd,
+              char *           ifname,
+              char *           args[],         /* Command line args */
+              int              count)          /* Args count */
+{
+  struct iwreq         wrq;
+  int                  i = 1;
+
+  if(!strcasecmp(args[0], "off"))
+    wrq.u.power.disabled = 1;  /* i.e. max size */
+  else
+    if(!strcasecmp(args[0], "on"))
+      {
+       /* Get old Power info */
+       wrq.u.power.flags = 0;
+       if(iw_get_ext(skfd, ifname, SIOCGIWPOWER, &wrq) < 0)
+         return(IWERR_GET_EXT);
+       wrq.u.power.disabled = 0;
+      }
+    else
+      {
+       double          value;
+       char *          unit;
+       int             gotone = 0;
+
+       /* Parse modifiers */
+       i = parse_modifiers(args, count, &wrq.u.power.flags,
+                           iwmod_power, IWMOD_POWER_NUM);
+       if(i < 0)
+         return(i);
+
+       wrq.u.power.disabled = 0;
+
+       /* Is there any value to grab ? */
+       value = strtod(args[i], &unit);
+       if(unit != args[i])
+         {
+           struct iw_range     range;
+           int                 flags;
+           /* Extract range info to handle properly 'relative' */
+           if(iw_get_range_info(skfd, ifname, &range) < 0)
+             memset(&range, 0, sizeof(range));
+
+           /* Get the flags to be able to do the proper conversion */
+           switch(wrq.u.power.flags & IW_POWER_TYPE)
+             {
+             case IW_POWER_SAVING:
+               flags = range.pms_flags;
+               break;
+             case IW_POWER_TIMEOUT:
+               flags = range.pmt_flags;
+               break;
+             default:
+               flags = range.pmp_flags;
+               break;
+             }
+           /* Check if time or relative */
+           if(flags & IW_POWER_RELATIVE)
+             {
+               if(range.we_version_compiled < 21)
+                 value *= MEGA;
+               else
+                 wrq.u.power.flags |= IW_POWER_RELATIVE;
+             }
            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);
-                   wrq.u.frag.fixed = 1;
-                 }
-               else                    /* Should be a numeric value */
-                 if(sscanf(args[i], "%ld", (unsigned long *) &(wrq.u.frag.value))
-                    != 1)
-                   iw_usage();
-           }
+               value *= MEGA;  /* default = s */
+               if(unit[0] == 'u') value /= MEGA;
+               if(unit[0] == 'm') value /= KILO;
+             }
+           wrq.u.power.value = (long) value;
+           /* Set some default type if none */
+           if((wrq.u.power.flags & IW_POWER_TYPE) == 0)
+             wrq.u.power.flags |= IW_POWER_PERIOD;
+           ++i;
+           gotone = 1;
+         }
+
+       /* Now, check the mode */
+       if(i < count)
+         {
+           if(!strcasecmp(args[i], "all"))
+             wrq.u.power.flags |= IW_POWER_ALL_R;
+           if(!strncasecmp(args[i], "unicast", 4))
+             wrq.u.power.flags |= IW_POWER_UNICAST_R;
+           if(!strncasecmp(args[i], "multicast", 5))
+             wrq.u.power.flags |= IW_POWER_MULTICAST_R;
+           if(!strncasecmp(args[i], "force", 5))
+             wrq.u.power.flags |= IW_POWER_FORCE_S;
+           if(!strcasecmp(args[i], "repeat"))
+             wrq.u.power.flags |= IW_POWER_REPEATER;
+           if(wrq.u.power.flags & IW_POWER_MODE)
+             {
+               ++i;
+               gotone = 1;
+             }
+         }
+       if(!gotone)
+         {
+           errarg = i;
+           return(IWERR_ARG_TYPE);
+         }
+      }
+
+  if(iw_set_ext(skfd, ifname, SIOCSIWPOWER, &wrq) < 0)
+    return(IWERR_SET_EXT);
+
+  /* Var args */
+  return(i);
+}
 
-         if(ioctl(skfd, SIOCSIWFRAG, &wrq) < 0)
-           {
-             fprintf(stderr, "SIOCSIWFRAG: %s\n", strerror(errno));
-             return(-1);
-           }
-         continue;
-       }
+#ifndef WE_ESSENTIAL
+/*------------------------------------------------------------------*/
+/*
+ * Set Nickname
+ */
+static int
+set_nick_info(int              skfd,
+             char *            ifname,
+             char *            args[],         /* Command line args */
+             int               count)          /* Args count */
+{
+  struct iwreq         wrq;
+  int                  we_kernel_version;
+
+  /* Avoid "Unused parameter" warning */
+  count = count;
+
+  if(strlen(args[0]) > IW_ESSID_MAX_SIZE)
+    {
+      errmax = IW_ESSID_MAX_SIZE;
+      return(IWERR_ARG_SIZE);
+    }
+
+  we_kernel_version = iw_get_kernel_we_version();
+
+  wrq.u.essid.pointer = (caddr_t) args[0];
+  wrq.u.essid.length = strlen(args[0]);
+  if(we_kernel_version < 21)
+    wrq.u.essid.length++;
+
+  if(iw_set_ext(skfd, ifname, SIOCSIWNICKN, &wrq) < 0)
+    return(IWERR_SET_EXT);
+
+  /* 1 args */
+  return(1);
+}
 
-      /* ---------- Set operation mode ---------- */
-      if(!strcmp(args[i], "mode"))
+/*------------------------------------------------------------------*/
+/*
+ * Set commit
+ */
+static int
+set_nwid_info(int              skfd,
+             char *            ifname,
+             char *            args[],         /* Command line args */
+             int               count)          /* Args count */
+{
+  struct iwreq         wrq;
+  unsigned long                temp;
+
+  /* Avoid "Unused parameter" warning */
+  count = count;
+
+  if((!strcasecmp(args[0], "off")) ||
+     (!strcasecmp(args[0], "any")))
+    wrq.u.nwid.disabled = 1;
+  else
+    if(!strcasecmp(args[0], "on"))
+      {
+       /* Get old nwid */
+       if(iw_get_ext(skfd, ifname, SIOCGIWNWID, &wrq) < 0)
+         return(IWERR_GET_EXT);
+       wrq.u.nwid.disabled = 0;
+      }
+    else
+      if(sscanf(args[0], "%lX", &(temp)) != 1)
+       {
+         errarg = 0;
+         return(IWERR_ARG_TYPE);
+       }
+      else
        {
-         int   k;
+         wrq.u.nwid.value = temp;
+         wrq.u.nwid.disabled = 0;
+       }
 
-         i++;
-         if(i >= count)
-           iw_usage();
+  wrq.u.nwid.fixed = 1;
 
-         if(sscanf(args[i], "%d", &k) != 1)
-           {
-             k = 0;
-             while(k < 6 && strncasecmp(args[i], operation_mode[k], 3))
-               k++;
-           }
-         if((k > 5) || (k < 0))
-           iw_usage();
+  /* Set new nwid */
+  if(iw_set_ext(skfd, ifname, SIOCSIWNWID, &wrq) < 0)
+    return(IWERR_SET_EXT);
+
+  /* 1 arg */
+  return(1);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Set AP Address
+ */
+static int
+set_apaddr_info(int            skfd,
+               char *          ifname,
+               char *          args[],         /* Command line args */
+               int             count)          /* Args count */
+{
+  struct iwreq         wrq;
+
+  /* Avoid "Unused parameter" warning */
+  count = count;
 
-         wrq.u.mode = k;
-         if(ioctl(skfd, SIOCSIWMODE, &wrq) < 0)
+  if((!strcasecmp(args[0], "auto")) ||
+     (!strcasecmp(args[0], "any")))
+    {
+      /* Send a broadcast address */
+      iw_broad_ether(&(wrq.u.ap_addr));
+    }
+  else
+    {
+      if(!strcasecmp(args[0], "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[0], &(wrq.u.ap_addr)) < 0)
            {
-             fprintf(stderr, "SIOCSIWMODE: %s\n", strerror(errno));
-             return(-1);
+             errarg = 0;
+             return(IWERR_ARG_TYPE);
            }
-         continue;
        }
+    }
 
-      /* ---------- Set Power Management ---------- */
-      if(!strncmp(args[i], "power", 3))
-       {
-         if(++i >= count)
-           iw_usage();
+  if(iw_set_ext(skfd, ifname, SIOCSIWAP, &wrq) < 0)
+    return(IWERR_SET_EXT);
 
-         if(!strcasecmp(args[i], "off"))
-           wrq.u.power.disabled = 1;   /* i.e. max size */
-         else
-           if(!strcasecmp(args[i], "on"))
+  /* 1 args */
+  return(1);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Set Tx Power
+ */
+static int
+set_txpower_info(int           skfd,
+               char *          ifname,
+               char *          args[],         /* Command line args */
+               int             count)          /* Args count */
+{
+  struct iwreq         wrq;
+  int                  i = 1;
+
+  /* Avoid "Unused parameter" warning */
+  args = args; count = count;
+
+  /* Prepare the request */
+  wrq.u.txpower.value = -1;
+  wrq.u.txpower.fixed = 1;
+  wrq.u.txpower.disabled = 0;
+  wrq.u.txpower.flags = IW_TXPOW_DBM;
+
+  if(!strcasecmp(args[0], "off"))
+    wrq.u.txpower.disabled = 1;        /* i.e. turn radio off */
+  else
+    if(!strcasecmp(args[0], "auto"))
+      wrq.u.txpower.fixed = 0; /* i.e. use power control */
+    else
+      {
+       if(!strcasecmp(args[0], "on"))
+         {
+           /* Get old tx-power */
+           if(iw_get_ext(skfd, ifname, SIOCGIWTXPOW, &wrq) < 0)
+             return(IWERR_GET_EXT);
+           wrq.u.txpower.disabled = 0;
+         }
+       else
+         {
+           if(!strcasecmp(args[0], "fixed"))
              {
-               /* Get old Power info */
-               if(ioctl(skfd, SIOCGIWPOWER, &wrq) < 0)
-                 {
-                   fprintf(stderr, "SIOCGIWPOWER: %s\n", strerror(errno));
-                   return(-1);
-                 }
-               strcpy(wrq.ifr_name, ifname);
-               wrq.u.power.disabled = 0;
+               /* Get old tx-power */
+               if(iw_get_ext(skfd, ifname, SIOCGIWTXPOW, &wrq) < 0)
+                 return(IWERR_GET_EXT);
+               wrq.u.txpower.fixed = 1;
+               wrq.u.txpower.disabled = 0;
              }
-           else
+           else                        /* Should be a numeric value */
              {
-               double          temp;
-               int             gotone = 0;
-               /* Default - nope */
-               wrq.u.power.flags = IW_POWER_ON;
-               wrq.u.power.disabled = 0;
-
-               /* Check value modifier */
-               if(!strcasecmp(args[i], "min"))
+               int             power;
+               int             ismwatt = 0;
+               struct iw_range range;
+
+               /* Extract range info to do proper conversion */
+               if(iw_get_range_info(skfd, ifname, &range) < 0)
+                 memset(&range, 0, sizeof(range));
+
+               /* Get the value */
+               if(sscanf(args[0], "%i", &(power)) != 1)
                  {
-                   wrq.u.power.flags |= IW_POWER_MIN;
-                   if(++i >= count)
-                     iw_usage();
+                   errarg = 0;
+                   return(IWERR_ARG_TYPE);
                  }
-               else
-                 if(!strcasecmp(args[i], "max"))
-                   {
-                     wrq.u.power.flags |= IW_POWER_MAX;
-                     if(++i >= count)
-                       iw_usage();
-                   }
 
-               /* Check value type */
-               if(!strcasecmp(args[i], "period"))
+               /* Check if milliWatt
+                * We authorise a single 'm' as a shorthand for 'mW',
+                * on the other hand a 'd' probably means 'dBm'... */
+               ismwatt = ((strchr(args[0], 'm') != NULL)
+                          && (strchr(args[0], 'd') == NULL));
+
+               /* We could check 'W' alone... Another time... */
+
+               /* Convert */
+               if(range.txpower_capa & IW_TXPOW_RELATIVE)
                  {
-                   wrq.u.power.flags |= IW_POWER_PERIOD;
-                   if(++i >= count)
-                     iw_usage();
+                   /* Can't convert */
+                   if(ismwatt)
+                     {
+                       errarg = 0;
+                       return(IWERR_ARG_TYPE);
+                     }
+                   wrq.u.txpower.flags = IW_TXPOW_RELATIVE;
                  }
                else
-                 if(!strcasecmp(args[i], "timeout"))
+                 if(range.txpower_capa & IW_TXPOW_MWATT)
+                   {
+                     if(!ismwatt)
+                       power = iw_dbm2mwatt(power);
+                     wrq.u.txpower.flags = IW_TXPOW_MWATT;
+                   }
+                 else
                    {
-                     wrq.u.power.flags |= IW_POWER_TIMEOUT;
-                     if(++i >= count)
-                       iw_usage();
+                     if(ismwatt)
+                       power = iw_mwatt2dbm(power);
+                     wrq.u.txpower.flags = IW_TXPOW_DBM;
                    }
+               wrq.u.txpower.value = power;
 
-               /* Is there any value to grab ? */
-               if(sscanf(args[i], "%lg", &(temp)) == 1)
+               /* Check for an additional argument */
+               if((i < count) && (!strcasecmp(args[i], "auto")))
                  {
-                   temp *= MEGA;       /* default = s */
-                   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_TYPE) == 0)
-                     wrq.u.power.flags |= IW_POWER_PERIOD;
+                   wrq.u.txpower.fixed = 0;
                    ++i;
-                   gotone = 1;
                  }
-
-               /* Now, check the mode */
-               if(i < count)
+               if((i < count) && (!strcasecmp(args[i], "fixed")))
                  {
-                   if(!strcasecmp(args[i], "all"))
-                     wrq.u.power.flags |= IW_POWER_ALL_R;
-                   if(!strncasecmp(args[i], "unicast", 4))
-                     wrq.u.power.flags |= IW_POWER_UNICAST_R;
-                   if(!strncasecmp(args[i], "multicast", 5))
-                     wrq.u.power.flags |= IW_POWER_MULTICAST_R;
-                   if(!strncasecmp(args[i], "force", 5))
-                     wrq.u.power.flags |= IW_POWER_FORCE_S;
-                   if(!strcasecmp(args[i], "repeat"))
-                     wrq.u.power.flags |= IW_POWER_REPEATER;
-                   if(wrq.u.power.flags & IW_POWER_MODE)
-                     {
-                       ++i;
-                       gotone = 1;
-                     }
+                   wrq.u.txpower.fixed = 1;
+                   ++i;
                  }
-               if(!gotone)
-                 iw_usage();
-               --i;
              }
+         }
+      }
 
-         if(ioctl(skfd, SIOCSIWPOWER, &wrq) < 0)
-           {
-             fprintf(stderr, "SIOCSIWPOWER(%d): %s\n",
-                     errno, strerror(errno));
-             return(-1);
-           }
-         continue;
-       }
+  if(iw_set_ext(skfd, ifname, SIOCSIWTXPOW, &wrq) < 0)
+    return(IWERR_SET_EXT);
+
+  /* Var args */
+  return(i);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Set Sensitivity
+ */
+static int
+set_sens_info(int              skfd,
+             char *            ifname,
+             char *            args[],         /* Command line args */
+             int               count)          /* Args count */
+{
+  struct iwreq         wrq;
+  int                  temp;
+
+  /* Avoid "Unused parameter" warning */
+  count = count;
+
+  if(sscanf(args[0], "%i", &(temp)) != 1)
+    {
+      errarg = 0;
+      return(IWERR_ARG_TYPE);
+    }
+  wrq.u.sens.value = temp;
+
+  if(iw_set_ext(skfd, ifname, SIOCSIWSENS, &wrq) < 0)
+    return(IWERR_SET_EXT);
+
+  /* 1 arg */
+  return(1);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Set Retry Limit
+ */
+static int
+set_retry_info(int             skfd,
+              char *           ifname,
+              char *           args[],         /* Command line args */
+              int              count)          /* Args count */
+{
+  struct iwreq         wrq;
+  int                  i = 0;
+  double               value;
+  char *               unit;
+
+  /* Parse modifiers */
+  i = parse_modifiers(args, count, &wrq.u.retry.flags,
+                     iwmod_retry, IWMOD_RETRY_NUM);
+  if(i < 0)
+    return(i);
+
+  /* Add default type if none */
+  if((wrq.u.retry.flags & IW_RETRY_TYPE) == 0)
+    wrq.u.retry.flags |= IW_RETRY_LIMIT;
+
+  wrq.u.retry.disabled = 0;
+
+  /* Is there any value to grab ? */
+  value = strtod(args[i], &unit);
+  if(unit == args[i])
+    {
+      errarg = i;
+      return(IWERR_ARG_TYPE);
+    }
 
-#if WIRELESS_EXT > 9
-      /* ---------- Set Transmit-Power ---------- */
-      if(!strncmp(args[i], "txpower", 3))
+  /* Limit is absolute, on the other hand lifetime is seconds */
+  if(wrq.u.retry.flags & IW_RETRY_LIFETIME)
+    {
+      struct iw_range  range;
+      /* Extract range info to handle properly 'relative' */
+      if(iw_get_range_info(skfd, ifname, &range) < 0)
+       memset(&range, 0, sizeof(range));
+
+      if(range.r_time_flags & IW_RETRY_RELATIVE)
        {
-         struct iw_range       range;
-
-         if(++i >= count)
-           iw_usage();
-
-         /* Extract range info */
-         if(get_range_info(skfd, ifname, &range) < 0)
-           memset(&range, 0, sizeof(range));
-
-         /* Prepare the request */
-         strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
-         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 */
+         if(range.we_version_compiled < 21)
+           value *= MEGA;
          else
-           if(!strcasecmp(args[i], "auto"))
-             wrq.u.txpower.fixed = 0;  /* i.e. use power control */
-           else
+           wrq.u.retry.flags |= IW_RETRY_RELATIVE;
+       }
+      else
+       {
+         /* Normalise lifetime */
+         value *= MEGA;        /* default = s */
+         if(unit[0] == 'u') value /= MEGA;
+         if(unit[0] == 'm') value /= KILO;
+       }
+    }
+  wrq.u.retry.value = (long) value;
+  ++i;
+
+  if(iw_set_ext(skfd, ifname, SIOCSIWRETRY, &wrq) < 0)
+    return(IWERR_SET_EXT);
+
+  /* Var args */
+  return(i);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Set RTS Threshold
+ */
+static int
+set_rts_info(int               skfd,
+            char *             ifname,
+            char *             args[],         /* Command line args */
+            int                count)          /* Args count */
+{
+  struct iwreq         wrq;
+
+  /* Avoid "Unused parameter" warning */
+  count = count;
+
+  wrq.u.rts.value = -1;
+  wrq.u.rts.fixed = 1;
+  wrq.u.rts.disabled = 0;
+
+  if(!strcasecmp(args[0], "off"))
+    wrq.u.rts.disabled = 1;    /* i.e. max size */
+  else
+    if(!strcasecmp(args[0], "auto"))
+      wrq.u.rts.fixed = 0;
+    else
+      {
+       if(!strcasecmp(args[0], "fixed"))
+         {
+           /* Get old RTS threshold */
+           if(iw_get_ext(skfd, ifname, SIOCGIWRTS, &wrq) < 0)
+             return(IWERR_GET_EXT);
+           wrq.u.rts.fixed = 1;
+         }
+       else
+         {     /* Should be a numeric value */
+           long        temp;
+           if(sscanf(args[0], "%li", (unsigned long *) &(temp)) != 1)
              {
-               if(!strcasecmp(args[i], "fixed"))
-                 {
-                   /* Get old tx-power */
-                   if(ioctl(skfd, SIOCGIWTXPOW, &wrq) < 0)
-                     {
-                       fprintf(stderr, "SIOCGIWTXPOW: %s\n", strerror(errno));
-                       return(-1);
-                     }
-                   strcpy(wrq.ifr_name, ifname);
-                   wrq.u.txpower.fixed = 1;
-                 }
-               else                    /* Should be a numeric value */
-                 {
-                   int         power;
-                   int         ismwatt = 0;
+               errarg = 0;
+               return(IWERR_ARG_TYPE);
+             }
+           wrq.u.rts.value = temp;
+         }
+      }
 
-                   /* Get the value */
-                   if(sscanf(args[i], "%ld",
-                             (unsigned long *) &(power)) != 1)
-                     iw_usage();
+  if(iw_set_ext(skfd, ifname, SIOCSIWRTS, &wrq) < 0)
+    return(IWERR_SET_EXT);
 
-                   /* Check if milliwatt */
-                   ismwatt = (index(args[i], 'm') != NULL);
+  /* 1 arg */
+  return(1);
+}
 
-                   /* Convert */
-                   if(!ismwatt && (range.txpower_capa & IW_TXPOW_MWATT))
-                     {
-                       power = dbm2mwatt(power);
-                       wrq.u.data.flags = IW_TXPOW_MWATT;
-                     }
-                   if(ismwatt && !(range.txpower_capa & IW_TXPOW_MWATT))
-                     power = mwatt2dbm(power);
-                   wrq.u.bitrate.value = power;
+/*------------------------------------------------------------------*/
+/*
+ * Set Fragmentation Threshold
+ */
+static int
+set_frag_info(int              skfd,
+             char *            ifname,
+             char *            args[],         /* Command line args */
+             int               count)          /* Args count */
+{
+  struct iwreq         wrq;
 
-                   /* 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;
-                     }
-                 }
+  /* Avoid "Unused parameter" warning */
+  count = count;
+
+  wrq.u.frag.value = -1;
+  wrq.u.frag.fixed = 1;
+  wrq.u.frag.disabled = 0;
+
+  if(!strcasecmp(args[0], "off"))
+    wrq.u.frag.disabled = 1;   /* i.e. max size */
+  else
+    if(!strcasecmp(args[0], "auto"))
+      wrq.u.frag.fixed = 0;
+    else
+      {
+       if(!strcasecmp(args[0], "fixed"))
+         {
+           /* Get old fragmentation threshold */
+           if(iw_get_ext(skfd, ifname, SIOCGIWFRAG, &wrq) < 0)
+             return(IWERR_GET_EXT);
+           wrq.u.frag.fixed = 1;
+         }
+       else
+         {     /* Should be a numeric value */
+           long        temp;
+           if(sscanf(args[0], "%li", &(temp))
+              != 1)
+             {
+               errarg = 0;
+               return(IWERR_ARG_TYPE);
              }
+           wrq.u.frag.value = temp;
+         }
+      }
 
-         if(ioctl(skfd, SIOCSIWTXPOW, &wrq) < 0)
-           {
-             fprintf(stderr, "SIOCSIWTXPOW: %s\n", strerror(errno));
-             return(-1);
-           }
-         continue;
-       }
-#endif
+  if(iw_set_ext(skfd, ifname, SIOCSIWFRAG, &wrq) < 0)
+    return(IWERR_SET_EXT);
 
-#if WIRELESS_EXT > 10
-      /* ---------- Set Power Management ---------- */
-      if(!strncmp(args[i], "retry", 3))
-       {
-         double                temp;
-         int           gotone = 0;
+  /* 1 arg */
+  return(1);
+}
 
-         if(++i >= count)
-           iw_usage();
+/*------------------------------------------------------------------*/
+/*
+ * Set Modulation
+ */
+static int
+set_modulation_info(int                skfd,
+                   char *      ifname,
+                   char *      args[],         /* Command line args */
+                   int         count)          /* Args count */
+{
+  struct iwreq         wrq;
+  int                  i = 1;
 
-         /* Default - nope */
-         wrq.u.retry.flags = IW_RETRY_LIMIT;
-         wrq.u.retry.disabled = 0;
+  /* Avoid "Unused parameter" warning */
+  args = args; count = count;
 
-         /* Check value modifier */
-         if(!strcasecmp(args[i], "min"))
+  if(!strcasecmp(args[0], "auto"))
+    wrq.u.param.fixed = 0;     /* i.e. use any modulation */
+  else
+    {
+      if(!strcasecmp(args[0], "fixed"))
+       {
+         /* Get old modulation */
+         if(iw_get_ext(skfd, ifname, SIOCGIWMODUL, &wrq) < 0)
+           return(IWERR_GET_EXT);
+         wrq.u.param.fixed = 1;
+       }
+      else
+       {
+         int           k;
+
+         /* Allow multiple modulations, combine them together */
+         wrq.u.param.value = 0x0;
+         i = 0;
+         do
            {
-             wrq.u.retry.flags |= IW_RETRY_MIN;
-             if(++i >= count)
-               iw_usage();
+             for(k = 0; k < IW_SIZE_MODUL_LIST; k++)
+               {
+                 if(!strcasecmp(args[i], iw_modul_list[k].cmd))
+                   {
+                     wrq.u.param.value |= iw_modul_list[k].mask;
+                     ++i;
+                     break;
+                   }
+               }
            }
-         else
-           if(!strcasecmp(args[i], "max"))
-             {
-               wrq.u.retry.flags |= IW_RETRY_MAX;
-               if(++i >= count)
-                 iw_usage();
-             }
+         /* For as long as current arg matched and not out of args */
+         while((i < count) && (k < IW_SIZE_MODUL_LIST));
 
-         /* Check value type */
-         if(!strcasecmp(args[i], "limit"))
+         /* Check we got something */
+         if(i == 0)
            {
-             wrq.u.retry.flags |= IW_RETRY_LIMIT;
-             if(++i >= count)
-               iw_usage();
+             errarg = 0;
+             return(IWERR_ARG_TYPE);
            }
-         else
-           if(!strncasecmp(args[i], "lifetime", 4))
-             {
-               wrq.u.retry.flags |= IW_RETRY_LIFETIME;
-               if(++i >= count)
-                 iw_usage();
-             }
 
-         /* Is there any value to grab ? */
-         if(sscanf(args[i], "%lg", &(temp)) == 1)
+         /* Check for an additional argument */
+         if((i < count) && (!strcasecmp(args[i], "auto")))
            {
-             /* 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;
+             wrq.u.param.fixed = 0;
              ++i;
-             gotone = 1;
            }
+         if((i < count) && (!strcasecmp(args[i], "fixed")))
+           {
+             wrq.u.param.fixed = 1;
+             ++i;
+           }
+       }
+    }
+
+  if(iw_set_ext(skfd, ifname, SIOCSIWMODUL, &wrq) < 0)
+    return(IWERR_SET_EXT);
+
+  /* Var args */
+  return(i);
+}
+#endif /* WE_ESSENTIAL */
+
+/*------------------------------------------------------------------*/
+/*
+ * Set commit
+ */
+static int
+set_commit_info(int            skfd,
+               char *          ifname,
+               char *          args[],         /* Command line args */
+               int             count)          /* Args count */
+{
+  struct iwreq         wrq;
+
+  /* Avoid "Unused parameter" warning */
+  args = args; count = count;
+
+  if(iw_set_ext(skfd, ifname, SIOCSIWCOMMIT, &wrq) < 0)
+    return(IWERR_SET_EXT);
+
+  /* No args */
+  return(0);
+}
 
-         if(!gotone)
-           iw_usage();
-         --i;
+/************************** SET DISPATCHER **************************/
+/*
+ * This is a modified version of the dispatcher in iwlist.
+ * The main difference is that here we may have multiple commands per
+ * line. Also, most commands here do take arguments, and most often
+ * a variable number of them.
+ * Therefore, the handler *must* return how many args were consumed...
+ *
+ * Note that the use of multiple commands per line is not advised
+ * in scripts, as it makes error management hard. All commands before
+ * the error are executed, but commands after the error are not
+ * processed.
+ * We also try to give as much clue as possible via stderr to the caller
+ * on which command did fail, but if there are two time the same command,
+ * you don't know which one failed...
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Map command line arguments to the proper procedure...
+ */
+typedef struct iwconfig_entry {
+  const char *         cmd;            /* Command line shorthand */
+  iw_enum_handler      fn;             /* Subroutine */
+  int                  min_count;
+  int                  request;        /* WE numerical ID */
+  const char *         name;           /* Human readable string */
+  const char *         argsname;       /* Args as human readable string */
+} iwconfig_cmd;
+
+static const struct iwconfig_entry iwconfig_cmds[] = {
+  { "essid",           set_essid_info,         1,      SIOCSIWESSID,
+       "Set ESSID",                    "{NNN|any|on|off}" },
+  { "mode",            set_mode_info,          1,      SIOCSIWMODE,
+       "Set Mode",                     "{managed|ad-hoc|master|...}" },
+  { "freq",            set_freq_info,          1,      SIOCSIWFREQ,
+       "Set Frequency",                "N.NNN[k|M|G]" },
+  { "channel",         set_freq_info,          1,      SIOCSIWFREQ,
+       "Set Frequency",                "N" },
+  { "bit",             set_bitrate_info,       1,      SIOCSIWRATE,
+       "Set Bit Rate",                 "{N[k|M|G]|auto|fixed}" },
+  { "rate",            set_bitrate_info,       1,      SIOCSIWRATE,
+       "Set Bit Rate",                 "{N[k|M|G]|auto|fixed}" },
+  { "enc",             set_enc_info,           1,      SIOCSIWENCODE,
+       "Set Encode",                   "{NNNN-NNNN|off}" },
+  { "key",             set_enc_info,           1,      SIOCSIWENCODE,
+       "Set Encode",                   "{NNNN-NNNN|off}"  },
+  { "power",           set_power_info,         1,      SIOCSIWPOWER,
+       "Set Power Management",         "{period N|timeout N|saving N|off}" },
+#ifndef WE_ESSENTIAL
+  { "nickname",                set_nick_info,          1,      SIOCSIWNICKN,
+       "Set Nickname",                 "NNN" },
+  { "nwid",            set_nwid_info,          1,      SIOCSIWNWID,
+       "Set NWID",                     "{NN|on|off}" },
+  { "ap",              set_apaddr_info,        1,      SIOCSIWAP,
+       "Set AP Address",               "{N|off|auto}" },
+  { "txpower",         set_txpower_info,       1,      SIOCSIWTXPOW,
+       "Set Tx Power",                 "{NmW|NdBm|off|auto}" },
+  { "sens",            set_sens_info,          1,      SIOCSIWSENS,
+       "Set Sensitivity",              "N" },
+  { "retry",           set_retry_info,         1,      SIOCSIWRETRY,
+       "Set Retry Limit",              "{limit N|lifetime N}" },
+  { "rts",             set_rts_info,           1,      SIOCSIWRTS,
+       "Set RTS Threshold",            "{N|auto|fixed|off}" },
+  { "frag",            set_frag_info,          1,      SIOCSIWFRAG,
+       "Set Fragmentation Threshold",  "{N|auto|fixed|off}" },
+  { "modulation",      set_modulation_info,    1,      SIOCGIWMODUL,
+       "Set Modulation",               "{11g|11a|CCK|OFDMg|...}" },
+#endif /* WE_ESSENTIAL */
+  { "commit",          set_commit_info,        0,      SIOCSIWCOMMIT,
+       "Commit changes",               "" },
+  { NULL, NULL, 0, 0, NULL, NULL },
+};
+
+/*------------------------------------------------------------------*/
+/*
+ * Find the most appropriate command matching the command line
+ */
+static inline const iwconfig_cmd *
+find_command(const char *      cmd)
+{
+  const iwconfig_cmd * found = NULL;
+  int                  ambig = 0;
+  unsigned int         len = strlen(cmd);
+  int                  i;
+
+  /* Go through all commands */
+  for(i = 0; iwconfig_cmds[i].cmd != NULL; ++i)
+    {
+      /* No match -> next one */
+      if(strncasecmp(iwconfig_cmds[i].cmd, cmd, len) != 0)
+       continue;
+
+      /* Exact match -> perfect */
+      if(len == strlen(iwconfig_cmds[i].cmd))
+       return &iwconfig_cmds[i];
+
+      /* Partial match */
+      if(found == NULL)
+       /* First time */
+       found = &iwconfig_cmds[i];
+      else
+       /* Another time */
+       if (iwconfig_cmds[i].fn != found->fn)
+         ambig = 1;
+    }
+
+  if(found == NULL)
+    {
+      fprintf(stderr, "iwconfig: unknown command \"%s\"\n", cmd);
+      return NULL;
+    }
+
+  if(ambig)
+    {
+      fprintf(stderr, "iwconfig: command \"%s\" is ambiguous\n", cmd);
+      return NULL;
+    }
+
+  return found;
+}
 
-         if(ioctl(skfd, SIOCSIWRETRY, &wrq) < 0)
+/*------------------------------------------------------------------*/
+/*
+ * Set the wireless options requested on command line
+ * Find the individual commands and call the appropriate subroutine
+ */
+static int
+set_info(int           skfd,           /* The socket */
+        char *         args[],         /* Command line args */
+        int            count,          /* Args count */
+        char *         ifname)         /* Dev name */
+{
+  const iwconfig_cmd * iwcmd;
+  int                  ret;
+
+  /* Loop until we run out of args... */
+  while(count > 0)
+    {
+      /* find the command matching the keyword */
+      iwcmd = find_command(args[0]);
+      if(iwcmd == NULL)
+       {
+         /* Here we have an unrecognised arg... Error already printed out. */
+         return(-1);
+       }
+
+      /* One arg is consumed (the command name) */
+      args++;
+      count--;
+
+      /* Check arg numbers */
+      if(count < iwcmd->min_count)
+       ret = IWERR_ARG_NUM;
+      else
+       ret = 0;
+
+      /* Call the command */
+      if(!ret)
+       ret = (*iwcmd->fn)(skfd, ifname, args, count);
+
+      /* Deal with various errors */
+      if(ret < 0)
+       {
+         int   request = iwcmd->request;
+         if(ret == IWERR_GET_EXT)
+           request++;  /* Transform the SET into GET */
+
+         fprintf(stderr, "Error for wireless request \"%s\" (%X) :\n",
+                 iwcmd->name, request);
+         switch(ret)
            {
-             fprintf(stderr, "SIOCSIWRETRY(%d): %s\n",
-                     errno, strerror(errno));
-             return(-1);
+           case IWERR_ARG_NUM:
+             fprintf(stderr, "    too few arguments.\n");
+             break;
+           case IWERR_ARG_TYPE:
+             if(errarg < 0)
+               errarg = 0;
+             if(errarg >= count)
+               errarg = count - 1;
+             fprintf(stderr, "    invalid argument \"%s\".\n", args[errarg]);
+             break;
+           case IWERR_ARG_SIZE:
+             fprintf(stderr, "    argument too big (max %d)\n", errmax);
+             break;
+           case IWERR_ARG_CONFLICT:
+             if(errarg < 0)
+               errarg = 0;
+             if(errarg >= count)
+               errarg = count - 1;
+             fprintf(stderr, "    conflicting argument \"%s\".\n", args[errarg]);
+             break;
+           case IWERR_SET_EXT:
+             fprintf(stderr, "    SET failed on device %-1.16s ; %s.\n",
+                     ifname, strerror(errno));
+             break;
+           case IWERR_GET_EXT:
+             fprintf(stderr, "    GET failed on device %-1.16s ; %s.\n",
+                     ifname, strerror(errno));
+             break;
            }
-         continue;
+         /* Stop processing, we don't know if we are in a consistent state
+          * in reading the command line */
+         return(ret);
        }
 
-#endif /* WIRELESS_EXT > 10 */
+      /* Substract consumed args from command line */
+      args += ret;
+      count -= ret;
 
-      /* ---------- Other ---------- */
-      /* Here we have an unrecognised arg... */
-      fprintf(stderr, "Invalid argument : %s\n", args[i]);
-      iw_usage();
-      return(-1);
-    }          /* for(index ... */
+      /* Loop back */
+    }
+
+  /* Done, all done */
   return(0);
 }
 
+/*------------------------------------------------------------------*/
+/*
+ * Display help
+ */
+static inline void
+iw_usage(void)
+{
+  int i;
+
+  fprintf(stderr,   "Usage: iwconfig [interface]\n");
+  for(i = 0; iwconfig_cmds[i].cmd != NULL; ++i)
+    fprintf(stderr, "                interface %s %s\n",
+           iwconfig_cmds[i].cmd, iwconfig_cmds[i].argsname);
+  fprintf(stderr,   "       Check man pages for more details.\n");
+}
+
+
 /******************************* MAIN ********************************/
 
 /*------------------------------------------------------------------*/
@@ -1437,11 +1921,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);
@@ -1449,34 +1933,34 @@ 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((!strcmp(argv[1], "-h")) || (!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);
-    }
+    else
+      /* Special case for version... */
+      if(!strcmp(argv[1], "-v") || !strcmp(argv[1], "--version"))
+       goterr = iw_print_version_info("iwconfig");
+      else
+       {
+         /* '--' escape device name */
+         if((argc > 2) && !strcmp(argv[1], "--"))
+           {
+             argv++;
+             argc--;
+           }
 
-  /* The other args on the line specify options to be set... */
-  goterr = set_info(skfd, argv + 2, argc - 2, argv[1]);
+         /* The device name must be the first argument */
+         if(argc == 2)
+           goterr = 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);
+  iw_sockets_close(skfd);
 
   return(goterr);
 }