Radix cross Linux

The main Radix cross Linux repository contains the build scripts of packages, which have the most complete and common functionality for desktop machines

452 Commits   2 Branches   1 Tag
Index: Makefile
===================================================================
--- Makefile	(nonexistent)
+++ Makefile	(revision 5)
@@ -0,0 +1,56 @@
+
+COMPONENT_TARGETS = $(HARDWARE_NOARCH)
+
+
+include ../../../../build-system/constants.mk
+
+
+url         = $(DOWNLOAD_SERVER)/sources/packages/n/wireless-tools
+
+versions    = 30
+pkgname     = wireless-tools
+suffix      = tar.gz
+
+tarballs    = $(addsuffix .$(suffix), $(addprefix $(pkgname)-, $(versions)))
+sha1s       = $(addsuffix .sha1sum, $(tarballs))
+
+patches     = $(CURDIR)/patches/wireless-tools-30-cross.patch
+
+.NOTPARALLEL: $(patches)
+
+
+BUILD_TARGETS = $(tarballs) $(sha1s) $(patches)
+
+
+include ../../../../build-system/core.mk
+
+
+.PHONY: download_clean
+
+
+$(tarballs):
+	@echo -e "\n======= Downloading source tarballs =======" ; \
+	 for tarball in $(tarballs) ; do \
+	   echo "$(url)/$$tarball" | xargs -n 1 -P 100 wget $(WGET_OPTIONS) - & \
+	 done ; wait
+
+$(sha1s): $(tarballs)
+	@for sha in $@ ; do \
+	   echo -e "\n======= Downloading '$$sha' signature =======\n" ; \
+	   echo "$(url)/$$sha" | xargs -n 1 -P 100 wget $(WGET_OPTIONS) - & wait %1 ; \
+	   touch $$sha ; \
+	   echo -e "\n======= Check the '$$sha' sha1sum =======\n" ; \
+	   sha1sum --check $$sha ; ret="$$?" ; \
+	   if [ "$$ret" == "1" ]; then \
+	     echo -e "\n======= ERROR: Bad '$$sha' sha1sum =======\n" ; \
+	     exit 1 ; \
+	   fi ; \
+	 done
+
+$(patches): $(sha1s)
+	@echo -e "\n======= Create Patches =======\n" ; \
+	 ( cd create-30-cross-patch ; ./create.patch.sh ) ; \
+	 echo -e "\n"
+
+download_clean:
+	@rm -f $(tarballs) $(sha1s) $(patches)
Index: create-30-cross-patch/create.patch.sh
===================================================================
--- create-30-cross-patch/create.patch.sh	(nonexistent)
+++ create-30-cross-patch/create.patch.sh	(revision 5)
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+VERSION=30
+
+tar --files-from=file.list -xzvf ../wireless-tools-$VERSION.tar.gz
+mv wireless-tools-$VERSION wireless-tools-$VERSION-orig
+
+cp -rf ./wireless-tools-$VERSION-new ./wireless-tools-$VERSION
+
+diff --unified -Nr  wireless-tools-$VERSION-orig  wireless-tools-$VERSION > wireless-tools-$VERSION-cross.patch
+
+mv wireless-tools-$VERSION-cross.patch ../patches
+
+rm -rf ./wireless-tools-$VERSION
+rm -rf ./wireless-tools-$VERSION-orig

Property changes on: create-30-cross-patch/create.patch.sh
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: create-30-cross-patch/file.list
===================================================================
--- create-30-cross-patch/file.list	(nonexistent)
+++ create-30-cross-patch/file.list	(revision 5)
@@ -0,0 +1,4 @@
+wireless-tools-30/Makefile
+wireless-tools-30/iwconfig.c
+wireless-tools-30/iwevent.c
+wireless-tools-30/iwlib.c
Index: create-30-cross-patch/wireless-tools-30-new/Makefile
===================================================================
--- create-30-cross-patch/wireless-tools-30-new/Makefile	(nonexistent)
+++ create-30-cross-patch/wireless-tools-30-new/Makefile	(revision 5)
@@ -0,0 +1,235 @@
+##
+## Please check the configurion parameters below
+##
+
+## Installation directory. By default, go in /usr/local.
+## Distributions should probably use /, but they probably know better...
+ifndef PREFIX
+  PREFIX = /usr/local
+endif
+
+## Compiler to use (modify this for cross compile).
+#CC = gcc
+## Other tools you need to modify for cross compile (static lib only).
+#AR = ar
+#RANLIB = ranlib
+
+## Uncomment this to build tools using static version of the library.
+## Mostly useful for embedded platforms without ldd, or to create
+## a local version (non-root).
+## Standard distros should comment that option to save space and to
+## build libiw.so used by third parties...
+BUILD_STATIC = y
+
+## Uncomment this to build without using libm (less efficient).
+## This is mostly useful for embedded platforms without maths.
+# BUILD_NOLIBM = y
+
+## Uncomment this to strip binary from symbols. This reduce binary size.
+## by a few percent but make debug worse...
+# BUILD_STRIPPING = y
+
+## Uncomment this to build with only essential functionality.
+## This leaves out the less used features and cut in half the tools.
+## This is mostly useful for embedded platforms without limited feature needs.
+# BUILD_WE_ESSENTIAL = y
+
+# ***************************************************************************
+# ***** Most users should not need to change anything beyond this point *****
+# ***************************************************************************
+
+# Version of the Wireless Tools
+WT_VERSION := $(shell sed -ne "/WT_VERSION/{s:\([^0-9]*\)::;p;q;}" < iwlib.h )
+
+# Version of Wireless Extensions.
+WE_VERSION := $(shell sed -ne "/WE_VERSION/{s:\([^0-9]*\)::;p;q;}" < iwlib.h )
+
+# Always use local header for wireless extensions
+WEXT_HEADER = wireless.$(WE_VERSION).h
+
+# Targets to build
+STATIC=libiw.a
+DYNAMIC=libiw.so.$(WT_VERSION)
+PROGS= iwconfig iwlist iwpriv iwspy iwgetid iwevent ifrename
+MANPAGES8=iwconfig.8 iwlist.8 iwpriv.8 iwspy.8 iwgetid.8 iwevent.8 ifrename.8
+MANPAGES7=wireless.7
+MANPAGES5=iftab.5
+EXTRAPROGS= macaddr iwmulticall
+
+# Composition of the library :
+OBJS = iwlib.o
+
+# Select which library to build and to link tool with
+ifdef BUILD_STATIC
+  IWLIB=$(STATIC)
+  IWLIB_INSTALL=install-static
+else
+  IWLIB=$(DYNAMIC)
+  IWLIB_INSTALL=install-dynamic
+endif
+
+# Standard name for dynamic library so that the dynamic linker can pick it.
+# We will just create a symbolic link to the real thing.
+DYNAMIC_LINK= libiw.so
+
+# Install directories
+INSTALL_DIR= $(PREFIX)/sbin
+INSTALL_LIB= $(PREFIX)/lib
+INSTALL_INC= $(PREFIX)/include
+INSTALL_MAN= $(PREFIX)/man
+
+# Various commands
+RM = rm -f
+RM_CMD = $(RM) *.BAK *.bak *.d *.o *.so ,* *~ *.a *.orig *.rej *.out
+LDCONFIG = ldconfig
+
+# Do we want to build with or without libm ?
+ifdef BUILD_NOLIBM
+  LIBS=
+  WELIB_FLAG= -DWE_NOLIBM=y
+else
+  LIBS= -lm
+endif
+
+# Stripping or not ?
+ifdef BUILD_STRIPPING
+  STRIPFLAGS= -Wl,-s
+else
+  STRIPFLAGS=
+endif
+
+# Do we want to build with only essential functionality ?
+ifdef BUILD_WE_ESSENTIAL
+  WEDEF_FLAG= -DWE_ESSENTIAL=y
+endif
+
+# Other flags
+CFLAGS=-Os -W -Wall -Wstrict-prototypes -Wmissing-prototypes -Wshadow \
+	-Wpointer-arith -Wcast-qual -Wimplicit-fallthrough=0 -I.
+#CFLAGS=-O2 -W -Wall -Wstrict-prototypes -I.
+DEPFLAGS=-MMD
+XCFLAGS=$(CFLAGS) $(DEPFLAGS) $(WARN) $(HEADERS) $(WELIB_FLAG) $(WEDEF_FLAG)
+PICFLAG=-fPIC
+
+# Standard compilation targets
+all:: $(IWLIB) $(PROGS)
+
+%: %.o
+	$(CC) $(LDFLAGS) $(STRIPFLAGS) $(XCFLAGS) -o $@ $^ $(LIBS)
+%.o: %.c wireless.h
+	$(CC) $(XCFLAGS) -c $<
+%.so: %.c wireless.h
+	$(CC) $(XCFLAGS) $(PICFLAG) -c -o $@ $<
+
+iwconfig: iwconfig.o $(IWLIB)
+
+iwlist: iwlist.o $(IWLIB)
+
+iwpriv: iwpriv.o $(IWLIB)
+
+iwspy: iwspy.o $(IWLIB)
+
+iwgetid: iwgetid.o $(IWLIB)
+
+iwevent: iwevent.o $(IWLIB)
+
+ifrename: ifrename.o $(IWLIB)
+
+macaddr: macaddr.o $(IWLIB)
+
+# Always do symbol stripping here
+iwmulticall: iwmulticall.o
+	$(CC) $(LDFLAGS) -Wl,-s $(XCFLAGS) -o $@ $^ $(LIBS)
+
+# It's a kind of magic...
+wireless.h:
+	cp $(WEXT_HEADER) wireless.h
+
+# Compilation of the dynamic library
+$(DYNAMIC): $(OBJS:.o=.so)
+	$(CC) -shared -o $@ -Wl,-soname,$@ $(STRIPFLAGS) $(LIBS) -lc $^
+
+# Compilation of the static library
+$(STATIC): $(OBJS:.o=.so)
+	$(RM) $@
+	$(AR) cru $@ $^
+	$(RANLIB) $@
+
+# Installation : So crude but so effective ;-)
+# Less crude thanks to many contributions ;-)
+install:: $(IWLIB_INSTALL) install-bin install-hdr install-man
+
+# Install the dynamic library
+install-dynamic:: $(DYNAMIC)
+	install -m 755 -d $(INSTALL_LIB)
+	install -m 755 $(DYNAMIC) $(INSTALL_LIB)
+	ln -sfn $(DYNAMIC) $(INSTALL_LIB)/$(DYNAMIC_LINK)
+	@echo "*** Don't forget to add $(INSTALL_LIB) to /etc/ld.so.conf, and run ldconfig as root. ***"
+#	@$(LDCONFIG) || echo "*** Could not run ldconfig ! ***"
+
+# Install the static library
+install-static:: $(STATIC)
+	install -m 755 -d $(INSTALL_LIB)
+	install -m 644 $(STATIC) $(INSTALL_LIB)
+
+# All the binaries. Careful, no dependancy on install-dynamic
+install-bin:: all
+	install -m 755 -d $(INSTALL_DIR)
+	install -m 755 $(PROGS) $(INSTALL_DIR)
+
+# Headers to go with the wireless lib (dev)
+install-hdr:: wireless.h
+	install -m 755 -d $(INSTALL_INC)
+	install -m 644 iwlib.h $(INSTALL_INC)
+	install -m 644 wireless.h $(INSTALL_INC)
+
+# How could you live without those manapages ?
+install-man::
+	for lang in . cs fr.*; do \
+	    install -m 755 -d $(INSTALL_MAN)/$$lang/man8/; \
+	    install -m 644 $$lang/$(MANPAGES8) $(INSTALL_MAN)/$$lang/man8/; \
+	    install -m 755 -d $(INSTALL_MAN)/$$lang/man7/; \
+	    install -m 644 $$lang/$(MANPAGES7) $(INSTALL_MAN)/$$lang/man7/; \
+	    install -m 755 -d $(INSTALL_MAN)/$$lang/man5/; \
+	    install -m 644 $$lang/$(MANPAGES5) $(INSTALL_MAN)/$$lang/man5/; \
+	done
+
+install-iwmulticall:: iwmulticall
+	install -m 755 -d $(INSTALL_DIR)
+	install -m 755 $< $(INSTALL_DIR)/iwconfig
+	( cd $(INSTALL_DIR) ; \
+	  ln -f -s iwconfig iwlist ; \
+	  ln -f -s iwconfig iwspy ; \
+	  ln -f -s iwconfig iwpriv ; \
+	  ln -f -s iwconfig iwgetid )
+
+clean::
+	$(RM_CMD) 
+
+realclean::
+	$(RM_CMD) 
+	$(RM) $(STATIC) $(DYNAMIC) $(PROGS) $(EXTRAPROGS) libiw* wireless.h
+
+uninstall::
+	for f in $(PROGS); do \
+	  $(RM) $(INSTALL_DIR)/$$f; \
+	done
+	$(RM) $(INSTALL_LIB)/$(STATIC)
+	$(RM) $(INSTALL_LIB)/$(DYNAMIC)
+	$(RM) $(INSTALL_LIB)/$(DYNAMIC_LINK)
+	$(RM) $(INSTALL_INC)/iwlib.h
+	$(RM) $(INSTALL_INC)/wireless.h
+	for lang in . cs fr.*; do \
+	    for f in $(MANPAGES8); do \
+		$(RM) $(INSTALL_MAN)/$$lang/man8/$$f; \
+	    done; \
+	    for f in $(MANPAGES7); do \
+		$(RM) $(INSTALL_MAN)/$$lang/man7/$$f; \
+	    done; \
+	    for f in $(MANPAGES5); do \
+		$(RM) $(INSTALL_MAN)/$$lang/man5/$$f; \
+	    done; \
+	done
+
+# Include dependancies
+-include *.d
Index: create-30-cross-patch/wireless-tools-30-new/iwconfig.c
===================================================================
--- create-30-cross-patch/wireless-tools-30-new/iwconfig.c	(nonexistent)
+++ create-30-cross-patch/wireless-tools-30-new/iwconfig.c	(revision 5)
@@ -0,0 +1,1965 @@
+/*
+ *	Wireless Tools
+ *
+ *		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 "iwlib.c" and "-lm".
+ *
+ * This file is released under the GPL license.
+ *     Copyright (c) 1997-2007 Jean Tourrilhes <jt@hpl.hp.com>
+ */
+
+#include "iwlib-private.h"		/* Private header */
+
+/**************************** CONSTANTS ****************************/
+
+/*
+ * Error codes defined for setting args
+ */
+#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
+
+/**************************** VARIABLES ****************************/
+
+/*
+ * Ugly, but deal with errors in set_info() efficiently...
+ */
+static int	errarg;
+static int	errmax;
+
+/************************* DISPLAY ROUTINES **************************/
+
+/*------------------------------------------------------------------*/
+/*
+ * Get wireless informations & config from the device driver
+ * We will call all the classical wireless ioctl on the driver through
+ * the socket to know what is supported and to get the settings...
+ */
+static int
+get_info(int			skfd,
+	 char *			ifname,
+	 struct wireless_info *	info)
+{
+  struct iwreq		wrq;
+
+  memset((char *) info, 0, sizeof(struct wireless_info));
+
+  /* Get basic information */
+  if(iw_get_basic_config(skfd, ifname, &(info->b)) < 0)
+    {
+      /* If no wireless name : no wireless extensions */
+      /* But let's check if the interface exists at all */
+      struct ifreq ifr;
+
+      strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
+      if(ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0)
+	return(-ENODEV);
+      else
+	return(-ENOTSUP);
+    }
+
+  /* Get ranges */
+  if(iw_get_range_info(skfd, ifname, &(info->range)) >= 0)
+    info->has_range = 1;
+
+  /* Get AP address */
+  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 bit rate */
+  if(iw_get_ext(skfd, ifname, SIOCGIWRATE, &wrq) >= 0)
+    {
+      info->has_bitrate = 1;
+      memcpy(&(info->bitrate), &(wrq.u.bitrate), sizeof(iwparam));
+    }
+
+  /* Get Power Management settings */
+  wrq.u.power.flags = 0;
+  if(iw_get_ext(skfd, ifname, SIOCGIWPOWER, &wrq) >= 0)
+    {
+      info->has_power = 1;
+      memcpy(&(info->power), &(wrq.u.power), sizeof(iwparam));
+    }
+
+  /* Get stats */
+  if(iw_get_stats(skfd, ifname, &(info->stats),
+		  &info->range, info->has_range) >= 0)
+    {
+      info->has_stats = 1;
+    }
+
+#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))
+    {
+      /* 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 sensitivity */
+  if(iw_get_ext(skfd, ifname, SIOCGIWSENS, &wrq) >= 0)
+    {
+      info->has_sens = 1;
+      memcpy(&(info->sens), &(wrq.u.sens), sizeof(iwparam));
+    }
+
+  if((info->has_range) && (info->range.we_version_compiled > 10))
+    {
+      /* Get retry limit/lifetime */
+      if(iw_get_ext(skfd, ifname, SIOCGIWRETRY, &wrq) >= 0)
+	{
+	  info->has_retry = 1;
+	  memcpy(&(info->retry), &(wrq.u.retry), sizeof(iwparam));
+	}
+    }
+
+  /* Get RTS threshold */
+  if(iw_get_ext(skfd, ifname, SIOCGIWRTS, &wrq) >= 0)
+    {
+      info->has_rts = 1;
+      memcpy(&(info->rts), &(wrq.u.rts), sizeof(iwparam));
+    }
+
+  /* Get fragmentation threshold */
+  if(iw_get_ext(skfd, ifname, SIOCGIWFRAG, &wrq) >= 0)
+    {
+      info->has_frag = 1;
+      memcpy(&(info->frag), &(wrq.u.frag), sizeof(iwparam));
+    }
+#endif	/* WE_ESSENTIAL */
+
+  return(0);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Print on the screen in a neat fashion all the info we have collected
+ * on a device.
+ */
+static void
+display_info(struct wireless_info *	info,
+	     char *			ifname)
+{
+  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.16s  %s  ", ifname, info->b.name);
+
+  /* Display ESSID (extended network), if any */
+  if(info->b.has_essid)
+    {
+      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->b.essid_on & IW_ENCODE_INDEX) > 1)
+	    printf("ESSID:\"%s\" [%d]  ", buffer,
+		   (info->b.essid_on & IW_ENCODE_INDEX));
+	  else
+	    printf("ESSID:\"%s\"  ", buffer);
+	}
+      else
+	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->b.has_essid || info->has_nickname)
+    {
+      printf("\n          ");
+      tokens = 0;
+    }
+
+#ifndef WE_ESSENTIAL
+  /* Display Network ID */
+  if(info->b.has_nwid)
+    {
+      /* Note : should display proper number of digits according to info
+       * in range structure */
+      if(info->b.nwid.disabled)
+	printf("NWID:off/any  ");
+      else
+	printf("NWID:%X  ", info->b.nwid.value);
+      tokens +=2;
+    }
+#endif	/* WE_ESSENTIAL */
+
+  /* Display the current mode of operation */
+  if(info->b.has_mode)
+    {
+      printf("Mode:%s  ", iw_operation_mode[info->b.mode]);
+      tokens +=3;
+    }
+
+  /* Display frequency / channel */
+  if(info->b.has_freq)
+    {
+      double		freq = info->b.freq;	/* Frequency/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))
+	(void)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;
+    }
+
+  /* Display the address of the current Access Point */
+  if(info->has_ap_addr)
+    {
+      /* A bit of clever formatting */
+      if(tokens > 8)
+	{
+	  printf("\n          ");
+	  tokens = 0;
+	}
+      tokens +=6;
+
+      /* Oups ! No Access Point in Ad-Hoc mode */
+      if((info->b.has_mode) && (info->b.mode == IW_MODE_ADHOC))
+	printf("Cell:");
+      else
+	printf("Access Point:");
+      printf(" %s   ", iw_sawap_ntop(&info->ap_addr, buffer));
+    }
+
+  /* Display the currently used/set bit-rate */
+  if(info->has_bitrate)
+    {
+      /* A bit of clever formatting */
+      if(tokens > 11)
+	{
+	  printf("\n          ");
+	  tokens = 0;
+	}
+      tokens +=3;
+
+      /* Display it */
+      iw_print_bitrate(buffer, sizeof(buffer), info->bitrate.value);
+      printf("Bit Rate%c%s   ", (info->bitrate.fixed ? '=' : ':'), buffer);
+    }
+
+#ifndef WE_ESSENTIAL
+  /* Display the Transmit Power */
+  if(info->has_txpower)
+    {
+      /* A bit of clever formatting */
+      if(tokens > 11)
+	{
+	  printf("\n          ");
+	  tokens = 0;
+	}
+      tokens +=3;
+
+      /* Display it */
+      iw_print_txpower(buffer, sizeof(buffer), &info->txpower);
+      printf("Tx-Power%c%s   ", (info->txpower.fixed ? '=' : ':'), buffer);
+    }
+
+  /* Display sensitivity */
+  if(info->has_sens)
+    {
+      /* A bit of clever formatting */
+      if(tokens > 10)
+	{
+	  printf("\n          ");
+	  tokens = 0;
+	}
+      tokens +=4;
+
+      /* Fixed ? */
+      printf("Sensitivity%c", info->sens.fixed ? '=' : ':');
+
+      if(info->has_range)
+	/* Display in dBm ? */
+	if(info->sens.value < 0)
+	  printf("%d dBm  ", info->sens.value);
+	else
+	  printf("%d/%d  ", info->sens.value, info->range.sensitivity);
+      else
+	printf("%d  ", info->sens.value);
+    }
+#endif	/* WE_ESSENTIAL */
+
+  printf("\n          ");
+  tokens = 0;
+
+#ifndef WE_ESSENTIAL
+  /* Display retry limit/lifetime information */
+  if(info->has_retry)
+    { 
+      printf("Retry");
+      /* Disabled ? */
+      if(info->retry.disabled)
+	printf(":off");
+      else
+	{
+	  /* Let's check the value and its type */
+	  if(info->retry.flags & IW_RETRY_TYPE)
+	    {
+	      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)
+	    printf(":on");
+ 	}
+      printf("   ");
+      tokens += 5;	/* Between 3 and 5, depend on flags */
+    }
+
+  /* Display the RTS threshold */
+  if(info->has_rts)
+    {
+      /* Disabled ? */
+      if(info->rts.disabled)
+	printf("RTS thr:off   ");
+      else
+	{
+	  /* Fixed ? */
+	  printf("RTS thr%c%d B   ",
+		 info->rts.fixed ? '=' : ':',
+		 info->rts.value);
+	}
+      tokens += 3;
+    }
+
+  /* Display the fragmentation threshold */
+  if(info->has_frag)
+    {
+      /* A bit of clever formatting */
+      if(tokens > 10)
+	{
+	  printf("\n          ");
+	  tokens = 0;
+	}
+      tokens +=4;
+
+      /* Disabled ? */
+      if(info->frag.disabled)
+	printf("Fragment thr:off");
+      else
+	{
+	  /* Fixed ? */
+	  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->b.has_key)
+    {
+      printf("Encryption key:");
+      if((info->b.key_flags & IW_ENCODE_DISABLED) || (info->b.key_size == 0))
+	printf("off");
+      else
+	{
+	  /* Display the key */
+	  iw_print_key(buffer, sizeof(buffer),
+		       info->b.key, info->b.key_size, info->b.key_flags);
+	  printf("%s", buffer);
+
+	  /* Other info... */
+	  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 */
+  /* Note : we display only one parameter, period or timeout. If a device
+   * (such as HiperLan) has both, the user need to use iwlist... */
+  if(info->has_power)	/* I hope the device has power ;-) */
+    { 
+      printf("Power Management");
+      /* Disabled ? */
+      if(info->power.disabled)
+	printf(":off");
+      else
+	{
+	  /* Let's check the value and its type */
+	  if(info->power.flags & IW_POWER_TYPE)
+	    {
+	      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 */
+	  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          ");
+    }
+
+  /* Display statistics */
+  if(info->has_stats)
+    {
+      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");
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Print on the screen in a neat fashion all the info we have collected
+ * on a device.
+ */
+static int
+print_info(int		skfd,
+	   char *	ifname,
+	   char *	args[],
+	   int		count)
+{
+  struct wireless_info	info;
+  int			rc;
+
+  /* Avoid "Unused parameter" warning */
+  args = args; count = count;
+
+  rc = get_info(skfd, ifname, &info);
+  switch(rc)
+    {
+    case 0:	/* Success */
+      /* Display it ! */
+      display_info(&info, ifname);
+      break;
+
+    case -ENOTSUP:
+      fprintf(stderr, "%-8.16s  no wireless extensions.\n\n",
+	      ifname);
+      break;
+
+    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.
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Map command line modifiers to the proper flags...
+ */
+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)
+{
+  int		i = 0;
+  int		k = 0;
+  __u16		result = 0;	/* Default : no flag set */
+
+  /* Get all modifiers and value types on the command line */
+  do
+    {
+      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;
+	    }
+	}
+    }
+  /* For as long as current arg matched and not out of args */
+  while((i < count) && (k < modnum));
+
+  /* Check there remains one arg for value */
+  if(i >= count)
+    return(IWERR_ARG_NUM);
+
+  /* Return result */
+  *pout = result;
+  return(i);
+}
+
+
+/*********************** 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 ESSID
+ */
+static int
+set_essid_info(int		skfd,
+	       char *		ifname,
+	       char *		args[],		/* Command line args */
+	       int		count)		/* Args count */
+{
+  struct iwreq		wrq;
+  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 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 */
+
+  /* Avoid "Unused parameter" warning */
+  count = count;
+
+  /* Check if it is a uint, otherwise get is as a string */
+  if(sscanf(args[0], "%i", &k) != 1)
+    {
+      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);
+    }
+
+  wrq.u.mode = k;
+  if(iw_set_ext(skfd, ifname, SIOCSIWMODE, &wrq) < 0)
+    return(IWERR_SET_EXT);
+
+  /* 1 arg */
+  return(1);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * 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(!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;
+	}
+      else			/* Should be a numeric value */
+	{
+	  double		freq;
+	  char *		unit;
+
+	  freq = strtod(args[0], &unit);
+	  if(unit == args[0])
+	    {
+	      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;
+	    }
+
+	  iw_float2freq(freq, &(wrq.u.freq));
+
+	  wrq.u.freq.flags = IW_FREQ_FIXED;
+
+	  /* Check for an additional argument */
+	  if((i < count) && (!strcasecmp(args[i], "auto")))
+	    {
+	      wrq.u.freq.flags = 0;
+	      ++i;
+	    }
+	  if((i < count) && (!strcasecmp(args[i], "fixed")))
+	    {
+	      wrq.u.freq.flags = IW_FREQ_FIXED;
+	      ++i;
+	    }
+	}
+    }
+
+  if(iw_set_ext(skfd, ifname, SIOCSIWFREQ, &wrq) < 0)
+    return(IWERR_SET_EXT);
+
+  /* Var args */
+  return(i);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * 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;
+
+  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;
+
+	  brate = strtod(args[0], &unit);
+	  if(unit == args[0])
+	    {
+	      errarg = 0;
+	      return(IWERR_ARG_TYPE);
+	    }
+	  if(unit != NULL)
+	    {
+	      if(unit[0] == 'G') brate *= GIGA;
+	      if(unit[0] == 'M') brate *= MEGA;
+	      if(unit[0] == 'k') brate *= KILO;
+	    }
+	  wrq.u.bitrate.value = (long) brate;
+	  wrq.u.bitrate.fixed = 1;
+
+	  /* Check for an additional argument */
+	  if((i < count) && (!strcasecmp(args[i], "auto")))
+	    {
+	      wrq.u.bitrate.fixed = 0;
+	      ++i;
+	    }
+	  if((i < count) && (!strcasecmp(args[i], "fixed")))
+	    {
+	      wrq.u.bitrate.fixed = 1;
+	      ++i;
+	    }
+	  if((i < count) && (!strcasecmp(args[i], "unicast")))
+	    {
+	      wrq.u.bitrate.flags |= IW_BITRATE_UNICAST;
+	      ++i;
+	    }
+	  if((i < count) && (!strcasecmp(args[i], "broadcast")))
+	    {
+	      wrq.u.bitrate.flags |= IW_BITRATE_BROADCAST;
+	      ++i;
+	    }
+	}
+    }
+
+  if(iw_set_ext(skfd, ifname, SIOCSIWRATE, &wrq) < 0)
+    return(IWERR_SET_EXT);
+
+  /* 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
+	{
+	  oldone = gotone;
+
+	  /* -- Check for the key -- */
+	  if(i < count)
+	    {
+	      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++;
+		}
+	    }
+
+	  /* -- Check for token index -- */
+	  if((i < count) &&
+	     (sscanf(args[i], "[%i]", &temp) == 1) &&
+	     (temp > 0) && (temp < IW_ENCODE_INDEX))
+	    {
+	      wrq.u.encoding.flags |= temp;
+	      ++i;
+	      gotone++;
+	    }
+
+	  /* -- Check the various flags -- */
+	  if((i < count) && (!strcasecmp(args[i], "off")))
+	    {
+	      wrq.u.data.flags |= IW_ENCODE_DISABLED;
+	      ++i;
+	      gotone++;
+	    }
+	  if((i < count) && (!strcasecmp(args[i], "open")))
+	    {
+	      wrq.u.data.flags |= IW_ENCODE_OPEN;
+	      ++i;
+	      gotone++;
+	    }
+	  if((i < count) && (!strncasecmp(args[i], "restricted", 5)))
+	    {
+	      wrq.u.data.flags |= IW_ENCODE_RESTRICTED;
+	      ++i;
+	      gotone++;
+	    }
+	  if((i < count) && (!strncasecmp(args[i], "temporary", 4)))
+	    {
+	      wrq.u.data.flags |= IW_ENCODE_TEMP;
+	      ++i;
+	      gotone++;
+	    }
+	}
+      while(gotone != oldone);
+
+      /* 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)
+	{
+	  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
+	      {
+		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);
+}
+
+#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 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
+	{
+	  wrq.u.nwid.value = temp;
+	  wrq.u.nwid.disabled = 0;
+	}
+
+  wrq.u.nwid.fixed = 1;
+
+  /* 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;
+
+  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)
+	    {
+	      errarg = 0;
+	      return(IWERR_ARG_TYPE);
+	    }
+	}
+    }
+
+  if(iw_set_ext(skfd, ifname, SIOCSIWAP, &wrq) < 0)
+    return(IWERR_SET_EXT);
+
+  /* 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 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			/* Should be a numeric value */
+	      {
+		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)
+		  {
+		    errarg = 0;
+		    return(IWERR_ARG_TYPE);
+		  }
+
+		/* 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)
+		  {
+		    /* Can't convert */
+		    if(ismwatt)
+		      {
+			errarg = 0;
+			return(IWERR_ARG_TYPE);
+		      }
+		    wrq.u.txpower.flags = IW_TXPOW_RELATIVE;
+		  }
+		else
+		  if(range.txpower_capa & IW_TXPOW_MWATT)
+		    {
+		      if(!ismwatt)
+			power = iw_dbm2mwatt(power);
+		      wrq.u.txpower.flags = IW_TXPOW_MWATT;
+		    }
+		  else
+		    {
+		      if(ismwatt)
+			power = iw_mwatt2dbm(power);
+		      wrq.u.txpower.flags = IW_TXPOW_DBM;
+		    }
+		wrq.u.txpower.value = power;
+
+		/* Check for an additional argument */
+		if((i < count) && (!strcasecmp(args[i], "auto")))
+		  {
+		    wrq.u.txpower.fixed = 0;
+		    ++i;
+		  }
+		if((i < count) && (!strcasecmp(args[i], "fixed")))
+		  {
+		    wrq.u.txpower.fixed = 1;
+		    ++i;
+		  }
+	      }
+	  }
+      }
+
+  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);
+    }
+
+  /* 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)
+	{
+	  if(range.we_version_compiled < 21)
+	    value *= MEGA;
+	  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)
+	      {
+		errarg = 0;
+		return(IWERR_ARG_TYPE);
+	      }
+	    wrq.u.rts.value = temp;
+	  }
+      }
+
+  if(iw_set_ext(skfd, ifname, SIOCSIWRTS, &wrq) < 0)
+    return(IWERR_SET_EXT);
+
+  /* 1 arg */
+  return(1);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Set Fragmentation Threshold
+ */
+static int
+set_frag_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.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(iw_set_ext(skfd, ifname, SIOCSIWFRAG, &wrq) < 0)
+    return(IWERR_SET_EXT);
+
+  /* 1 arg */
+  return(1);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * 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;
+
+  /* Avoid "Unused parameter" warning */
+  args = args; count = count;
+
+  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
+	    {
+	      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;
+		    }
+		}
+	    }
+	  /* For as long as current arg matched and not out of args */
+	  while((i < count) && (k < IW_SIZE_MODUL_LIST));
+
+	  /* Check we got something */
+	  if(i == 0)
+	    {
+	      errarg = 0;
+	      return(IWERR_ARG_TYPE);
+	    }
+
+	  /* Check for an additional argument */
+	  if((i < count) && (!strcasecmp(args[i], "auto")))
+	    {
+	      wrq.u.param.fixed = 0;
+	      ++i;
+	    }
+	  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);
+}
+
+/************************** 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;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * 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)
+	    {
+	    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;
+	    }
+	  /* Stop processing, we don't know if we are in a consistent state
+	   * in reading the command line */
+	  return(ret);
+	}
+
+      /* Substract consumed args from command line */
+      args += ret;
+      count -= ret;
+
+      /* 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 ********************************/
+
+/*------------------------------------------------------------------*/
+/*
+ * The main !
+ */
+int
+main(int	argc,
+     char **	argv)
+{
+  int skfd;		/* generic raw socket desc.	*/
+  int goterr = 0;
+
+  /* Create a channel to the NET kernel. */
+  if((skfd = iw_sockets_open()) < 0)
+    {
+      perror("socket");
+      exit(-1);
+    }
+
+  /* No argument : show the list of all device + info */
+  if(argc == 1)
+    iw_enum_devices(skfd, &print_info, NULL, 0);
+  else
+    /* Special case for help... */
+    if((!strcmp(argv[1], "-h")) || (!strcmp(argv[1], "--help")))
+      iw_usage();
+    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 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. */
+  iw_sockets_close(skfd);
+
+  return(goterr);
+}
Index: create-30-cross-patch/wireless-tools-30-new/iwevent.c
===================================================================
--- create-30-cross-patch/wireless-tools-30-new/iwevent.c	(nonexistent)
+++ create-30-cross-patch/wireless-tools-30-new/iwevent.c	(revision 5)
@@ -0,0 +1,806 @@
+/*
+ *	Wireless Tools
+ *
+ *		Jean II - HPL 99->04
+ *
+ * Main code for "iwevent". This listent for wireless events on rtnetlink.
+ * You need to link this code against "iwcommon.c" and "-lm".
+ *
+ * Part of this code is from Alexey Kuznetsov, part is from Casey Carter,
+ * I've just put the pieces together...
+ * By the way, if you know a way to remove the root restrictions, tell me
+ * about it...
+ *
+ * This file is released under the GPL license.
+ *     Copyright (c) 1997-2004 Jean Tourrilhes <jt@hpl.hp.com>
+ */
+
+/***************************** INCLUDES *****************************/
+
+#include "iwlib-private.h"		/* Private header */
+
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+#include <getopt.h>
+#include <time.h>
+#include <sys/time.h>
+
+/* Ugly backward compatibility :-( */
+#ifndef IFLA_WIRELESS
+#define IFLA_WIRELESS	(IFLA_MASTER + 1)
+#endif /* IFLA_WIRELESS */
+
+/****************************** TYPES ******************************/
+
+/*
+ * Static information about wireless interface.
+ * We cache this info for performance reason.
+ */
+typedef struct wireless_iface
+{
+  /* Linked list */
+  struct wireless_iface *	next;
+
+  /* Interface identification */
+  int		ifindex;		/* Interface index == black magic */
+
+  /* Interface data */
+  char			ifname[IFNAMSIZ + 1];	/* Interface name */
+  struct iw_range	range;			/* Wireless static data */
+  int			has_range;
+} wireless_iface;
+
+/**************************** VARIABLES ****************************/
+
+/* Cache of wireless interfaces */
+struct wireless_iface *	interface_cache = NULL;
+
+/************************ RTNETLINK HELPERS ************************/
+/*
+ * The following code is extracted from :
+ * ----------------------------------------------
+ * libnetlink.c	RTnetlink service routines.
+ *
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ *
+ * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ * -----------------------------------------------
+ */
+
+struct rtnl_handle
+{
+	int			fd;
+	struct sockaddr_nl	local;
+	struct sockaddr_nl	peer;
+	__u32			seq;
+	__u32			dump;
+};
+
+static inline void rtnl_close(struct rtnl_handle *rth)
+{
+	close(rth->fd);
+}
+
+static inline int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions)
+{
+	int addr_len;
+
+	addr_len = sizeof(rth);
+	memset(rth, 0, addr_len);
+
+	rth->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+	if (rth->fd < 0) {
+		perror("Cannot open netlink socket");
+		return -1;
+	}
+
+	memset(&rth->local, 0, sizeof(rth->local));
+	rth->local.nl_family = AF_NETLINK;
+	rth->local.nl_groups = subscriptions;
+
+	if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) {
+		perror("Cannot bind netlink socket");
+		return -1;
+	}
+	addr_len = sizeof(rth->local);
+	if (getsockname(rth->fd, (struct sockaddr*)&rth->local,
+			(socklen_t *) &addr_len) < 0) {
+		perror("Cannot getsockname");
+		return -1;
+	}
+	if (addr_len != sizeof(rth->local)) {
+		fprintf(stderr, "Wrong address length %d\n", addr_len);
+		return -1;
+	}
+	if (rth->local.nl_family != AF_NETLINK) {
+		fprintf(stderr, "Wrong address family %d\n", rth->local.nl_family);
+		return -1;
+	}
+	rth->seq = time(NULL);
+	return 0;
+}
+
+/******************* WIRELESS INTERFACE DATABASE *******************/
+/*
+ * We keep a few information about each wireless interface on the
+ * system. This avoid to query this info at each event, therefore
+ * reducing overhead.
+ *
+ * Each interface is indexed by the 'ifindex'. As opposed to interface
+ * names, 'ifindex' are never reused (even if you reactivate the same
+ * hardware), so the data we cache will never apply to the wrong
+ * interface.
+ * Because of that, we are pretty lazy when it come to purging the
+ * cache...
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Get name of interface based on interface index...
+ */
+static inline int
+index2name(int		skfd,
+	   int		ifindex,
+	   char *	name)
+{
+  struct ifreq	irq;
+  int		ret = 0;
+
+  memset(name, 0, IFNAMSIZ + 1);
+
+  /* Get interface name */
+  irq.ifr_ifindex = ifindex;
+  if(ioctl(skfd, SIOCGIFNAME, &irq) < 0)
+    ret = -1;
+  else
+    strncpy(name, irq.ifr_name, IFNAMSIZ);
+
+  return(ret);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Get interface data from cache or live interface
+ */
+static struct wireless_iface *
+iw_get_interface_data(int	ifindex)
+{
+  struct wireless_iface *	curr;
+  int				skfd = -1;	/* ioctl socket */
+
+  /* Search for it in the database */
+  curr = interface_cache;
+  while(curr != NULL)
+    {
+      /* Match ? */
+      if(curr->ifindex == ifindex)
+	{
+	  //printf("Cache : found %d-%s\n", curr->ifindex, curr->ifname);
+
+	  /* Return */
+	  return(curr);
+	}
+      /* Next entry */
+      curr = curr->next;
+    }
+
+  /* Create a channel to the NET kernel. Doesn't happen too often, so
+   * socket creation overhead is minimal... */
+  if((skfd = iw_sockets_open()) < 0)
+    {
+      perror("iw_sockets_open");
+      return(NULL);
+    }
+
+  /* Create new entry, zero, init */
+  curr = calloc(1, sizeof(struct wireless_iface));
+  if(!curr)
+    {
+      fprintf(stderr, "Malloc failed\n");
+      return(NULL);
+    }
+  curr->ifindex = ifindex;
+
+  /* Extract static data */
+  if(index2name(skfd, ifindex, curr->ifname) < 0)
+    {
+      perror("index2name");
+      free(curr);
+      return(NULL);
+    }
+  curr->has_range = (iw_get_range_info(skfd, curr->ifname, &curr->range) >= 0);
+  //printf("Cache : create %d-%s\n", curr->ifindex, curr->ifname);
+
+  /* Done */
+  iw_sockets_close(skfd);
+
+  /* Link it */
+  curr->next = interface_cache;
+  interface_cache = curr;
+
+  return(curr);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Remove interface data from cache (if it exist)
+ */
+static void
+iw_del_interface_data(int	ifindex)
+{
+  struct wireless_iface *	curr;
+  struct wireless_iface *	prev = NULL;
+  struct wireless_iface *	next;
+
+  /* Go through the list, find the interface, kills it */
+  curr = interface_cache;
+  while(curr)
+    {
+      next = curr->next;
+
+      /* Got a match ? */
+      if(curr->ifindex == ifindex)
+	{
+	  /* Unlink. Root ? */
+	  if(!prev)
+	    interface_cache = next;
+	  else
+	    prev->next = next;
+	  //printf("Cache : purge %d-%s\n", curr->ifindex, curr->ifname);
+
+	  /* Destroy */
+	  free(curr);
+	}
+      else
+	{
+	  /* Keep as previous */
+	  prev = curr;
+	}
+
+      /* Next entry */
+      curr = next;
+    }
+}
+
+/********************* WIRELESS EVENT DECODING *********************/
+/*
+ * Parse the Wireless Event and print it out
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Dump a buffer as a serie of hex
+ * Maybe should go in iwlib...
+ * Maybe we should have better formatting like iw_print_key...
+ */
+static char *
+iw_hexdump(char *		buf,
+	   size_t		buflen,
+	   const unsigned char *data,
+	   size_t		datalen)
+{
+  size_t	i;
+  char *	pos = buf;
+
+  for(i = 0; i < datalen; i++)
+    pos += snprintf(pos, buf + buflen - pos, "%02X", data[i]);
+  return buf;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Print one element from the scanning results
+ */
+static inline int
+print_event_token(struct iw_event *	event,		/* Extracted token */
+		  struct iw_range *	iw_range,	/* Range info */
+		  int			has_range)
+{
+  char		buffer[128];	/* Temporary buffer */
+  char		buffer2[30];	/* Temporary buffer */
+  char *	prefix = (IW_IS_GET(event->cmd) ? "New" : "Set");
+
+  /* Now, let's decode the event */
+  switch(event->cmd)
+    {
+      /* ----- set events ----- */
+      /* Events that result from a "SET XXX" operation by the user */
+    case SIOCSIWNWID:
+      if(event->u.nwid.disabled)
+	printf("Set NWID:off/any\n");
+      else
+	printf("Set NWID:%X\n", event->u.nwid.value);
+      break;
+    case SIOCSIWFREQ:
+    case SIOCGIWFREQ:
+      {
+	double		freq;			/* Frequency/channel */
+	int		channel = -1;		/* Converted to channel */
+	freq = iw_freq2float(&(event->u.freq));
+	if(has_range)
+	  {
+	    if(freq < KILO)
+	      /* Convert channel to frequency if possible */
+	      channel = iw_channel_to_freq((int) freq, &freq, iw_range);
+	    else
+	      /* Convert frequency to channel if possible */
+	      channel = iw_freq_to_channel(freq, iw_range);
+	  }
+	iw_print_freq(buffer, sizeof(buffer),
+		      freq, channel, event->u.freq.flags);
+	printf("%s %s\n", prefix, buffer);
+      }
+      break;
+    case SIOCSIWMODE:
+      printf("Set Mode:%s\n",
+	     iw_operation_mode[event->u.mode]);
+      break;
+    case SIOCSIWESSID:
+    case SIOCGIWESSID:
+      {
+	char essid[4*IW_ESSID_MAX_SIZE + 1];
+	memset(essid, '\0', sizeof(essid));
+	if((event->u.essid.pointer) && (event->u.essid.length))
+	  iw_essid_escape(essid,
+			  event->u.essid.pointer, event->u.essid.length);
+	if(event->u.essid.flags)
+	  {
+	    /* Does it have an ESSID index ? */
+	    if((event->u.essid.flags & IW_ENCODE_INDEX) > 1)
+	      printf("%s ESSID:\"%s\" [%d]\n", prefix, essid,
+		     (event->u.essid.flags & IW_ENCODE_INDEX));
+	    else
+	      printf("%s ESSID:\"%s\"\n", prefix, essid);
+	  }
+	else
+	  printf("%s ESSID:off/any\n", prefix);
+      }
+      break;
+    case SIOCSIWENCODE:
+      {
+	unsigned char	key[IW_ENCODING_TOKEN_MAX];
+	if(event->u.data.pointer)
+	  memcpy(key, event->u.data.pointer, event->u.data.length);
+	else
+	  event->u.data.flags |= IW_ENCODE_NOKEY;
+	printf("Set Encryption key:{%X}", event->u.data.flags);
+	if(event->u.data.flags & IW_ENCODE_DISABLED)
+	  printf("off\n");
+	else
+	  {
+	    /* Display the key */
+	    iw_print_key(buffer, sizeof(buffer), key, event->u.data.length,
+			 event->u.data.flags);
+	    printf("%s", buffer);
+
+	    /* Other info... */
+	    if((event->u.data.flags & IW_ENCODE_INDEX) > 1)
+	      printf(" [%d]", event->u.data.flags & IW_ENCODE_INDEX);
+	    if(event->u.data.flags & IW_ENCODE_RESTRICTED)
+	      printf("   Security mode:restricted");
+	    if(event->u.data.flags & IW_ENCODE_OPEN)
+	      printf("   Security mode:open");
+	    printf("\n");
+	  }
+      }
+      break;
+      /* ----- driver events ----- */
+      /* Events generated by the driver when something important happens */
+    case SIOCGIWAP:
+      printf("New Access Point/Cell address:%s\n",
+	     iw_sawap_ntop(&event->u.ap_addr, buffer));
+      break;
+    case SIOCGIWSCAN:
+      printf("Scan request completed\n");
+      break;
+    case IWEVTXDROP:
+      printf("Tx packet dropped:%s\n",
+	     iw_saether_ntop(&event->u.addr, buffer));
+      break;
+    case IWEVCUSTOM:
+      {
+	char custom[IW_CUSTOM_MAX+1];
+	memset(custom, '\0', sizeof(custom));
+	if((event->u.data.pointer) && (event->u.data.length))
+	  memcpy(custom, event->u.data.pointer, event->u.data.length);
+	printf("Custom driver event:%s\n", custom);
+      }
+      break;
+    case IWEVREGISTERED:
+      printf("Registered node:%s\n",
+	     iw_saether_ntop(&event->u.addr, buffer));
+      break;
+    case IWEVEXPIRED:
+      printf("Expired node:%s\n",
+	     iw_saether_ntop(&event->u.addr, buffer));
+      break;
+    case SIOCGIWTHRSPY:
+      {
+	struct iw_thrspy	threshold;
+	if((event->u.data.pointer) && (event->u.data.length))
+	  {
+	    memcpy(&threshold, event->u.data.pointer,
+		   sizeof(struct iw_thrspy));
+	    printf("Spy threshold crossed on address:%s\n",
+		   iw_saether_ntop(&threshold.addr, buffer));
+	    iw_print_stats(buffer, sizeof(buffer),
+			   &threshold.qual, iw_range, has_range);
+	    printf("                            Link %s\n", buffer);
+	  }
+	else
+	  printf("Invalid Spy Threshold event\n");
+      }
+      break;
+      /* ----- driver WPA events ----- */
+      /* Events generated by the driver, used for WPA operation */
+    case IWEVMICHAELMICFAILURE:
+      if(event->u.data.length >= sizeof(struct iw_michaelmicfailure))
+	{
+	  struct iw_michaelmicfailure mf;
+	  memcpy(&mf, event->u.data.pointer, sizeof(mf));
+	  printf("Michael MIC failure flags:0x%X src_addr:%s tsc:%s\n",
+		 mf.flags,
+		 iw_saether_ntop(&mf.src_addr, buffer2),
+		 iw_hexdump(buffer, sizeof(buffer),
+			    mf.tsc, IW_ENCODE_SEQ_MAX_SIZE));
+	}
+      break;
+    case IWEVASSOCREQIE:
+      printf("Association Request IEs:%s\n",
+	     iw_hexdump(buffer, sizeof(buffer),
+			event->u.data.pointer, event->u.data.length));
+      break;
+    case IWEVASSOCRESPIE:
+      printf("Association Response IEs:%s\n",
+	     iw_hexdump(buffer, sizeof(buffer),
+			event->u.data.pointer, event->u.data.length));
+      break;
+    case IWEVPMKIDCAND:
+      if(event->u.data.length >= sizeof(struct iw_pmkid_cand))
+	{
+	  struct iw_pmkid_cand cand;
+	  memcpy(&cand, event->u.data.pointer, sizeof(cand));
+	  printf("PMKID candidate flags:0x%X index:%d bssid:%s\n",
+		 cand.flags, cand.index,
+		 iw_saether_ntop(&cand.bssid, buffer));
+	}
+      break;
+      /* ----- junk ----- */
+      /* other junk not currently in use */
+    case SIOCGIWRATE:
+      iw_print_bitrate(buffer, sizeof(buffer), event->u.bitrate.value);
+      printf("New Bit Rate:%s\n", buffer);
+      break;
+    case SIOCGIWNAME:
+      printf("Protocol:%-1.16s\n", event->u.name);
+      break;
+    case IWEVQUAL:
+      {
+	event->u.qual.updated = 0x0;	/* Not that reliable, disable */
+	iw_print_stats(buffer, sizeof(buffer),
+		       &event->u.qual, iw_range, has_range);
+	printf("Link %s\n", buffer);
+	break;
+      }
+    default:
+      printf("(Unknown Wireless event 0x%04X)\n", event->cmd);
+    }	/* switch(event->cmd) */
+
+  return(0);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Print out all Wireless Events part of the RTNetlink message
+ * Most often, there will be only one event per message, but
+ * just make sure we read everything...
+ */
+static inline int
+print_event_stream(int		ifindex,
+		   char *	data,
+		   int		len)
+{
+  struct iw_event	iwe;
+  struct stream_descr	stream;
+  int			i = 0;
+  int			ret;
+  char			buffer[64];
+  struct timeval	recv_time;
+  struct timezone	tz;
+  struct wireless_iface *	wireless_data;
+
+  /* Get data from cache */
+  wireless_data = iw_get_interface_data(ifindex);
+  if(wireless_data == NULL)
+    return(-1);
+
+  /* Print received time in readable form */
+  gettimeofday(&recv_time, &tz);
+  iw_print_timeval(buffer, sizeof(buffer), &recv_time, &tz);
+
+  iw_init_event_stream(&stream, data, len);
+  do
+    {
+      /* Extract an event and print it */
+      ret = iw_extract_event_stream(&stream, &iwe,
+				    wireless_data->range.we_version_compiled);
+      if(ret != 0)
+	{
+	  if(i++ == 0)
+	    printf("%s   %-8.16s ", buffer, wireless_data->ifname);
+	  else
+	    printf("                           ");
+	  if(ret > 0)
+	    print_event_token(&iwe,
+			      &wireless_data->range, wireless_data->has_range);
+	  else
+	    printf("(Invalid event)\n");
+	  /* Push data out *now*, in case we are redirected to a pipe */
+	  fflush(stdout);
+	}
+    }
+  while(ret > 0);
+
+  return(0);
+}
+
+/*********************** RTNETLINK EVENT DUMP***********************/
+/*
+ * Dump the events we receive from rtnetlink
+ * This code is mostly from Casey
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Respond to a single RTM_NEWLINK event from the rtnetlink socket.
+ */
+static int
+LinkCatcher(struct nlmsghdr *nlh)
+{
+  struct ifinfomsg* ifi;
+
+#if 0
+  fprintf(stderr, "nlmsg_type = %d.\n", nlh->nlmsg_type);
+#endif
+
+  ifi = NLMSG_DATA(nlh);
+
+  /* Code is ugly, but sort of works - Jean II */
+
+  /* If interface is getting destoyed */
+  if(nlh->nlmsg_type == RTM_DELLINK)
+    {
+      /* Remove from cache (if in cache) */
+      iw_del_interface_data(ifi->ifi_index);
+      return 0;
+    }
+
+  /* Only keep add/change events */
+  if(nlh->nlmsg_type != RTM_NEWLINK)
+    return 0;
+
+  /* Check for attributes */
+  if (nlh->nlmsg_len > NLMSG_ALIGN(sizeof(struct ifinfomsg)))
+    {
+      int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(sizeof(struct ifinfomsg));
+      struct rtattr *attr = (void *) ((char *) ifi +
+				      NLMSG_ALIGN(sizeof(struct ifinfomsg)));
+
+      while (RTA_OK(attr, attrlen))
+	{
+	  /* Check if the Wireless kind */
+	  if(attr->rta_type == IFLA_WIRELESS)
+	    {
+	      /* Go to display it */
+	      print_event_stream(ifi->ifi_index,
+				 (char *) attr + RTA_ALIGN(sizeof(struct rtattr)),
+				 attr->rta_len - RTA_ALIGN(sizeof(struct rtattr)));
+	    }
+	  attr = RTA_NEXT(attr, attrlen);
+	}
+    }
+
+  return 0;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * We must watch the rtnelink socket for events.
+ * This routine handles those events (i.e., call this when rth.fd
+ * is ready to read).
+ */
+static inline void
+handle_netlink_events(struct rtnl_handle *	rth)
+{
+  while(1)
+    {
+      struct sockaddr_nl sanl;
+      socklen_t sanllen = sizeof(struct sockaddr_nl);
+
+      struct nlmsghdr *h;
+      int amt;
+      char buf[8192];
+
+      amt = recvfrom(rth->fd, buf, sizeof(buf), MSG_DONTWAIT, (struct sockaddr*)&sanl, &sanllen);
+      if(amt < 0)
+	{
+	  if(errno != EINTR && errno != EAGAIN)
+	    {
+	      fprintf(stderr, "%s: error reading netlink: %s.\n",
+		      __PRETTY_FUNCTION__, strerror(errno));
+	    }
+	  return;
+	}
+
+      if(amt == 0)
+	{
+	  fprintf(stderr, "%s: EOF on netlink??\n", __PRETTY_FUNCTION__);
+	  return;
+	}
+
+      h = (struct nlmsghdr*)buf;
+      while(amt >= (int)sizeof(*h))
+	{
+	  int len = h->nlmsg_len;
+	  int l = len - sizeof(*h);
+
+	  if(l < 0 || len > amt)
+	    {
+	      fprintf(stderr, "%s: malformed netlink message: len=%d\n", __PRETTY_FUNCTION__, len);
+	      break;
+	    }
+
+	  switch(h->nlmsg_type)
+	    {
+	    case RTM_NEWLINK:
+	    case RTM_DELLINK:
+	      LinkCatcher(h);
+	      break;
+	    default:
+#if 0
+	      fprintf(stderr, "%s: got nlmsg of type %#x.\n", __PRETTY_FUNCTION__, h->nlmsg_type);
+#endif
+	      break;
+	    }
+
+	  len = NLMSG_ALIGN(len);
+	  amt -= len;
+	  h = (struct nlmsghdr*)((char*)h + len);
+	}
+
+      if(amt > 0)
+	fprintf(stderr, "%s: remnant of size %d on netlink\n", __PRETTY_FUNCTION__, amt);
+    }
+}
+
+/**************************** MAIN LOOP ****************************/
+
+/* ---------------------------------------------------------------- */
+/*
+ * Wait until we get an event
+ */
+static inline int
+wait_for_event(struct rtnl_handle *	rth)
+{
+#if 0
+  struct timeval	tv;	/* Select timeout */
+#endif
+
+  /* Forever */
+  while(1)
+    {
+      fd_set		rfds;		/* File descriptors for select */
+      int		last_fd;	/* Last fd */
+      int		ret;
+
+      /* Guess what ? We must re-generate rfds each time */
+      FD_ZERO(&rfds);
+      FD_SET(rth->fd, &rfds);
+      last_fd = rth->fd;
+
+      /* Wait until something happens */
+      ret = select(last_fd + 1, &rfds, NULL, NULL, NULL);
+
+      /* Check if there was an error */
+      if(ret < 0)
+	{
+	  if(errno == EAGAIN || errno == EINTR)
+	    continue;
+	  fprintf(stderr, "Unhandled signal - exiting...\n");
+	  break;
+	}
+
+      /* Check if there was a timeout */
+      if(ret == 0)
+	{
+	  continue;
+	}
+
+      /* Check for interface discovery events. */
+      if(FD_ISSET(rth->fd, &rfds))
+	handle_netlink_events(rth);
+    }
+
+  return(0);
+}
+
+/******************************* MAIN *******************************/
+
+/* ---------------------------------------------------------------- */
+/*
+ * helper ;-)
+ */
+static void
+iw_usage(int status)
+{
+  fputs("Usage: iwevent [OPTIONS]\n"
+	"   Monitors and displays Wireless Events.\n"
+	"   Options are:\n"
+	"     -h,--help     Print this message.\n"
+	"     -v,--version  Show version of this program.\n",
+	status ? stderr : stdout);
+  exit(status);
+}
+/* Command line options */
+static const struct option long_opts[] = {
+  { "help", no_argument, NULL, 'h' },
+  { "version", no_argument, NULL, 'v' },
+  { NULL, 0, NULL, 0 }
+};
+
+/* ---------------------------------------------------------------- */
+/*
+ * main body of the program
+ */
+int
+main(int	argc,
+     char *	argv[])
+{
+  struct rtnl_handle	rth;
+  int opt;
+
+  /* Check command line options */
+  while((opt = getopt_long(argc, argv, "hv", long_opts, NULL)) > 0)
+    {
+      switch(opt)
+	{
+	case 'h':
+	  iw_usage(0);
+	  break;
+
+	case 'v':
+	  return(iw_print_version_info("iwevent"));
+	  break;
+
+	default:
+	  iw_usage(1);
+	  break;
+	}
+    }
+  if(optind < argc)
+    {
+      fputs("Too many arguments.\n", stderr);
+      iw_usage(1);
+    }
+
+  /* Open netlink channel */
+  if(rtnl_open(&rth, RTMGRP_LINK) < 0)
+    {
+      perror("Can't initialize rtnetlink socket");
+      return(1);
+    }
+
+  fprintf(stderr, "Waiting for Wireless Events from interfaces...\n");
+
+  /* Do what we have to do */
+  wait_for_event(&rth);
+
+  /* Cleanup - only if you are pedantic */
+  rtnl_close(&rth);
+
+  return(0);
+}
Index: create-30-cross-patch/wireless-tools-30-new/iwlib.c
===================================================================
--- create-30-cross-patch/wireless-tools-30-new/iwlib.c	(nonexistent)
+++ create-30-cross-patch/wireless-tools-30-new/iwlib.c	(revision 5)
@@ -0,0 +1,3322 @@
+/*
+ *	Wireless Tools
+ *
+ *		Jean II - HPLB 97->99 - HPL 99->09
+ *
+ * Common subroutines to all the wireless tools...
+ *
+ * This file is released under the GPL license.
+ *     Copyright (c) 1997-2009 Jean Tourrilhes <jt@hpl.hp.com>
+ */
+
+/***************************** INCLUDES *****************************/
+
+#include "iwlib-private.h"		/* Private header */
+
+/************************ CONSTANTS & MACROS ************************/
+
+/*
+ * Constants fof WE-9->15
+ */
+#define IW15_MAX_FREQUENCIES	16
+#define IW15_MAX_BITRATES	8
+#define IW15_MAX_TXPOWER	8
+#define IW15_MAX_ENCODING_SIZES	8
+#define IW15_MAX_SPY		8
+#define IW15_MAX_AP		8
+
+/****************************** TYPES ******************************/
+
+/*
+ *	Struct iw_range up to WE-15
+ */
+struct	iw15_range
+{
+	__u32		throughput;
+	__u32		min_nwid;
+	__u32		max_nwid;
+	__u16		num_channels;
+	__u8		num_frequency;
+	struct iw_freq	freq[IW15_MAX_FREQUENCIES];
+	__s32		sensitivity;
+	struct iw_quality	max_qual;
+	__u8		num_bitrates;
+	__s32		bitrate[IW15_MAX_BITRATES];
+	__s32		min_rts;
+	__s32		max_rts;
+	__s32		min_frag;
+	__s32		max_frag;
+	__s32		min_pmp;
+	__s32		max_pmp;
+	__s32		min_pmt;
+	__s32		max_pmt;
+	__u16		pmp_flags;
+	__u16		pmt_flags;
+	__u16		pm_capa;
+	__u16		encoding_size[IW15_MAX_ENCODING_SIZES];
+	__u8		num_encoding_sizes;
+	__u8		max_encoding_tokens;
+	__u16		txpower_capa;
+	__u8		num_txpower;
+	__s32		txpower[IW15_MAX_TXPOWER];
+	__u8		we_version_compiled;
+	__u8		we_version_source;
+	__u16		retry_capa;
+	__u16		retry_flags;
+	__u16		r_time_flags;
+	__s32		min_retry;
+	__s32		max_retry;
+	__s32		min_r_time;
+	__s32		max_r_time;
+	struct iw_quality	avg_qual;
+};
+
+/*
+ * Union for all the versions of iwrange.
+ * Fortunately, I mostly only add fields at the end, and big-bang
+ * reorganisations are few.
+ */
+union	iw_range_raw
+{
+	struct iw15_range	range15;	/* WE 9->15 */
+	struct iw_range		range;		/* WE 16->current */
+};
+
+/*
+ * Offsets in iw_range struct
+ */
+#define iwr15_off(f)	( ((char *) &(((struct iw15_range *) NULL)->f)) - \
+			  (char *) NULL)
+#define iwr_off(f)	( ((char *) &(((struct iw_range *) NULL)->f)) - \
+			  (char *) NULL)
+
+/*
+ * Union to perform unaligned access when working around alignement issues
+ */
+union	iw_align_u16
+{
+	__u16		value;
+	unsigned char	byte[2];
+};
+
+/**************************** VARIABLES ****************************/
+
+/* Modes as human readable strings */
+const char * const iw_operation_mode[] = { "Auto",
+					"Ad-Hoc",
+					"Managed",
+					"Master",
+					"Repeater",
+					"Secondary",
+					"Monitor",
+					"Unknown/bug" };
+
+/* Modulations as human readable strings */
+const struct iw_modul_descr	iw_modul_list[] = {
+  /* Start with aggregate types, so that they display first */
+  { IW_MODUL_11AG, "11ag",
+    "IEEE 802.11a + 802.11g (2.4 & 5 GHz, up to 54 Mb/s)" },
+  { IW_MODUL_11AB, "11ab",
+    "IEEE 802.11a + 802.11b (2.4 & 5 GHz, up to 54 Mb/s)" },
+  { IW_MODUL_11G, "11g", "IEEE 802.11g (2.4 GHz, up to 54 Mb/s)" },
+  { IW_MODUL_11A, "11a", "IEEE 802.11a (5 GHz, up to 54 Mb/s)" },
+  { IW_MODUL_11B, "11b", "IEEE 802.11b (2.4 GHz, up to 11 Mb/s)" },
+
+  /* Proprietary aggregates */
+  { IW_MODUL_TURBO | IW_MODUL_11A, "turboa",
+    "Atheros turbo mode at 5 GHz (up to 108 Mb/s)" },
+  { IW_MODUL_TURBO | IW_MODUL_11G, "turbog",
+    "Atheros turbo mode at 2.4 GHz (up to 108 Mb/s)" },
+  { IW_MODUL_PBCC | IW_MODUL_11B, "11+",
+    "TI 802.11+ (2.4 GHz, up to 22 Mb/s)" },
+
+  /* Individual modulations */
+  { IW_MODUL_OFDM_G, "OFDMg",
+    "802.11g higher rates, OFDM at 2.4 GHz (up to 54 Mb/s)" },
+  { IW_MODUL_OFDM_A, "OFDMa", "802.11a, OFDM at 5 GHz (up to 54 Mb/s)" },
+  { IW_MODUL_CCK, "CCK", "802.11b higher rates (2.4 GHz, up to 11 Mb/s)" },
+  { IW_MODUL_DS, "DS", "802.11 Direct Sequence (2.4 GHz, up to 2 Mb/s)" },
+  { IW_MODUL_FH, "FH", "802.11 Frequency Hopping (2,4 GHz, up to 2 Mb/s)" },
+
+  /* Proprietary modulations */
+  { IW_MODUL_TURBO, "turbo",
+    "Atheros turbo mode, channel bonding (up to 108 Mb/s)" },
+  { IW_MODUL_PBCC, "PBCC",
+    "TI 802.11+ higher rates (2.4 GHz, up to 22 Mb/s)" },
+  { IW_MODUL_CUSTOM, "custom",
+    "Driver specific modulation (check driver documentation)" },
+};
+
+/* Disable runtime version warning in iw_get_range_info() */
+int	iw_ignore_version = 1;
+
+/************************ SOCKET SUBROUTINES *************************/
+
+/*------------------------------------------------------------------*/
+/*
+ * Open a socket.
+ * Depending on the protocol present, open the right socket. The socket
+ * will allow us to talk to the driver.
+ */
+int
+iw_sockets_open(void)
+{
+  static const int families[] = {
+    AF_INET, AF_IPX, AF_AX25, AF_APPLETALK
+  };
+  unsigned int	i;
+  int		sock;
+
+  /*
+   * Now pick any (exisiting) useful socket family for generic queries
+   * Note : don't open all the socket, only returns when one matches,
+   * all protocols might not be valid.
+   * Workaround by Jim Kaba <jkaba@sarnoff.com>
+   * Note : in 99% of the case, we will just open the inet_sock.
+   * The remaining 1% case are not fully correct...
+   */
+
+  /* Try all families we support */
+  for(i = 0; i < sizeof(families)/sizeof(int); ++i)
+    {
+      /* Try to open the socket, if success returns it */
+      sock = socket(families[i], SOCK_DGRAM, 0);
+      if(sock >= 0)
+	return sock;
+  }
+
+  return -1;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Extract the interface name out of /proc/net/wireless or /proc/net/dev.
+ */
+static inline char *
+iw_get_ifname(char *	name,	/* Where to store the name */
+	      int	nsize,	/* Size of name buffer */
+	      char *	buf)	/* Current position in buffer */
+{
+  char *	end;
+
+  /* Skip leading spaces */
+  while(isspace(*buf))
+    buf++;
+
+#ifndef IW_RESTRIC_ENUM
+  /* Get name up to the last ':'. Aliases may contain ':' in them,
+   * but the last one should be the separator */
+  end = strrchr(buf, ':');
+#else
+  /* Get name up to ": "
+   * Note : we compare to ": " to make sure to process aliased interfaces
+   * properly. Doesn't work on /proc/net/dev, because it doesn't guarantee
+   * a ' ' after the ':'*/
+  end = strstr(buf, ": ");
+#endif
+
+  /* Not found ??? To big ??? */
+  if((end == NULL) || (((end - buf) + 1) > nsize))
+    return(NULL);
+
+  /* Copy */
+  memcpy(name, buf, (end - buf));
+  name[end - buf] = '\0';
+
+  /* Return value currently unused, just make sure it's non-NULL */
+  return(end);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Enumerate devices and call specified routine
+ * The new way just use /proc/net/wireless, so get all wireless interfaces,
+ * whether configured or not. This is the default if available.
+ * The old way use SIOCGIFCONF, so get only configured interfaces (wireless
+ * or not).
+ */
+void
+iw_enum_devices(int		skfd,
+		iw_enum_handler	fn,
+		char *		args[],
+		int		count)
+{
+  char		buff[1024];
+  FILE *	fh;
+  struct ifconf ifc;
+  struct ifreq *ifr;
+  int		i;
+
+#ifndef IW_RESTRIC_ENUM
+  /* Check if /proc/net/dev is available */
+  fh = fopen(PROC_NET_DEV, "r");
+#else
+  /* Check if /proc/net/wireless is available */
+  fh = fopen(PROC_NET_WIRELESS, "r");
+#endif
+
+  if(fh != NULL)
+    {
+      /* Success : use data from /proc/net/wireless */
+
+      /* Eat 2 lines of header */
+      fgets(buff, sizeof(buff), fh);
+      fgets(buff, sizeof(buff), fh);
+
+      /* Read each device line */
+      while(fgets(buff, sizeof(buff), fh))
+	{
+	  char	name[IFNAMSIZ + 1];
+	  char *s;
+
+	  /* Skip empty or almost empty lines. It seems that in some
+	   * cases fgets return a line with only a newline. */
+	  if((buff[0] == '\0') || (buff[1] == '\0'))
+	    continue;
+
+	  /* Extract interface name */
+	  s = iw_get_ifname(name, sizeof(name), buff);
+
+	  if(!s)
+	    {
+	      /* Failed to parse, complain and continue */
+#ifndef IW_RESTRIC_ENUM
+	      fprintf(stderr, "Cannot parse " PROC_NET_DEV "\n");
+#else
+	      fprintf(stderr, "Cannot parse " PROC_NET_WIRELESS "\n");
+#endif
+	    }
+	  else
+	    /* Got it, print info about this interface */
+	    (*fn)(skfd, name, args, count);
+	}
+
+      fclose(fh);
+    }
+  else
+    {
+      /* Get list of configured devices using "traditional" way */
+      ifc.ifc_len = sizeof(buff);
+      ifc.ifc_buf = buff;
+      if(ioctl(skfd, SIOCGIFCONF, &ifc) < 0)
+	{
+	  fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno));
+	  return;
+	}
+      ifr = ifc.ifc_req;
+
+      /* Print them */
+      for(i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++)
+	(*fn)(skfd, ifr->ifr_name, args, count);
+    }
+}
+
+/*********************** WIRELESS SUBROUTINES ************************/
+
+/*------------------------------------------------------------------*/
+/*
+ * Extract WE version number from /proc/net/wireless
+ * In most cases, you really want to get version information from
+ * the range info (range->we_version_compiled), see below...
+ *
+ * If we have WE-16 and later, the WE version is available at the
+ * end of the header line of the file.
+ * For version prior to that, we can only detect the change from
+ * v11 to v12, so we do an approximate job. Fortunately, v12 to v15
+ * are highly binary compatible (on the struct level).
+ */
+int
+iw_get_kernel_we_version(void)
+{
+  char		buff[1024];
+  FILE *	fh;
+  char *	p;
+  int		v;
+
+  /* Check if /proc/net/wireless is available */
+  fh = fopen(PROC_NET_WIRELESS, "r");
+
+  if(fh == NULL)
+    {
+      fprintf(stderr, "Cannot read " PROC_NET_WIRELESS "\n");
+      return(-1);
+    }
+
+  /* Read the first line of buffer */
+  fgets(buff, sizeof(buff), fh);
+
+  if(strstr(buff, "| WE") == NULL)
+    {
+      /* Prior to WE16, so explicit version not present */
+
+      /* Black magic */
+      if(strstr(buff, "| Missed") == NULL)
+	v = 11;
+      else
+	v = 15;
+      fclose(fh);
+      return(v);
+    }
+
+  /* Read the second line of buffer */
+  fgets(buff, sizeof(buff), fh);
+
+  /* Get to the last separator, to get the version */
+  p = strrchr(buff, '|');
+  if((p == NULL) || (sscanf(p + 1, "%d", &v) != 1))
+    {
+      fprintf(stderr, "Cannot parse " PROC_NET_WIRELESS "\n");
+      fclose(fh);
+      return(-1);
+    }
+
+  fclose(fh);
+  return(v);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Print the WE versions of the interface.
+ */
+static int
+print_iface_version_info(int	skfd,
+			 char *	ifname,
+			 char *	args[],		/* Command line args */
+			 int	count)		/* Args count */
+{
+  struct iwreq		wrq;
+  char			buffer[sizeof(iwrange) * 2];	/* Large enough */
+  struct iw_range *	range;
+
+  /* Avoid "Unused parameter" warning */
+  args = args; count = count;
+
+  /* If no wireless name : no wireless extensions.
+   * This enable us to treat the SIOCGIWRANGE failure below properly. */
+  if(iw_get_ext(skfd, ifname, SIOCGIWNAME, &wrq) < 0)
+    return(-1);
+
+  /* Cleanup */
+  memset(buffer, 0, sizeof(buffer));
+
+  wrq.u.data.pointer = (caddr_t) buffer;
+  wrq.u.data.length = sizeof(buffer);
+  wrq.u.data.flags = 0;
+  if(iw_get_ext(skfd, ifname, SIOCGIWRANGE, &wrq) < 0)
+    {
+      /* Interface support WE (see above), but not IWRANGE */
+      fprintf(stderr, "%-8.16s  Driver has no Wireless Extension version information.\n\n", ifname);
+      return(0);
+    }
+
+  /* Copy stuff at the right place, ignore extra */
+  range = (struct iw_range *) buffer;
+
+  /* For new versions, we can check the version directly, for old versions
+   * we use magic. 300 bytes is a also magic number, don't touch... */
+  if(wrq.u.data.length >= 300)
+    {
+      /* Version is always at the same offset, so it's ok */
+      printf("%-8.16s  Recommend Wireless Extension v%d or later,\n",
+	     ifname, range->we_version_source);
+      printf("          Currently compiled with Wireless Extension v%d.\n\n",
+	     range->we_version_compiled);
+    }
+  else
+    {
+      fprintf(stderr, "%-8.16s  Wireless Extension version too old.\n\n",
+		      ifname);
+    }
+
+
+  return(0);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Print the WE versions of the tools.
+ */
+int
+iw_print_version_info(const char *	toolname)
+{
+  int		skfd;			/* generic raw socket desc.	*/
+  int		we_kernel_version;
+
+  /* Create a channel to the NET kernel. */
+  if((skfd = iw_sockets_open()) < 0)
+    {
+      perror("socket");
+      return -1;
+    }
+
+  /* Information about the tools themselves */
+  if(toolname != NULL)
+    printf("%-8.16s  Wireless-Tools version %d\n", toolname, WT_VERSION);
+  printf("          Compatible with Wireless Extension v11 to v%d.\n\n",
+	 WE_MAX_VERSION);
+
+  /* Get version from kernel */
+  we_kernel_version = iw_get_kernel_we_version();
+  /* Only version >= 16 can be verified, other are guessed */
+  if(we_kernel_version > 15)
+    printf("Kernel    Currently compiled with Wireless Extension v%d.\n\n",
+	   we_kernel_version);
+
+  /* Version for each device */
+  iw_enum_devices(skfd, &print_iface_version_info, NULL, 0);
+
+  iw_sockets_close(skfd);
+
+  return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Get the range information out of the driver
+ */
+int
+iw_get_range_info(int		skfd,
+		  const char *	ifname,
+		  iwrange *	range)
+{
+  struct iwreq		wrq;
+  char			buffer[sizeof(iwrange) * 2];	/* Large enough */
+  union iw_range_raw *	range_raw;
+
+  /* Cleanup */
+  bzero(buffer, sizeof(buffer));
+
+  wrq.u.data.pointer = (caddr_t) buffer;
+  wrq.u.data.length = sizeof(buffer);
+  wrq.u.data.flags = 0;
+  if(iw_get_ext(skfd, ifname, SIOCGIWRANGE, &wrq) < 0)
+    return(-1);
+
+  /* Point to the buffer */
+  range_raw = (union iw_range_raw *) buffer;
+
+  /* For new versions, we can check the version directly, for old versions
+   * we use magic. 300 bytes is a also magic number, don't touch... */
+  if(wrq.u.data.length < 300)
+    {
+      /* That's v10 or earlier. Ouch ! Let's make a guess...*/
+      range_raw->range.we_version_compiled = 9;
+    }
+
+  /* Check how it needs to be processed */
+  if(range_raw->range.we_version_compiled > 15)
+    {
+      /* This is our native format, that's easy... */
+      /* Copy stuff at the right place, ignore extra */
+      memcpy((char *) range, buffer, sizeof(iwrange));
+    }
+  else
+    {
+      /* Zero unknown fields */
+      bzero((char *) range, sizeof(struct iw_range));
+
+      /* Initial part unmoved */
+      memcpy((char *) range,
+	     buffer,
+	     iwr15_off(num_channels));
+      /* Frequencies pushed futher down towards the end */
+      memcpy((char *) range + iwr_off(num_channels),
+	     buffer + iwr15_off(num_channels),
+	     iwr15_off(sensitivity) - iwr15_off(num_channels));
+      /* This one moved up */
+      memcpy((char *) range + iwr_off(sensitivity),
+	     buffer + iwr15_off(sensitivity),
+	     iwr15_off(num_bitrates) - iwr15_off(sensitivity));
+      /* This one goes after avg_qual */
+      memcpy((char *) range + iwr_off(num_bitrates),
+	     buffer + iwr15_off(num_bitrates),
+	     iwr15_off(min_rts) - iwr15_off(num_bitrates));
+      /* Number of bitrates has changed, put it after */
+      memcpy((char *) range + iwr_off(min_rts),
+	     buffer + iwr15_off(min_rts),
+	     iwr15_off(txpower_capa) - iwr15_off(min_rts));
+      /* Added encoding_login_index, put it after */
+      memcpy((char *) range + iwr_off(txpower_capa),
+	     buffer + iwr15_off(txpower_capa),
+	     iwr15_off(txpower) - iwr15_off(txpower_capa));
+      /* Hum... That's an unexpected glitch. Bummer. */
+      memcpy((char *) range + iwr_off(txpower),
+	     buffer + iwr15_off(txpower),
+	     iwr15_off(avg_qual) - iwr15_off(txpower));
+      /* Avg qual moved up next to max_qual */
+      memcpy((char *) range + iwr_off(avg_qual),
+	     buffer + iwr15_off(avg_qual),
+	     sizeof(struct iw_quality));
+    }
+
+  /* We are now checking much less than we used to do, because we can
+   * accomodate more WE version. But, there are still cases where things
+   * will break... */
+  if(!iw_ignore_version)
+    {
+      /* We don't like very old version (unfortunately kernel 2.2.X) */
+      if(range->we_version_compiled <= 10)
+	{
+	  fprintf(stderr, "Warning: Driver for device %s has been compiled with an ancient version\n", ifname);
+	  fprintf(stderr, "of Wireless Extension, while this program support version 11 and later.\n");
+	  fprintf(stderr, "Some things may be broken...\n\n");
+	}
+
+      /* We don't like future versions of WE, because we can't cope with
+       * the unknown */
+      if(range->we_version_compiled > WE_MAX_VERSION)
+	{
+	  fprintf(stderr, "Warning: Driver for device %s has been compiled with version %d\n", ifname, range->we_version_compiled);
+	  fprintf(stderr, "of Wireless Extension, while this program supports up to version %d.\n", WE_MAX_VERSION);
+	  fprintf(stderr, "Some things may be broken...\n\n");
+	}
+
+      /* Driver version verification */
+      if((range->we_version_compiled > 10) &&
+	 (range->we_version_compiled < range->we_version_source))
+	{
+	  fprintf(stderr, "Warning: Driver for device %s recommend version %d of Wireless Extension,\n", ifname, range->we_version_source);
+	  fprintf(stderr, "but has been compiled with version %d, therefore some driver features\n", range->we_version_compiled);
+	  fprintf(stderr, "may not be available...\n\n");
+	}
+      /* Note : we are only trying to catch compile difference, not source.
+       * If the driver source has not been updated to the latest, it doesn't
+       * matter because the new fields are set to zero */
+    }
+
+  /* Don't complain twice.
+   * In theory, the test apply to each individual driver, but usually
+   * all drivers are compiled from the same kernel. */
+  iw_ignore_version = 1;
+
+  return(0);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Get information about what private ioctls are supported by the driver
+ *
+ * Note : there is one danger using this function. If it return 0, you
+ * still need to free() the buffer. Beware.
+ */
+int
+iw_get_priv_info(int		skfd,
+		 const char *	ifname,
+		 iwprivargs **	ppriv)
+{
+  struct iwreq		wrq;
+  iwprivargs *		priv = NULL;	/* Not allocated yet */
+  int			maxpriv = 16;	/* Minimum for compatibility WE<13 */
+  iwprivargs *		newpriv;
+
+  /* Some driver may return a very large number of ioctls. Some
+   * others a very small number. We now use a dynamic allocation
+   * of the array to satisfy everybody. Of course, as we don't know
+   * in advance the size of the array, we try various increasing
+   * sizes. Jean II */
+  do
+    {
+      /* (Re)allocate the buffer */
+      newpriv = realloc(priv, maxpriv * sizeof(priv[0]));
+      if(newpriv == NULL)
+	{
+	  fprintf(stderr, "%s: Allocation failed\n", __FUNCTION__);
+	  break;
+	}
+      priv = newpriv;
+
+      /* Ask the driver if it's large enough */
+      wrq.u.data.pointer = (caddr_t) priv;
+      wrq.u.data.length = maxpriv;
+      wrq.u.data.flags = 0;
+      if(iw_get_ext(skfd, ifname, SIOCGIWPRIV, &wrq) >= 0)
+	{
+	  /* Success. Pass the buffer by pointer */
+	  *ppriv = priv;
+	  /* Return the number of ioctls */
+	  return(wrq.u.data.length);
+	}
+
+      /* Only E2BIG means the buffer was too small, abort on other errors */
+      if(errno != E2BIG)
+	{
+	  /* Most likely "not supported". Don't barf. */
+	  break;
+	}
+
+      /* Failed. We probably need a bigger buffer. Check if the kernel
+       * gave us any hints. */
+      if(wrq.u.data.length > maxpriv)
+	maxpriv = wrq.u.data.length;
+      else
+	maxpriv *= 2;
+    }
+  while(maxpriv < 1000);
+
+  /* Cleanup */
+  if(priv)
+    free(priv);
+  *ppriv = NULL;
+
+  return(-1);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Get essential wireless config from the device driver
+ * We will call all the classical wireless ioctl on the driver through
+ * the socket to know what is supported and to get the settings...
+ * Note : compare to the version in iwconfig, we extract only
+ * what's *really* needed to configure a device...
+ */
+int
+iw_get_basic_config(int			skfd,
+		    const char *	ifname,
+		    wireless_config *	info)
+{
+  struct iwreq		wrq;
+
+  memset((char *) info, 0, sizeof(struct wireless_config));
+
+  /* Get wireless name */
+  if(iw_get_ext(skfd, ifname, SIOCGIWNAME, &wrq) < 0)
+    /* If no wireless name : no wireless extensions */
+    return(-1);
+  else
+    {
+      strncpy(info->name, wrq.u.name, IFNAMSIZ);
+      info->name[IFNAMSIZ] = '\0';
+    }
+
+  /* Get network ID */
+  if(iw_get_ext(skfd, ifname, SIOCGIWNWID, &wrq) >= 0)
+    {
+      info->has_nwid = 1;
+      memcpy(&(info->nwid), &(wrq.u.nwid), sizeof(iwparam));
+    }
+
+  /* Get frequency / channel */
+  if(iw_get_ext(skfd, ifname, SIOCGIWFREQ, &wrq) >= 0)
+    {
+      info->has_freq = 1;
+      info->freq = iw_freq2float(&(wrq.u.freq));
+      info->freq_flags = wrq.u.freq.flags;
+    }
+
+  /* Get encryption information */
+  wrq.u.data.pointer = (caddr_t) info->key;
+  wrq.u.data.length = IW_ENCODING_TOKEN_MAX;
+  wrq.u.data.flags = 0;
+  if(iw_get_ext(skfd, ifname, SIOCGIWENCODE, &wrq) >= 0)
+    {
+      info->has_key = 1;
+      info->key_size = wrq.u.data.length;
+      info->key_flags = wrq.u.data.flags;
+    }
+
+  /* Get ESSID */
+  wrq.u.essid.pointer = (caddr_t) info->essid;
+  wrq.u.essid.length = IW_ESSID_MAX_SIZE + 2;
+  wrq.u.essid.flags = 0;
+  if(iw_get_ext(skfd, ifname, SIOCGIWESSID, &wrq) >= 0)
+    {
+      info->has_essid = 1;
+      info->essid_on = wrq.u.data.flags;
+      info->essid_len = wrq.u.essid.length;
+    }
+
+  /* Get operation mode */
+  if(iw_get_ext(skfd, ifname, SIOCGIWMODE, &wrq) >= 0)
+    {
+      info->has_mode = 1;
+      /* Note : event->u.mode is unsigned, no need to check <= 0 */
+      if(wrq.u.mode < IW_NUM_OPER_MODE)
+	info->mode = wrq.u.mode;
+      else
+	info->mode = IW_NUM_OPER_MODE;	/* Unknown/bug */
+    }
+
+  return(0);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Set essential wireless config in the device driver
+ * We will call all the classical wireless ioctl on the driver through
+ * the socket to know what is supported and to set the settings...
+ * We support only the restricted set as above...
+ */
+int
+iw_set_basic_config(int			skfd,
+		    const char *	ifname,
+		    wireless_config *	info)
+{
+  struct iwreq		wrq;
+  int			ret = 0;
+
+  /* Get wireless name (check if interface is valid) */
+  if(iw_get_ext(skfd, ifname, SIOCGIWNAME, &wrq) < 0)
+    /* If no wireless name : no wireless extensions */
+    return(-2);
+
+  /* Set the current mode of operation
+   * Mode need to be first : some settings apply only in a specific mode
+   * (such as frequency).
+   */
+  if(info->has_mode)
+    {
+      strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
+      wrq.u.mode = info->mode;
+
+      if(iw_get_ext(skfd, ifname, SIOCSIWMODE, &wrq) < 0)
+	{
+	  fprintf(stderr, "SIOCSIWMODE: %s\n", strerror(errno));
+	  ret = -1;
+	}
+    }
+
+  /* Set frequency / channel */
+  if(info->has_freq)
+    {
+      iw_float2freq(info->freq, &(wrq.u.freq));
+
+      if(iw_set_ext(skfd, ifname, SIOCSIWFREQ, &wrq) < 0)
+	{
+	  fprintf(stderr, "SIOCSIWFREQ: %s\n", strerror(errno));
+	  ret = -1;
+	}
+    }
+
+  /* Set encryption information */
+  if(info->has_key)
+    {
+      int		flags = info->key_flags;
+
+      /* Check if there is a key index */
+      if((flags & IW_ENCODE_INDEX) > 0)
+	{
+	  /* Set the index */
+	  wrq.u.data.pointer = (caddr_t) NULL;
+	  wrq.u.data.flags = (flags & (IW_ENCODE_INDEX)) | IW_ENCODE_NOKEY;
+	  wrq.u.data.length = 0;
+
+	  if(iw_set_ext(skfd, ifname, SIOCSIWENCODE, &wrq) < 0)
+	    {
+	      fprintf(stderr, "SIOCSIWENCODE(%d): %s\n",
+		      errno, strerror(errno));
+	      ret = -1;
+	    }
+	}
+
+      /* Mask out index to minimise probability of reject when setting key */
+      flags = flags & (~IW_ENCODE_INDEX);
+
+      /* Set the key itself (set current key in this case) */
+      wrq.u.data.pointer = (caddr_t) info->key;
+      wrq.u.data.length = info->key_size;
+      wrq.u.data.flags = flags;
+
+      /* Compatibility with WE<13 */
+      if(flags & IW_ENCODE_NOKEY)
+	wrq.u.data.pointer = NULL;
+
+      if(iw_set_ext(skfd, ifname, SIOCSIWENCODE, &wrq) < 0)
+	{
+	  fprintf(stderr, "SIOCSIWENCODE(%d): %s\n",
+		  errno, strerror(errno));
+	  ret = -1;
+	}
+    }
+
+  /* Set Network ID, if available (this is for non-802.11 cards) */
+  if(info->has_nwid)
+    {
+      memcpy(&(wrq.u.nwid), &(info->nwid), sizeof(iwparam));
+      wrq.u.nwid.fixed = 1;	/* Hum... When in Rome... */
+
+      if(iw_set_ext(skfd, ifname, SIOCSIWNWID, &wrq) < 0)
+	{
+	  fprintf(stderr, "SIOCSIWNWID: %s\n", strerror(errno));
+	  ret = -1;
+	}
+    }
+
+  /* Set ESSID (extended network), if available.
+   * ESSID need to be last : most device re-perform the scanning/discovery
+   * when this is set, and things like encryption keys are better be
+   * defined if we want to discover the right set of APs/nodes.
+   */
+  if(info->has_essid)
+    {
+      int		we_kernel_version;
+      we_kernel_version = iw_get_kernel_we_version();
+
+      wrq.u.essid.pointer = (caddr_t) info->essid;
+      wrq.u.essid.length = strlen(info->essid);
+      wrq.u.data.flags = info->essid_on;
+      if(we_kernel_version < 21)
+	wrq.u.essid.length++;
+
+      if(iw_set_ext(skfd, ifname, SIOCSIWESSID, &wrq) < 0)
+	{
+	  fprintf(stderr, "SIOCSIWESSID: %s\n", strerror(errno));
+	  ret = -1;
+	}
+    }
+
+  return(ret);
+}
+
+/*********************** PROTOCOL SUBROUTINES ***********************/
+/*
+ * Fun stuff with protocol identifiers (SIOCGIWNAME).
+ * We assume that drivers are returning sensible values in there,
+ * which is not always the case :-(
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Compare protocol identifiers.
+ * We don't want to know if the two protocols are the exactly same,
+ * but if they interoperate at some level, and also if they accept the
+ * same type of config (ESSID vs NWID, freq...).
+ * This is supposed to work around the alphabet soup.
+ * Return 1 if protocols are compatible, 0 otherwise
+ */
+int
+iw_protocol_compare(const char *	protocol1,
+		    const char *	protocol2)
+{
+  const char *	dot11 = "IEEE 802.11";
+  const char *	dot11_ds = "Dbg";
+  const char *	dot11_5g = "a";
+
+  /* If the strings are the same -> easy */
+  if(!strncmp(protocol1, protocol2, IFNAMSIZ))
+    return(1);
+
+  /* Are we dealing with one of the 802.11 variant ? */
+  if( (!strncmp(protocol1, dot11, strlen(dot11))) &&
+      (!strncmp(protocol2, dot11, strlen(dot11))) )
+    {
+      const char *	sub1 = protocol1 + strlen(dot11);
+      const char *	sub2 = protocol2 + strlen(dot11);
+      unsigned int	i;
+      int		isds1 = 0;
+      int		isds2 = 0;
+      int		is5g1 = 0;
+      int		is5g2 = 0;
+
+      /* Check if we find the magic letters telling it's DS compatible */
+      for(i = 0; i < strlen(dot11_ds); i++)
+	{
+	  if(strchr(sub1, dot11_ds[i]) != NULL)
+	    isds1 = 1;
+	  if(strchr(sub2, dot11_ds[i]) != NULL)
+	    isds2 = 1;
+	}
+      if(isds1 && isds2)
+	return(1);
+
+      /* Check if we find the magic letters telling it's 5GHz compatible */
+      for(i = 0; i < strlen(dot11_5g); i++)
+	{
+	  if(strchr(sub1, dot11_5g[i]) != NULL)
+	    is5g1 = 1;
+	  if(strchr(sub2, dot11_5g[i]) != NULL)
+	    is5g2 = 1;
+	}
+      if(is5g1 && is5g2)
+	return(1);
+    }
+  /* Not compatible */
+  return(0);
+}
+
+/************************ ESSID SUBROUTINES ************************/
+/*
+ * The ESSID identify 802.11 networks, and is an array if 32 bytes.
+ * Most people use it as an ASCII string, and are happy with it.
+ * However, any byte is valid, including the NUL character. Characters
+ * beyond the ASCII range are interpreted according to the locale and
+ * the OS, which is somethign we don't control (network of other
+ * people).
+ * Routines in here try to deal with that in asafe way.
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Escape non-ASCII characters from ESSID.
+ * This allow us to display those weirds characters to the user.
+ *
+ * Source is 32 bytes max.
+ * Destination buffer needs to be at least 129 bytes, will be NUL
+ * terminated.
+ */
+void
+iw_essid_escape(char *		dest,
+		const char *	src,
+		const int	slen)
+{
+  const unsigned char *	s = (const unsigned char *) src;
+  const unsigned char *	e = s + slen;
+  char *		d = dest;
+
+  /* Look every character of the string */
+  while(s < e)
+    {
+      int	isescape;
+
+      /* Escape the escape to avoid ambiguity.
+       * We do a fast path test for performance reason. Compiler will
+       * optimise all that ;-) */
+      if(*s == '\\')
+	{
+	  /* Check if we would confuse it with an escape sequence */
+	  if((e-s) > 4 && (s[1] == 'x')
+	     && (isxdigit(s[2])) && (isxdigit(s[3])))
+	    {
+	      isescape = 1;
+	    }
+	  else
+	    isescape = 0;
+	}
+      else
+	isescape = 0;
+      
+
+      /* Is it a non-ASCII character ??? */
+      if(isescape || !isascii(*s) || iscntrl(*s))
+	{
+	  /* Escape */
+	  sprintf(d, "\\x%02X", *s);
+	  d += 4;
+	}
+      else
+	{
+	  /* Plain ASCII, just copy */
+	  *d = *s;
+	  d++;
+	}
+      s++;
+    }
+
+  /* NUL terminate destination */
+  *d = '\0';
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Un-Escape non-ASCII characters from ESSID
+ * This allow the user to specify weird characters in ESSID.
+ *
+ * The source is a NUL terminated string.
+ * Destination buffer is at least the size of source (ESSID will shrink)
+ * Destination may contains NUL, therefore we return the length.
+ * This function still works is src and dest are the same ;-)
+ */
+int
+iw_essid_unescape(char *	dest,
+		  const char *	src)
+{
+  const char *	s = src;
+  char *	d = dest;
+  char *	p;
+  int		len;
+
+  /* Look-up the next '\' sequence, stop when no more */
+  while((p = strchr(s, '\\')) != NULL)
+    {
+      /* Copy block of unescaped chars before the '\' */
+      len = p - s;
+      memcpy(d, s, len);
+      d += len;
+      s += len;		/* Identical to 's = p' */
+
+      /* Check if it is really an escape sequence. We do also check for NUL */
+      if((s[1] == 'x') && (isxdigit(s[2])) && (isxdigit(s[3])))
+	{
+	  unsigned int	temp;
+	  /* Valid Escape sequence, un-escape it */
+	  sscanf(s + 2, "%2X", &temp);
+	  *d = temp;
+	  d++;
+	  s+=4;
+	}
+      else
+	{
+	  /* Not valid, don't un-escape it */
+	  *d = *s;
+	  d++;
+	  s++;
+	}
+    }
+
+  /* Copy remaining of the string */
+  len = strlen(s);
+  memcpy(d, s, len + 1);
+  /* Return length */
+  return((d - dest) + len);
+}
+
+/********************** FREQUENCY SUBROUTINES ***********************/
+/*
+ * Note : the two functions below are the cause of troubles on
+ * various embeeded platforms, as they are the reason we require
+ * libm (math library).
+ * In this case, please use enable BUILD_NOLIBM in the makefile
+ *
+ * FIXME : check negative mantissa and exponent
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Convert a floating point the our internal representation of
+ * frequencies.
+ * The kernel doesn't want to hear about floating point, so we use
+ * this custom format instead.
+ */
+void
+iw_float2freq(double	in,
+	      iwfreq *	out)
+{
+#ifdef WE_NOLIBM
+  /* Version without libm : slower */
+  out->e = 0;
+  while(in > 1e9)
+    {
+      in /= 10;
+      out->e++;
+    }
+  out->m = (long) in;
+#else	/* WE_NOLIBM */
+  /* Version with libm : faster */
+  out->e = (short) (floor(log10(in)));
+  if(out->e > 8)
+    {
+      out->m = ((long) (floor(in / pow(10,out->e - 6)))) * 100;
+      out->e -= 8;
+    }
+  else
+    {
+      out->m = (long) in;
+      out->e = 0;
+    }
+#endif	/* WE_NOLIBM */
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Convert our internal representation of frequencies to a floating point.
+ */
+double
+iw_freq2float(const iwfreq *	in)
+{
+#ifdef WE_NOLIBM
+  /* Version without libm : slower */
+  int		i;
+  double	res = (double) in->m;
+  for(i = 0; i < in->e; i++)
+    res *= 10;
+  return(res);
+#else	/* WE_NOLIBM */
+  /* Version with libm : faster */
+  return ((double) in->m) * pow(10,in->e);
+#endif	/* WE_NOLIBM */
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Output a frequency with proper scaling
+ */
+void
+iw_print_freq_value(char *	buffer,
+		    int		buflen,
+		    double	freq)
+{
+  if(freq < KILO)
+    snprintf(buffer, buflen, "%g", freq);
+  else
+    {
+      char	scale;
+      int	divisor;
+
+      if(freq >= GIGA)
+	{
+	  scale = 'G';
+	  divisor = GIGA;
+	}
+      else
+	{
+	  if(freq >= MEGA)
+	    {
+	      scale = 'M';
+	      divisor = MEGA;
+	    }
+	  else
+	    {
+	      scale = 'k';
+	      divisor = KILO;
+	    }
+	}
+      snprintf(buffer, buflen, "%g %cHz", freq / divisor, scale);
+    }
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Output a frequency with proper scaling
+ */
+void
+iw_print_freq(char *	buffer,
+	      int	buflen,
+	      double	freq,
+	      int	channel,
+	      int	freq_flags)
+{
+  char	sep = ((freq_flags & IW_FREQ_FIXED) ? '=' : ':');
+  char	vbuf[16];
+
+  /* Print the frequency/channel value */
+  iw_print_freq_value(vbuf, sizeof(vbuf), freq);
+
+  /* Check if channel only */
+  if(freq < KILO)
+    snprintf(buffer, buflen, "Channel%c%s", sep, vbuf);
+  else
+    {
+      /* Frequency. Check if we have a channel as well */
+      if(channel >= 0)
+	snprintf(buffer, buflen, "Frequency%c%s (Channel %d)",
+		 sep, vbuf, channel);
+      else
+	snprintf(buffer, buflen, "Frequency%c%s", sep, vbuf);
+    }
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Convert a frequency to a channel (negative -> error)
+ */
+int
+iw_freq_to_channel(double			freq,
+		   const struct iw_range *	range)
+{
+  double	ref_freq;
+  int		k;
+
+  /* Check if it's a frequency or not already a channel */
+  if(freq < KILO)
+    return(-1);
+
+  /* We compare the frequencies as double to ignore differences
+   * in encoding. Slower, but safer... */
+  for(k = 0; k < range->num_frequency; k++)
+    {
+      ref_freq = iw_freq2float(&(range->freq[k]));
+      if(freq == ref_freq)
+	return(range->freq[k].i);
+    }
+  /* Not found */
+  return(-2);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Convert a channel to a frequency (negative -> error)
+ * Return the channel on success
+ */
+int
+iw_channel_to_freq(int				channel,
+		   double *			pfreq,
+		   const struct iw_range *	range)
+{
+  int		has_freq = 0;
+  int		k;
+
+  /* Check if the driver support only channels or if it has frequencies */
+  for(k = 0; k < range->num_frequency; k++)
+    {
+      if((range->freq[k].e != 0) || (range->freq[k].m > (int) KILO))
+	has_freq = 1;
+    }
+  if(!has_freq)
+    return(-1);
+
+  /* Find the correct frequency in the list */
+  for(k = 0; k < range->num_frequency; k++)
+    {
+      if(range->freq[k].i == channel)
+	{
+	  *pfreq = iw_freq2float(&(range->freq[k]));
+	  return(channel);
+	}
+    }
+  /* Not found */
+  return(-2);
+}
+
+/*********************** BITRATE SUBROUTINES ***********************/
+
+/*------------------------------------------------------------------*/
+/*
+ * Output a bitrate with proper scaling
+ */
+void
+iw_print_bitrate(char *	buffer,
+		 int	buflen,
+		 int	bitrate)
+{
+  double	rate = bitrate;
+  char		scale;
+  int		divisor;
+
+  if(rate >= GIGA)
+    {
+      scale = 'G';
+      divisor = GIGA;
+    }
+  else
+    {
+      if(rate >= MEGA)
+	{
+	  scale = 'M';
+	  divisor = MEGA;
+	}
+      else
+	{
+	  scale = 'k';
+	  divisor = KILO;
+	}
+    }
+  snprintf(buffer, buflen, "%g %cb/s", rate / divisor, scale);
+}
+
+/************************ POWER SUBROUTINES *************************/
+
+/*------------------------------------------------------------------*/
+/*
+ * Convert a value in dBm to a value in milliWatt.
+ */
+int
+iw_dbm2mwatt(int	in)
+{
+#ifdef WE_NOLIBM
+  /* Version without libm : slower */
+  int		ip = in / 10;
+  int		fp = in % 10;
+  int		k;
+  double	res = 1.0;
+
+  /* Split integral and floating part to avoid accumulating rounding errors */
+  for(k = 0; k < ip; k++)
+    res *= 10;
+  for(k = 0; k < fp; k++)
+    res *= LOG10_MAGIC;
+  return((int) res);
+#else	/* WE_NOLIBM */
+  /* Version with libm : faster */
+  return((int) (floor(pow(10.0, (((double) in) / 10.0)))));
+#endif	/* WE_NOLIBM */
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Convert a value in milliWatt to a value in dBm.
+ */
+int
+iw_mwatt2dbm(int	in)
+{
+#ifdef WE_NOLIBM
+  /* Version without libm : slower */
+  double	fin = (double) in;
+  int		res = 0;
+
+  /* Split integral and floating part to avoid accumulating rounding errors */
+  while(fin > 10.0)
+    {
+      res += 10;
+      fin /= 10.0;
+    }
+  while(fin > 1.000001)	/* Eliminate rounding errors, take ceil */
+    {
+      res += 1;
+      fin /= LOG10_MAGIC;
+    }
+  return(res);
+#else	/* WE_NOLIBM */
+  /* Version with libm : faster */
+  return((int) (ceil(10.0 * log10((double) in))));
+#endif	/* WE_NOLIBM */
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Output a txpower with proper conversion
+ */
+void
+iw_print_txpower(char *			buffer,
+		 int			buflen,
+		 struct iw_param *	txpower)
+{
+  int		dbm;
+
+  /* Check if disabled */
+  if(txpower->disabled)
+    {
+      snprintf(buffer, buflen, "off");
+    }
+  else
+    {
+      /* Check for relative values */
+      if(txpower->flags & IW_TXPOW_RELATIVE)
+	{
+	  snprintf(buffer, buflen, "%d", txpower->value);
+	}
+      else
+	{
+	  /* Convert everything to dBm */
+	  if(txpower->flags & IW_TXPOW_MWATT)
+	    dbm = iw_mwatt2dbm(txpower->value);
+	  else
+	    dbm = txpower->value;
+
+	  /* Display */
+	  snprintf(buffer, buflen, "%d dBm", dbm);
+	}
+    }
+}
+
+/********************** STATISTICS SUBROUTINES **********************/
+
+/*------------------------------------------------------------------*/
+/*
+ * Read /proc/net/wireless to get the latest statistics
+ * Note : strtok not thread safe, not used in WE-12 and later.
+ */
+int
+iw_get_stats(int		skfd,
+	     const char *	ifname,
+	     iwstats *		stats,
+	     const iwrange *	range,
+	     int		has_range)
+{
+  /* Fortunately, we can always detect this condition properly */
+  if((has_range) && (range->we_version_compiled > 11))
+    {
+      struct iwreq		wrq;
+      wrq.u.data.pointer = (caddr_t) stats;
+      wrq.u.data.length = sizeof(struct iw_statistics);
+      wrq.u.data.flags = 1;		/* Clear updated flag */
+      strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
+      if(iw_get_ext(skfd, ifname, SIOCGIWSTATS, &wrq) < 0)
+	return(-1);
+
+      /* Format has not changed since WE-12, no conversion */
+      return(0);
+    }
+  else
+    {
+      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);
+	      /* No conversion needed */
+	      return 0;
+	    }
+	}
+      fclose(f);
+      return -1;
+    }
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Output the link statistics, taking care of formating
+ */
+void
+iw_print_stats(char *		buffer,
+	       int		buflen,
+	       const iwqual *	qual,
+	       const iwrange *	range,
+	       int		has_range)
+{
+  int		len;
+
+  /* People are very often confused by the 8 bit arithmetic happening
+   * here.
+   * All the values here are encoded in a 8 bit integer. 8 bit integers
+   * are either unsigned [0 ; 255], signed [-128 ; +127] or
+   * negative [-255 ; 0].
+   * Further, on 8 bits, 0x100 == 256 == 0.
+   *
+   * Relative/percent values are always encoded unsigned, between 0 and 255.
+   * Absolute/dBm values are always encoded between -192 and 63.
+   * (Note that up to version 28 of Wireless Tools, dBm used to be
+   *  encoded always negative, between -256 and -1).
+   *
+   * How do we separate relative from absolute values ?
+   * The old way is to use the range to do that. As of WE-19, we have
+   * an explicit IW_QUAL_DBM flag in updated...
+   * The range allow to specify the real min/max of the value. As the
+   * range struct only specify one bound of the value, we assume that
+   * the other bound is 0 (zero).
+   * For relative values, range is [0 ; range->max].
+   * For absolute values, range is [range->max ; 63].
+   *
+   * Let's take two example :
+   * 1) value is 75%. qual->value = 75 ; range->max_qual.value = 100
+   * 2) value is -54dBm. noise floor of the radio is -104dBm.
+   *    qual->value = -54 = 202 ; range->max_qual.value = -104 = 152
+   *
+   * Jean II
+   */
+
+  /* Just do it...
+   * The old way to detect dBm require both the range and a non-null
+   * level (which confuse the test). The new way can deal with level of 0
+   * because it does an explicit test on the flag. */
+  if(has_range && ((qual->level != 0)
+		   || (qual->updated & (IW_QUAL_DBM | IW_QUAL_RCPI))))
+    {
+      /* Deal with quality : always a relative value */
+      if(!(qual->updated & IW_QUAL_QUAL_INVALID))
+	{
+	  len = snprintf(buffer, buflen, "Quality%c%d/%d  ",
+			 qual->updated & IW_QUAL_QUAL_UPDATED ? '=' : ':',
+			 qual->qual, range->max_qual.qual);
+	  buffer += len;
+	  buflen -= len;
+	}
+
+      /* Check if the statistics are in RCPI (IEEE 802.11k) */
+      if(qual->updated & IW_QUAL_RCPI)
+	{
+	  /* Deal with signal level in RCPI */
+	  /* RCPI = int{(Power in dBm +110)*2} for 0dbm > Power > -110dBm */
+	  if(!(qual->updated & IW_QUAL_LEVEL_INVALID))
+	    {
+	      double	rcpilevel = (qual->level / 2.0) - 110.0;
+	      len = snprintf(buffer, buflen, "Signal level%c%g dBm  ",
+			     qual->updated & IW_QUAL_LEVEL_UPDATED ? '=' : ':',
+			     rcpilevel);
+	      buffer += len;
+	      buflen -= len;
+	    }
+
+	  /* Deal with noise level in dBm (absolute power measurement) */
+	  if(!(qual->updated & IW_QUAL_NOISE_INVALID))
+	    {
+	      double	rcpinoise = (qual->noise / 2.0) - 110.0;
+	      len = snprintf(buffer, buflen, "Noise level%c%g dBm",
+			     qual->updated & IW_QUAL_NOISE_UPDATED ? '=' : ':',
+			     rcpinoise);
+	    }
+	}
+      else
+	{
+	  /* Check if the statistics are in dBm */
+	  if((qual->updated & IW_QUAL_DBM)
+	     || (qual->level > range->max_qual.level))
+	    {
+	      /* Deal with signal level in dBm  (absolute power measurement) */
+	      if(!(qual->updated & IW_QUAL_LEVEL_INVALID))
+		{
+		  int	dblevel = qual->level;
+		  /* Implement a range for dBm [-192; 63] */
+		  if(qual->level >= 64)
+		    dblevel -= 0x100;
+		  len = snprintf(buffer, buflen, "Signal level%c%d dBm  ",
+				 qual->updated & IW_QUAL_LEVEL_UPDATED ? '=' : ':',
+				 dblevel);
+		  buffer += len;
+		  buflen -= len;
+		}
+
+	      /* Deal with noise level in dBm (absolute power measurement) */
+	      if(!(qual->updated & IW_QUAL_NOISE_INVALID))
+		{
+		  int	dbnoise = qual->noise;
+		  /* Implement a range for dBm [-192; 63] */
+		  if(qual->noise >= 64)
+		    dbnoise -= 0x100;
+		  len = snprintf(buffer, buflen, "Noise level%c%d dBm",
+				 qual->updated & IW_QUAL_NOISE_UPDATED ? '=' : ':',
+				 dbnoise);
+		}
+	    }
+	  else
+	    {
+	      /* Deal with signal level as relative value (0 -> max) */
+	      if(!(qual->updated & IW_QUAL_LEVEL_INVALID))
+		{
+		  len = snprintf(buffer, buflen, "Signal level%c%d/%d  ",
+				 qual->updated & IW_QUAL_LEVEL_UPDATED ? '=' : ':',
+				 qual->level, range->max_qual.level);
+		  buffer += len;
+		  buflen -= len;
+		}
+
+	      /* Deal with noise level as relative value (0 -> max) */
+	      if(!(qual->updated & IW_QUAL_NOISE_INVALID))
+		{
+		  len = snprintf(buffer, buflen, "Noise level%c%d/%d",
+				 qual->updated & IW_QUAL_NOISE_UPDATED ? '=' : ':',
+				 qual->noise, range->max_qual.noise);
+		}
+	    }
+	}
+    }
+  else
+    {
+      /* We can't read the range, so we don't know... */
+      snprintf(buffer, buflen,
+	       "Quality:%d  Signal level:%d  Noise level:%d",
+	       qual->qual, qual->level, qual->noise);
+    }
+}
+
+/*********************** ENCODING SUBROUTINES ***********************/
+
+/*------------------------------------------------------------------*/
+/*
+ * Output the encoding key, with a nice formating
+ */
+void
+iw_print_key(char *			buffer,
+	     int			buflen,
+	     const unsigned char *	key,		/* Must be unsigned */
+	     int			key_size,
+	     int			key_flags)
+{
+  int	i;
+
+  /* Check buffer size -> 1 bytes => 2 digits + 1/2 separator */
+  if((key_size * 3) > buflen)
+    {
+      snprintf(buffer, buflen, "<too big>");
+      return;
+    }
+
+  /* Is the key present ??? */
+  if(key_flags & IW_ENCODE_NOKEY)
+    {
+      /* Nope : print on or dummy */
+      if(key_size <= 0)
+	strcpy(buffer, "on");			/* Size checked */
+      else
+	{
+	  strcpy(buffer, "**");			/* Size checked */
+	  buffer +=2;
+	  for(i = 1; i < key_size; i++)
+	    {
+	      if((i & 0x1) == 0)
+		strcpy(buffer++, "-");		/* Size checked */
+	      strcpy(buffer, "**");		/* Size checked */
+	      buffer +=2;
+	    }
+	}
+    }
+  else
+    {
+      /* Yes : print the key */
+      sprintf(buffer, "%.2X", key[0]);		/* Size checked */
+      buffer +=2;
+      for(i = 1; i < key_size; i++)
+	{
+	  if((i & 0x1) == 0)
+	    strcpy(buffer++, "-");		/* Size checked */
+	  sprintf(buffer, "%.2X", key[i]);	/* Size checked */
+	  buffer +=2;
+	}
+    }
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Convert a passphrase into a key
+ * ### NOT IMPLEMENTED ###
+ * Return size of the key, or 0 (no key) or -1 (error)
+ */
+static int
+iw_pass_key(const char *	input,
+	    unsigned char *	key)
+{
+  input = input; key = key;
+  fprintf(stderr, "Error: Passphrase not implemented\n");
+  return(-1);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Parse a key from the command line.
+ * Return size of the key, or 0 (no key) or -1 (error)
+ * If the key is too long, it's simply truncated...
+ */
+int
+iw_in_key(const char *		input,
+	  unsigned char *	key)
+{
+  int		keylen = 0;
+
+  /* Check the type of key */
+  if(!strncmp(input, "s:", 2))
+    {
+      /* First case : as an ASCII string (Lucent/Agere cards) */
+      keylen = strlen(input + 2);		/* skip "s:" */
+      if(keylen > IW_ENCODING_TOKEN_MAX)
+	keylen = IW_ENCODING_TOKEN_MAX;
+      memcpy(key, input + 2, keylen);
+    }
+  else
+    if(!strncmp(input, "p:", 2))
+      {
+	/* Second case : as a passphrase (PrismII cards) */
+	return(iw_pass_key(input + 2, key));		/* skip "p:" */
+      }
+    else
+      {
+	const char *	p;
+	int		dlen;	/* Digits sequence length */
+	unsigned char	out[IW_ENCODING_TOKEN_MAX];
+
+	/* Third case : as hexadecimal digits */
+	p = input;
+	dlen = -1;
+
+	/* Loop until we run out of chars in input or overflow the output */
+	while(*p != '\0')
+	  {
+	    int	temph;
+	    int	templ;
+	    int	count;
+	    /* No more chars in this sequence */
+	    if(dlen <= 0)
+	      {
+		/* Skip separator */
+		if(dlen == 0)
+		  p++;
+		/* Calculate num of char to next separator */
+		dlen = strcspn(p, "-:;.,");
+	      }
+	    /* Get each char separatly (and not by two) so that we don't
+	     * get confused by 'enc' (=> '0E'+'0C') and similar */
+	    count = sscanf(p, "%1X%1X", &temph, &templ);
+	    if(count < 1)
+	      return(-1);		/* Error -> non-hex char */
+	    /* Fixup odd strings such as '123' is '01'+'23' and not '12'+'03'*/
+	    if(dlen % 2)
+	      count = 1;
+	    /* Put back two chars as one byte and output */
+	    if(count == 2)
+	      templ |= temph << 4;
+	    else
+	      templ = temph;
+	    out[keylen++] = (unsigned char) (templ & 0xFF);
+	    /* Check overflow in output */
+	    if(keylen >= IW_ENCODING_TOKEN_MAX)
+	      break;
+	    /* Move on to next chars */
+	    p += count;
+	    dlen -= count;
+	  }
+	/* We use a temporary output buffer 'out' so that if there is
+	 * an error, we don't overwrite the original key buffer.
+	 * Because of the way iwconfig loop on multiple key/enc arguments
+	 * until it finds an error in here, this is necessary to avoid
+	 * silently corrupting the encryption key... */
+	memcpy(key, out, keylen);
+      }
+
+#ifdef DEBUG
+  {
+    char buf[IW_ENCODING_TOKEN_MAX * 3];
+    iw_print_key(buf, sizeof(buf), key, keylen, 0);
+    printf("Got key : %d [%s]\n", keylen, buf);
+  }
+#endif
+
+  return(keylen);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Parse a key from the command line.
+ * Return size of the key, or 0 (no key) or -1 (error)
+ */
+int
+iw_in_key_full(int		skfd,
+	       const char *	ifname,
+	       const char *	input,
+	       unsigned char *	key,
+	       __u16 *		flags)
+{
+  int		keylen = 0;
+  char *	p;
+
+  if(!strncmp(input, "l:", 2))
+    {
+      struct iw_range	range;
+
+      /* Extra case : as a login (user:passwd - Cisco LEAP) */
+      keylen = strlen(input + 2) + 1;		/* skip "l:", add '\0' */
+      /* Most user/password is 8 char, so 18 char total, < 32 */
+      if(keylen > IW_ENCODING_TOKEN_MAX)
+	keylen = IW_ENCODING_TOKEN_MAX;
+      memcpy(key, input + 2, keylen);
+
+      /* Separate the two strings */
+      p = strchr((char *) key, ':');
+      if(p == NULL)
+	{
+	  fprintf(stderr, "Error: Invalid login format\n");
+	  return(-1);
+	}
+      *p = '\0';
+
+      /* Extract range info */
+      if(iw_get_range_info(skfd, ifname, &range) < 0)
+	/* Hum... Maybe we should return an error ??? */
+	memset(&range, 0, sizeof(range));
+
+      if(range.we_version_compiled > 15)
+	{
+
+	  printf("flags = %X, index = %X\n",
+		 *flags, range.encoding_login_index);
+	  if((*flags & IW_ENCODE_INDEX) == 0)
+	    {
+	      /* Extract range info */
+	      if(iw_get_range_info(skfd, ifname, &range) < 0)
+		memset(&range, 0, sizeof(range));
+	      printf("flags = %X, index = %X\n", *flags, range.encoding_login_index);
+	      /* Set the index the driver expects */
+	      *flags |= range.encoding_login_index & IW_ENCODE_INDEX;
+	    }
+	  printf("flags = %X, index = %X\n", *flags, range.encoding_login_index);
+	}
+    }
+  else
+    /* Simpler routine above */
+    keylen = iw_in_key(input, key);
+
+  return(keylen);
+}
+
+/******************* POWER MANAGEMENT SUBROUTINES *******************/
+
+/*------------------------------------------------------------------*/
+/*
+ * Output a power management value with all attributes...
+ */
+void
+iw_print_pm_value(char *	buffer,
+		  int		buflen,
+		  int		value,
+		  int		flags,
+		  int		we_version)
+{
+  /* Check size */
+  if(buflen < 25)
+    {
+      snprintf(buffer, buflen, "<too big>");
+      return;
+    }
+  buflen -= 25;
+
+  /* Modifiers */
+  if(flags & IW_POWER_MIN)
+    {
+      strcpy(buffer, " min");				/* Size checked */
+      buffer += 4;
+    }
+  if(flags & IW_POWER_MAX)
+    {
+      strcpy(buffer, " max");				/* Size checked */
+      buffer += 4;
+    }
+
+  /* Type */
+  if(flags & IW_POWER_TIMEOUT)
+    {
+      strcpy(buffer, " timeout:");			/* Size checked */
+      buffer += 9;
+    }
+  else
+    {
+      if(flags & IW_POWER_SAVING)
+	{
+	  strcpy(buffer, " saving:");			/* Size checked */
+	  buffer += 8;
+	}
+      else
+	{
+	  strcpy(buffer, " period:");			/* Size checked */
+	  buffer += 8;
+	}
+    }
+
+  /* Display value without units */
+  if(flags & IW_POWER_RELATIVE)
+    {
+      if(we_version < 21)
+	value /= MEGA;
+      snprintf(buffer, buflen, "%d", value);
+    }
+  else
+    {
+      /* Display value with units */
+      if(value >= (int) MEGA)
+	snprintf(buffer, buflen, "%gs", ((double) value) / MEGA);
+      else
+	if(value >= (int) KILO)
+	  snprintf(buffer, buflen, "%gms", ((double) value) / KILO);
+	else
+	  snprintf(buffer, buflen, "%dus", value);
+    }
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Output a power management mode
+ */
+void
+iw_print_pm_mode(char *	buffer,
+		 int	buflen,
+		 int	flags)
+{
+  /* Check size */
+  if(buflen < 28)
+    {
+      snprintf(buffer, buflen, "<too big>");
+      return;
+    }
+
+  /* Print the proper mode... */
+  switch(flags & IW_POWER_MODE)
+    {
+    case IW_POWER_UNICAST_R:
+      strcpy(buffer, "mode:Unicast only received");	/* Size checked */
+      break;
+    case IW_POWER_MULTICAST_R:
+      strcpy(buffer, "mode:Multicast only received");	/* Size checked */
+      break;
+    case IW_POWER_ALL_R:
+      strcpy(buffer, "mode:All packets received");	/* Size checked */
+      break;
+    case IW_POWER_FORCE_S:
+      strcpy(buffer, "mode:Force sending");		/* Size checked */
+      break;
+    case IW_POWER_REPEATER:
+      strcpy(buffer, "mode:Repeat multicasts");		/* Size checked */
+      break;
+    default:
+      strcpy(buffer, "");				/* Size checked */
+      break;
+    }
+}
+
+/***************** RETRY LIMIT/LIFETIME SUBROUTINES *****************/
+
+/*------------------------------------------------------------------*/
+/*
+ * Output a retry value with all attributes...
+ */
+void
+iw_print_retry_value(char *	buffer,
+		     int	buflen,
+		     int	value,
+		     int	flags,
+		     int	we_version)
+{
+  /* Check buffer size */
+  if(buflen < 20)
+    {
+      snprintf(buffer, buflen, "<too big>");
+      return;
+    }
+  buflen -= 20;
+
+  /* Modifiers */
+  if(flags & IW_RETRY_MIN)
+    {
+      strcpy(buffer, " min");				/* Size checked */
+      buffer += 4;
+    }
+  if(flags & IW_RETRY_MAX)
+    {
+      strcpy(buffer, " max");				/* Size checked */
+      buffer += 4;
+    }
+  if(flags & IW_RETRY_SHORT)
+    {
+      strcpy(buffer, " short");				/* Size checked */
+      buffer += 6;
+    }
+  if(flags & IW_RETRY_LONG)
+    {
+      strcpy(buffer, "  long");				/* Size checked */
+      buffer += 6;
+    }
+
+  /* Type lifetime of limit */
+  if(flags & IW_RETRY_LIFETIME)
+    {
+      strcpy(buffer, " lifetime:");			/* Size checked */
+      buffer += 10;
+
+      /* Display value without units */
+      if(flags & IW_RETRY_RELATIVE)
+	{
+	  if(we_version < 21)
+	    value /= MEGA;
+	  snprintf(buffer, buflen, "%d", value);
+	}
+      else
+	{
+	  /* Display value with units */
+	  if(value >= (int) MEGA)
+	    snprintf(buffer, buflen, "%gs", ((double) value) / MEGA);
+	  else
+	    if(value >= (int) KILO)
+	      snprintf(buffer, buflen, "%gms", ((double) value) / KILO);
+	    else
+	      snprintf(buffer, buflen, "%dus", value);
+	}
+    }
+  else
+    snprintf(buffer, buflen, " limit:%d", value);
+}
+
+/************************* TIME SUBROUTINES *************************/
+
+/*------------------------------------------------------------------*/
+/*
+ * Print timestamps
+ * Inspired from irdadump...
+ */
+void
+iw_print_timeval(char *				buffer,
+		 int				buflen,
+		 const struct timeval *		timev,
+		 const struct timezone *	tz)
+{
+        int s;
+
+	s = (timev->tv_sec - tz->tz_minuteswest * 60) % 86400;
+	snprintf(buffer, buflen, "%02d:%02d:%02d.%06u", 
+		s / 3600, (s % 3600) / 60, 
+		s % 60, (u_int32_t) timev->tv_usec);
+}
+
+/*********************** ADDRESS SUBROUTINES ************************/
+/*
+ * This section is mostly a cut & past from net-tools-1.2.0
+ * (Well... This has evolved over the years)
+ * manage address display and input...
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Check if interface support the right MAC address type...
+ */
+int
+iw_check_mac_addr_type(int		skfd,
+		       const char *	ifname)
+{
+  struct ifreq		ifr;
+
+  /* Get the type of hardware address */
+  strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
+  if((ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) ||
+     ((ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER)
+      && (ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211)))
+    {
+      /* Deep trouble... */
+      fprintf(stderr, "Interface %s doesn't support MAC addresses\n",
+	     ifname);
+      return(-1);
+    }
+
+#ifdef DEBUG
+  {
+    char buf[20];
+    printf("Hardware : %d - %s\n", ifr.ifr_hwaddr.sa_family,
+	   iw_saether_ntop(&ifr.ifr_hwaddr, buf));
+  }
+#endif
+
+  return(0);
+}
+
+
+/*------------------------------------------------------------------*/
+/*
+ * Check if interface support the right interface address type...
+ */
+int
+iw_check_if_addr_type(int		skfd,
+		      const char *	ifname)
+{
+  struct ifreq		ifr;
+
+  /* Get the type of interface address */
+  strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
+  if((ioctl(skfd, SIOCGIFADDR, &ifr) < 0) ||
+     (ifr.ifr_addr.sa_family !=  AF_INET))
+    {
+      /* Deep trouble... */
+      fprintf(stderr, "Interface %s doesn't support IP addresses\n", ifname);
+      return(-1);
+    }
+
+#ifdef DEBUG
+  printf("Interface : %d - 0x%lX\n", ifr.ifr_addr.sa_family,
+	 *((unsigned long *) ifr.ifr_addr.sa_data));
+#endif
+
+  return(0);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Display an arbitrary length MAC address in readable format.
+ */
+char *
+iw_mac_ntop(const unsigned char *	mac,
+	    int				maclen,
+	    char *			buf,
+	    int				buflen)
+{
+  int	i;
+
+  /* Overflow check (don't forget '\0') */
+  if(buflen < (maclen * 3 - 1 + 1))
+    return(NULL);
+
+  /* First byte */
+  sprintf(buf, "%02X", mac[0]);
+
+  /* Other bytes */
+  for(i = 1; i < maclen; i++)
+    sprintf(buf + (i * 3) - 1, ":%02X", mac[i]);
+  return(buf);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Display an Ethernet address in readable format.
+ */
+void
+iw_ether_ntop(const struct ether_addr *	eth,
+	      char *			buf)
+{
+  sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X",
+	  eth->ether_addr_octet[0], eth->ether_addr_octet[1],
+	  eth->ether_addr_octet[2], eth->ether_addr_octet[3],
+	  eth->ether_addr_octet[4], eth->ether_addr_octet[5]);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Display an Wireless Access Point Socket Address in readable format.
+ * Note : 0x44 is an accident of history, that's what the Orinoco/PrismII
+ * chipset report, and the driver doesn't filter it.
+ */
+char *
+iw_sawap_ntop(const struct sockaddr *	sap,
+	      char *			buf)
+{
+  const struct ether_addr ether_zero = {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }};
+  const struct ether_addr ether_bcast = {{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }};
+  const struct ether_addr ether_hack = {{ 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 }};
+  const struct ether_addr * ether_wap = (const struct ether_addr *) sap->sa_data;
+
+  if(!iw_ether_cmp(ether_wap, &ether_zero))
+    sprintf(buf, "Not-Associated");
+  else
+    if(!iw_ether_cmp(ether_wap, &ether_bcast))
+      sprintf(buf, "Invalid");
+    else
+      if(!iw_ether_cmp(ether_wap, &ether_hack))
+	sprintf(buf, "None");
+      else
+	iw_ether_ntop(ether_wap, buf);
+  return(buf);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Input an arbitrary length MAC address and convert to binary.
+ * Return address size.
+ */
+int
+iw_mac_aton(const char *	orig,
+	    unsigned char *	mac,
+	    int			macmax)
+{
+  const char *	p = orig;
+  int		maclen = 0;
+
+  /* Loop on all bytes of the string */
+  while(*p != '\0')
+    {
+      int	temph;
+      int	templ;
+      int	count;
+      /* Extract one byte as two chars */
+      count = sscanf(p, "%1X%1X", &temph, &templ);
+      if(count != 2)
+	break;			/* Error -> non-hex chars */
+      /* Output two chars as one byte */
+      templ |= temph << 4;
+      mac[maclen++] = (unsigned char) (templ & 0xFF);
+
+      /* Check end of string */
+      p += 2;
+      if(*p == '\0')
+	{
+#ifdef DEBUG
+	  char buf[20];
+	  iw_ether_ntop((const struct ether_addr *) mac, buf);
+	  fprintf(stderr, "iw_mac_aton(%s): %s\n", orig, buf);
+#endif
+	  return(maclen);		/* Normal exit */
+	}
+
+      /* Check overflow */
+      if(maclen >= macmax)
+	{
+#ifdef DEBUG
+	  fprintf(stderr, "iw_mac_aton(%s): trailing junk!\n", orig);
+#endif
+	  errno = E2BIG;
+	  return(0);			/* Error -> overflow */
+	}
+
+      /* Check separator */
+      if(*p != ':')
+	break;
+      p++;
+    }
+
+  /* Error... */
+#ifdef DEBUG
+  fprintf(stderr, "iw_mac_aton(%s): invalid ether address!\n", orig);
+#endif
+  errno = EINVAL;
+  return(0);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Input an Ethernet address and convert to binary.
+ */
+int
+iw_ether_aton(const char *orig, struct ether_addr *eth)
+{
+  int	maclen;
+  maclen = iw_mac_aton(orig, (unsigned char *) eth, ETH_ALEN);
+  if((maclen > 0) && (maclen < ETH_ALEN))
+    {
+      errno = EINVAL;
+      maclen = 0;
+    }
+  return(maclen);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Input an Internet address and convert to binary.
+ */
+int
+iw_in_inet(char *name, struct sockaddr *sap)
+{
+  struct hostent *hp;
+  struct netent *np;
+  struct sockaddr_in *sain = (struct sockaddr_in *) sap;
+
+  /* Grmpf. -FvK */
+  sain->sin_family = AF_INET;
+  sain->sin_port = 0;
+
+  /* Default is special, meaning 0.0.0.0. */
+  if (!strcmp(name, "default")) {
+	sain->sin_addr.s_addr = INADDR_ANY;
+	return(1);
+  }
+
+  /* Try the NETWORKS database to see if this is a known network. */
+  if ((np = getnetbyname(name)) != (struct netent *)NULL) {
+	sain->sin_addr.s_addr = htonl(np->n_net);
+	strcpy(name, np->n_name);
+	return(1);
+  }
+
+  /* Always use the resolver (DNS name + IP addresses) */
+  if ((hp = gethostbyname(name)) == (struct hostent *)NULL) {
+	errno = h_errno;
+	return(-1);
+  }
+  memcpy((char *) &sain->sin_addr, (char *) hp->h_addr_list[0], hp->h_length);
+  strcpy(name, hp->h_name);
+  return(0);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Input an address and convert to binary.
+ */
+int
+iw_in_addr(int		skfd,
+	   const char *	ifname,
+	   char *	bufp,
+	   struct sockaddr *sap)
+{
+  /* Check if it is a hardware or IP address */
+  if(strchr(bufp, ':') == NULL)
+    {
+      struct sockaddr	if_address;
+      struct arpreq	arp_query;
+
+      /* Check if we have valid interface address type */
+      if(iw_check_if_addr_type(skfd, ifname) < 0)
+	{
+	  fprintf(stderr, "%-8.16s  Interface doesn't support IP addresses\n", ifname);
+	  return(-1);
+	}
+
+      /* Read interface address */
+      if(iw_in_inet(bufp, &if_address) < 0)
+	{
+	  fprintf(stderr, "Invalid interface address %s\n", bufp);
+	  return(-1);
+	}
+
+      /* Translate IP addresses to MAC addresses */
+      memcpy((char *) &(arp_query.arp_pa),
+	     (char *) &if_address,
+	     sizeof(struct sockaddr));
+      arp_query.arp_ha.sa_family = 0;
+      arp_query.arp_flags = 0;
+      /* The following restrict the search to the interface only */
+      /* For old kernels which complain, just comment it... */
+      strncpy(arp_query.arp_dev, ifname, IFNAMSIZ);
+      if((ioctl(skfd, SIOCGARP, &arp_query) < 0) ||
+	 !(arp_query.arp_flags & ATF_COM))
+	{
+	  fprintf(stderr, "Arp failed for %s on %s... (%d)\nTry to ping the address before setting it.\n",
+		  bufp, ifname, errno);
+	  return(-1);
+	}
+
+      /* Store new MAC address */
+      memcpy((char *) sap,
+	     (char *) &(arp_query.arp_ha),
+	     sizeof(struct sockaddr));
+
+#ifdef DEBUG
+      {
+	char buf[20];
+	printf("IP Address %s => Hw Address = %s\n",
+	       bufp, iw_saether_ntop(sap, buf));
+      }
+#endif
+    }
+  else	/* If it's an hardware address */
+    {
+      /* Check if we have valid mac address type */
+      if(iw_check_mac_addr_type(skfd, ifname) < 0)
+	{
+	  fprintf(stderr, "%-8.16s  Interface doesn't support MAC addresses\n", ifname);
+	  return(-1);
+	}
+
+      /* Get the hardware address */
+      if(iw_saether_aton(bufp, sap) == 0)
+	{
+	  fprintf(stderr, "Invalid hardware address %s\n", bufp);
+	  return(-1);
+	}
+    }
+
+#ifdef DEBUG
+  {
+    char buf[20];
+    printf("Hw Address = %s\n", iw_saether_ntop(sap, buf));
+  }
+#endif
+
+  return(0);
+}
+
+/************************* MISC SUBROUTINES **************************/
+
+/* Size (in bytes) of various events */
+static const int priv_type_size[] = {
+	0,				/* IW_PRIV_TYPE_NONE */
+	1,				/* IW_PRIV_TYPE_BYTE */
+	1,				/* IW_PRIV_TYPE_CHAR */
+	0,				/* Not defined */
+	sizeof(__u32),			/* IW_PRIV_TYPE_INT */
+	sizeof(struct iw_freq),		/* IW_PRIV_TYPE_FLOAT */
+	sizeof(struct sockaddr),	/* IW_PRIV_TYPE_ADDR */
+	0,				/* Not defined */
+};
+
+/*------------------------------------------------------------------*/
+/*
+ * Max size in bytes of an private argument.
+ */
+int
+iw_get_priv_size(int	args)
+{
+  int	num = args & IW_PRIV_SIZE_MASK;
+  int	type = (args & IW_PRIV_TYPE_MASK) >> 12;
+
+  return(num * priv_type_size[type]);
+}
+
+/************************ EVENT SUBROUTINES ************************/
+/*
+ * The Wireless Extension API 14 and greater define Wireless Events,
+ * that are used for various events and scanning.
+ * Those functions help the decoding of events, so are needed only in
+ * this case.
+ */
+
+/* -------------------------- CONSTANTS -------------------------- */
+
+/* Type of headers we know about (basically union iwreq_data) */
+#define IW_HEADER_TYPE_NULL	0	/* Not available */
+#define IW_HEADER_TYPE_CHAR	2	/* char [IFNAMSIZ] */
+#define IW_HEADER_TYPE_UINT	4	/* __u32 */
+#define IW_HEADER_TYPE_FREQ	5	/* struct iw_freq */
+#define IW_HEADER_TYPE_ADDR	6	/* struct sockaddr */
+#define IW_HEADER_TYPE_POINT	8	/* struct iw_point */
+#define IW_HEADER_TYPE_PARAM	9	/* struct iw_param */
+#define IW_HEADER_TYPE_QUAL	10	/* struct iw_quality */
+
+/* Handling flags */
+/* Most are not implemented. I just use them as a reminder of some
+ * cool features we might need one day ;-) */
+#define IW_DESCR_FLAG_NONE	0x0000	/* Obvious */
+/* Wrapper level flags */
+#define IW_DESCR_FLAG_DUMP	0x0001	/* Not part of the dump command */
+#define IW_DESCR_FLAG_EVENT	0x0002	/* Generate an event on SET */
+#define IW_DESCR_FLAG_RESTRICT	0x0004	/* GET : request is ROOT only */
+				/* SET : Omit payload from generated iwevent */
+#define IW_DESCR_FLAG_NOMAX	0x0008	/* GET : no limit on request size */
+/* Driver level flags */
+#define IW_DESCR_FLAG_WAIT	0x0100	/* Wait for driver event */
+
+/* ---------------------------- TYPES ---------------------------- */
+
+/*
+ * Describe how a standard IOCTL looks like.
+ */
+struct iw_ioctl_description
+{
+	__u8	header_type;		/* NULL, iw_point or other */
+	__u8	token_type;		/* Future */
+	__u16	token_size;		/* Granularity of payload */
+	__u16	min_tokens;		/* Min acceptable token number */
+	__u16	max_tokens;		/* Max acceptable token number */
+	__u32	flags;			/* Special handling of the request */
+};
+
+/* -------------------------- VARIABLES -------------------------- */
+
+/*
+ * Meta-data about all the standard Wireless Extension request we
+ * know about.
+ */
+static const struct iw_ioctl_description standard_ioctl_descr[] = {
+	[SIOCSIWCOMMIT	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_NULL,
+	},
+	[SIOCGIWNAME	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_CHAR,
+		.flags		= IW_DESCR_FLAG_DUMP,
+	},
+	[SIOCSIWNWID	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+		.flags		= IW_DESCR_FLAG_EVENT,
+	},
+	[SIOCGIWNWID	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+		.flags		= IW_DESCR_FLAG_DUMP,
+	},
+	[SIOCSIWFREQ	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_FREQ,
+		.flags		= IW_DESCR_FLAG_EVENT,
+	},
+	[SIOCGIWFREQ	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_FREQ,
+		.flags		= IW_DESCR_FLAG_DUMP,
+	},
+	[SIOCSIWMODE	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_UINT,
+		.flags		= IW_DESCR_FLAG_EVENT,
+	},
+	[SIOCGIWMODE	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_UINT,
+		.flags		= IW_DESCR_FLAG_DUMP,
+	},
+	[SIOCSIWSENS	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCGIWSENS	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCSIWRANGE	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_NULL,
+	},
+	[SIOCGIWRANGE	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= sizeof(struct iw_range),
+		.flags		= IW_DESCR_FLAG_DUMP,
+	},
+	[SIOCSIWPRIV	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_NULL,
+	},
+	[SIOCGIWPRIV	- SIOCIWFIRST] = { /* (handled directly by us) */
+		.header_type	= IW_HEADER_TYPE_NULL,
+	},
+	[SIOCSIWSTATS	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_NULL,
+	},
+	[SIOCGIWSTATS	- SIOCIWFIRST] = { /* (handled directly by us) */
+		.header_type	= IW_HEADER_TYPE_NULL,
+		.flags		= IW_DESCR_FLAG_DUMP,
+	},
+	[SIOCSIWSPY	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= sizeof(struct sockaddr),
+		.max_tokens	= IW_MAX_SPY,
+	},
+	[SIOCGIWSPY	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= sizeof(struct sockaddr) +
+				  sizeof(struct iw_quality),
+		.max_tokens	= IW_MAX_SPY,
+	},
+	[SIOCSIWTHRSPY	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= sizeof(struct iw_thrspy),
+		.min_tokens	= 1,
+		.max_tokens	= 1,
+	},
+	[SIOCGIWTHRSPY	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= sizeof(struct iw_thrspy),
+		.min_tokens	= 1,
+		.max_tokens	= 1,
+	},
+	[SIOCSIWAP	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_ADDR,
+	},
+	[SIOCGIWAP	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_ADDR,
+		.flags		= IW_DESCR_FLAG_DUMP,
+	},
+	[SIOCSIWMLME	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.min_tokens	= sizeof(struct iw_mlme),
+		.max_tokens	= sizeof(struct iw_mlme),
+	},
+	[SIOCGIWAPLIST	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= sizeof(struct sockaddr) +
+				  sizeof(struct iw_quality),
+		.max_tokens	= IW_MAX_AP,
+		.flags		= IW_DESCR_FLAG_NOMAX,
+	},
+	[SIOCSIWSCAN	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.min_tokens	= 0,
+		.max_tokens	= sizeof(struct iw_scan_req),
+	},
+	[SIOCGIWSCAN	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_SCAN_MAX_DATA,
+		.flags		= IW_DESCR_FLAG_NOMAX,
+	},
+	[SIOCSIWESSID	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_ESSID_MAX_SIZE + 1,
+		.flags		= IW_DESCR_FLAG_EVENT,
+	},
+	[SIOCGIWESSID	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_ESSID_MAX_SIZE + 1,
+		.flags		= IW_DESCR_FLAG_DUMP,
+	},
+	[SIOCSIWNICKN	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_ESSID_MAX_SIZE + 1,
+	},
+	[SIOCGIWNICKN	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_ESSID_MAX_SIZE + 1,
+	},
+	[SIOCSIWRATE	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCGIWRATE	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCSIWRTS	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCGIWRTS	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCSIWFRAG	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCGIWFRAG	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCSIWTXPOW	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCGIWTXPOW	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCSIWRETRY	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCGIWRETRY	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCSIWENCODE	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		/* Hack : this never returns any payload in event.
+		 * Fix the 64->32 bit hack... */
+		.token_size	= 0,
+		.max_tokens	= IW_ENCODING_TOKEN_MAX,
+		.flags		= IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT,
+	},
+	[SIOCGIWENCODE	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		/* Hack : this never returns any payload in event.
+		 * Fix the 64->32 bit hack... */
+		.token_size	= 0,
+		.max_tokens	= IW_ENCODING_TOKEN_MAX,
+		.flags		= IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT,
+	},
+	[SIOCSIWPOWER	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCGIWPOWER	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCSIWMODUL	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCGIWMODUL	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCSIWGENIE	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_GENERIC_IE_MAX,
+	},
+	[SIOCGIWGENIE	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_GENERIC_IE_MAX,
+	},
+	[SIOCSIWAUTH	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCGIWAUTH	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCSIWENCODEEXT - SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.min_tokens	= sizeof(struct iw_encode_ext),
+		.max_tokens	= sizeof(struct iw_encode_ext) +
+				  IW_ENCODING_TOKEN_MAX,
+	},
+	[SIOCGIWENCODEEXT - SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.min_tokens	= sizeof(struct iw_encode_ext),
+		.max_tokens	= sizeof(struct iw_encode_ext) +
+				  IW_ENCODING_TOKEN_MAX,
+	},
+	[SIOCSIWPMKSA - SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.min_tokens	= sizeof(struct iw_pmksa),
+		.max_tokens	= sizeof(struct iw_pmksa),
+	},
+};
+static const unsigned int standard_ioctl_num = (sizeof(standard_ioctl_descr) /
+						sizeof(struct iw_ioctl_description));
+
+/*
+ * Meta-data about all the additional standard Wireless Extension events
+ * we know about.
+ */
+static const struct iw_ioctl_description standard_event_descr[] = {
+	[IWEVTXDROP	- IWEVFIRST] = {
+		.header_type	= IW_HEADER_TYPE_ADDR,
+	},
+	[IWEVQUAL	- IWEVFIRST] = {
+		.header_type	= IW_HEADER_TYPE_QUAL,
+	},
+	[IWEVCUSTOM	- IWEVFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_CUSTOM_MAX,
+	},
+	[IWEVREGISTERED	- IWEVFIRST] = {
+		.header_type	= IW_HEADER_TYPE_ADDR,
+	},
+	[IWEVEXPIRED	- IWEVFIRST] = {
+		.header_type	= IW_HEADER_TYPE_ADDR, 
+	},
+	[IWEVGENIE	- IWEVFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_GENERIC_IE_MAX,
+	},
+	[IWEVMICHAELMICFAILURE	- IWEVFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT, 
+		.token_size	= 1,
+		.max_tokens	= sizeof(struct iw_michaelmicfailure),
+	},
+	[IWEVASSOCREQIE	- IWEVFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_GENERIC_IE_MAX,
+	},
+	[IWEVASSOCRESPIE	- IWEVFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_GENERIC_IE_MAX,
+	},
+	[IWEVPMKIDCAND	- IWEVFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= sizeof(struct iw_pmkid_cand),
+	},
+};
+static const unsigned int standard_event_num = (sizeof(standard_event_descr) /
+						sizeof(struct iw_ioctl_description));
+
+/* Size (in bytes) of various events */
+static const int event_type_size[] = {
+	IW_EV_LCP_PK_LEN,	/* IW_HEADER_TYPE_NULL */
+	0,
+	IW_EV_CHAR_PK_LEN,	/* IW_HEADER_TYPE_CHAR */
+	0,
+	IW_EV_UINT_PK_LEN,	/* IW_HEADER_TYPE_UINT */
+	IW_EV_FREQ_PK_LEN,	/* IW_HEADER_TYPE_FREQ */
+	IW_EV_ADDR_PK_LEN,	/* IW_HEADER_TYPE_ADDR */
+	0,
+	IW_EV_POINT_PK_LEN,	/* Without variable payload */
+	IW_EV_PARAM_PK_LEN,	/* IW_HEADER_TYPE_PARAM */
+	IW_EV_QUAL_PK_LEN,	/* IW_HEADER_TYPE_QUAL */
+};
+
+/*------------------------------------------------------------------*/
+/*
+ * Initialise the struct stream_descr so that we can extract
+ * individual events from the event stream.
+ */
+void
+iw_init_event_stream(struct stream_descr *	stream,	/* Stream of events */
+		     char *			data,
+		     int			len)
+{
+  /* Cleanup */
+  memset((char *) stream, '\0', sizeof(struct stream_descr));
+
+  /* Set things up */
+  stream->current = data;
+  stream->end = data + len;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Extract the next event from the event stream.
+ */
+int
+iw_extract_event_stream(struct stream_descr *	stream,	/* Stream of events */
+			struct iw_event *	iwe,	/* Extracted event */
+			int			we_version)
+{
+  const struct iw_ioctl_description *	descr = NULL;
+  int		event_type = 0;
+  unsigned int	event_len = 1;		/* Invalid */
+  char *	pointer;
+  /* Don't "optimise" the following variable, it will crash */
+  unsigned	cmd_index;		/* *MUST* be unsigned */
+
+  /* Check for end of stream */
+  if((stream->current + IW_EV_LCP_PK_LEN) > stream->end)
+    return(0);
+
+#ifdef DEBUG
+  printf("DBG - stream->current = %p, stream->value = %p, stream->end = %p\n",
+	 stream->current, stream->value, stream->end);
+#endif
+
+  /* Extract the event header (to get the event id).
+   * Note : the event may be unaligned, therefore copy... */
+  memcpy((char *) iwe, stream->current, IW_EV_LCP_PK_LEN);
+
+#ifdef DEBUG
+  printf("DBG - iwe->cmd = 0x%X, iwe->len = %d\n",
+	 iwe->cmd, iwe->len);
+#endif
+
+  /* Check invalid events */
+  if(iwe->len <= IW_EV_LCP_PK_LEN)
+    return(-1);
+
+  /* Get the type and length of that event */
+  if(iwe->cmd <= SIOCIWLAST)
+    {
+      cmd_index = iwe->cmd - SIOCIWFIRST;
+      if(cmd_index < standard_ioctl_num)
+	descr = &(standard_ioctl_descr[cmd_index]);
+    }
+  else
+    {
+      cmd_index = iwe->cmd - IWEVFIRST;
+      if(cmd_index < standard_event_num)
+	descr = &(standard_event_descr[cmd_index]);
+    }
+  if(descr != NULL)
+    event_type = descr->header_type;
+  /* Unknown events -> event_type=0 => IW_EV_LCP_PK_LEN */
+  event_len = event_type_size[event_type];
+  /* Fixup for earlier version of WE */
+  if((we_version <= 18) && (event_type == IW_HEADER_TYPE_POINT))
+    event_len += IW_EV_POINT_OFF;
+
+  /* Check if we know about this event */
+  if(event_len <= IW_EV_LCP_PK_LEN)
+    {
+      /* Skip to next event */
+      stream->current += iwe->len;
+      return(2);
+    }
+  event_len -= IW_EV_LCP_PK_LEN;
+
+  /* Set pointer on data */
+  if(stream->value != NULL)
+    pointer = stream->value;			/* Next value in event */
+  else
+    pointer = stream->current + IW_EV_LCP_PK_LEN;	/* First value in event */
+
+#ifdef DEBUG
+  printf("DBG - event_type = %d, event_len = %d, pointer = %p\n",
+	 event_type, event_len, pointer);
+#endif
+
+  /* Copy the rest of the event (at least, fixed part) */
+  if((pointer + event_len) > stream->end)
+    {
+      /* Go to next event */
+      stream->current += iwe->len;
+      return(-2);
+    }
+  /* Fixup for WE-19 and later : pointer no longer in the stream */
+  /* Beware of alignement. Dest has local alignement, not packed */
+  if((we_version > 18) && (event_type == IW_HEADER_TYPE_POINT))
+    memcpy((char *) iwe + IW_EV_LCP_LEN + IW_EV_POINT_OFF,
+	   pointer, event_len);
+  else
+    memcpy((char *) iwe + IW_EV_LCP_LEN, pointer, event_len);
+
+  /* Skip event in the stream */
+  pointer += event_len;
+
+  /* Special processing for iw_point events */
+  if(event_type == IW_HEADER_TYPE_POINT)
+    {
+      /* Check the length of the payload */
+      unsigned int	extra_len = iwe->len - (event_len + IW_EV_LCP_PK_LEN);
+      if(extra_len > 0)
+	{
+	  /* Set pointer on variable part (warning : non aligned) */
+	  iwe->u.data.pointer = pointer;
+
+	  /* Check that we have a descriptor for the command */
+	  if(descr == NULL)
+	    /* Can't check payload -> unsafe... */
+	    iwe->u.data.pointer = NULL;	/* Discard paylod */
+	  else
+	    {
+	      /* Those checks are actually pretty hard to trigger,
+	       * because of the checks done in the kernel... */
+
+	      unsigned int	token_len = iwe->u.data.length * descr->token_size;
+
+	      /* Ugly fixup for alignement issues.
+	       * If the kernel is 64 bits and userspace 32 bits,
+	       * we have an extra 4+4 bytes.
+	       * Fixing that in the kernel would break 64 bits userspace. */
+	      if((token_len != extra_len) && (extra_len >= 4))
+		{
+		  union iw_align_u16	alt_dlen;
+		  unsigned int		alt_token_len;
+		  /* Usespace seems to not always like unaligned access,
+		   * so be careful and make sure to align value.
+		   * I hope gcc won't play any of its aliasing tricks... */
+		  alt_dlen.byte[0] = *(pointer);
+		  alt_dlen.byte[1] = *(pointer + 1);
+		  alt_token_len = alt_dlen.value * descr->token_size;
+#ifdef DEBUG
+		  printf("DBG - alt_token_len = %d\n", alt_token_len);
+#endif
+		  /* Verify that data is consistent if assuming 64 bit
+		   * alignement... */
+		  if((alt_token_len + 8) == extra_len)
+		    {
+		      /* Ok, let's redo everything */
+		      pointer -= event_len;
+		      pointer += 4;
+		      /* Dest has local alignement, not packed */
+		      memcpy((char *) iwe + IW_EV_LCP_LEN + IW_EV_POINT_OFF,
+			     pointer, event_len);
+		      pointer += event_len + 4;
+		      token_len = alt_token_len;
+		      /* We may have no payload */
+		      if(alt_token_len)
+			iwe->u.data.pointer = pointer;
+		      else
+			iwe->u.data.pointer = NULL;
+		    }
+		}
+
+	      /* Discard bogus events which advertise more tokens than
+	       * what they carry... */
+	      if(token_len > extra_len)
+		iwe->u.data.pointer = NULL;	/* Discard paylod */
+	      /* Check that the advertised token size is not going to
+	       * produce buffer overflow to our caller... */
+	      if((iwe->u.data.length > descr->max_tokens)
+		 && !(descr->flags & IW_DESCR_FLAG_NOMAX))
+		iwe->u.data.pointer = NULL;	/* Discard paylod */
+	      /* Same for underflows... */
+	      if(iwe->u.data.length < descr->min_tokens)
+		iwe->u.data.pointer = NULL;	/* Discard paylod */
+#ifdef DEBUG
+	      printf("DBG - extra_len = %d, token_len = %d, token = %d, max = %d, min = %d\n",
+		     extra_len, token_len, iwe->u.data.length, descr->max_tokens, descr->min_tokens);
+#endif
+	    }
+	}
+      else
+	/* No data */
+	iwe->u.data.pointer = NULL;
+
+      /* Go to next event */
+      stream->current += iwe->len;
+    }
+  else
+    {
+      /* Ugly fixup for alignement issues.
+       * If the kernel is 64 bits and userspace 32 bits,
+       * we have an extra 4 bytes.
+       * Fixing that in the kernel would break 64 bits userspace. */
+      if((stream->value == NULL)
+	 && ((((iwe->len - IW_EV_LCP_PK_LEN) % event_len) == 4)
+	     || ((iwe->len == 12) && ((event_type == IW_HEADER_TYPE_UINT) ||
+				      (event_type == IW_HEADER_TYPE_QUAL))) ))
+	{
+#ifdef DEBUG
+	  printf("DBG - alt iwe->len = %d\n", iwe->len - 4);
+#endif
+	  pointer -= event_len;
+	  pointer += 4;
+	  /* Beware of alignement. Dest has local alignement, not packed */
+	  memcpy((char *) iwe + IW_EV_LCP_LEN, pointer, event_len);
+	  pointer += event_len;
+	}
+
+      /* Is there more value in the event ? */
+      if((pointer + event_len) <= (stream->current + iwe->len))
+	/* Go to next value */
+	stream->value = pointer;
+      else
+	{
+	  /* Go to next event */
+	  stream->value = NULL;
+	  stream->current += iwe->len;
+	}
+    }
+  return(1);
+}
+
+/*********************** SCANNING SUBROUTINES ***********************/
+/*
+ * The Wireless Extension API 14 and greater define Wireless Scanning.
+ * The normal API is complex, this is an easy API that return
+ * a subset of the scanning results. This should be enough for most
+ * applications that want to use Scanning.
+ * If you want to have use the full/normal API, check iwlist.c...
+ *
+ * Precaution when using scanning :
+ * The scanning operation disable normal network traffic, and therefore
+ * you should not abuse of scan.
+ * The scan need to check the presence of network on other frequencies.
+ * While you are checking those other frequencies, you can *NOT* be on
+ * your normal frequency to listen to normal traffic in the cell.
+ * You need typically in the order of one second to actively probe all
+ * 802.11b channels (do the maths). Some cards may do that in background,
+ * to reply to scan commands faster, but they still have to do it.
+ * Leaving the cell for such an extended period of time is pretty bad.
+ * Any kind of streaming/low latency traffic will be impacted, and the
+ * user will perceive it (easily checked with telnet). People trying to
+ * send traffic to you will retry packets and waste bandwidth. Some
+ * applications may be sensitive to those packet losses in weird ways,
+ * and tracing those weird behavior back to scanning may take time.
+ * If you are in ad-hoc mode, if two nodes scan approx at the same
+ * time, they won't see each other, which may create associations issues.
+ * For those reasons, the scanning activity should be limited to
+ * what's really needed, and continuous scanning is a bad idea.
+ * Jean II
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Process/store one element from the scanning results in wireless_scan
+ */
+static inline struct wireless_scan *
+iw_process_scanning_token(struct iw_event *		event,
+			  struct wireless_scan *	wscan)
+{
+  struct wireless_scan *	oldwscan;
+
+  /* Now, let's decode the event */
+  switch(event->cmd)
+    {
+    case SIOCGIWAP:
+      /* New cell description. Allocate new cell descriptor, zero it. */
+      oldwscan = wscan;
+      wscan = (struct wireless_scan *) malloc(sizeof(struct wireless_scan));
+      if(wscan == NULL)
+	return(wscan);
+      /* Link at the end of the list */
+      if(oldwscan != NULL)
+	oldwscan->next = wscan;
+
+      /* Reset it */
+      bzero(wscan, sizeof(struct wireless_scan));
+
+      /* Save cell identifier */
+      wscan->has_ap_addr = 1;
+      memcpy(&(wscan->ap_addr), &(event->u.ap_addr), sizeof (sockaddr));
+      break;
+    case SIOCGIWNWID:
+      wscan->b.has_nwid = 1;
+      memcpy(&(wscan->b.nwid), &(event->u.nwid), sizeof(iwparam));
+      break;
+    case SIOCGIWFREQ:
+      wscan->b.has_freq = 1;
+      wscan->b.freq = iw_freq2float(&(event->u.freq));
+      wscan->b.freq_flags = event->u.freq.flags;
+      break;
+    case SIOCGIWMODE:
+      wscan->b.mode = event->u.mode;
+      if((wscan->b.mode < IW_NUM_OPER_MODE) && (wscan->b.mode >= 0))
+	wscan->b.has_mode = 1;
+      break;
+    case SIOCGIWESSID:
+      wscan->b.has_essid = 1;
+      wscan->b.essid_on = event->u.data.flags;
+      memset(wscan->b.essid, '\0', IW_ESSID_MAX_SIZE + 1);
+      if((event->u.essid.pointer) && (event->u.essid.length))
+	memcpy(wscan->b.essid, event->u.essid.pointer, event->u.essid.length);
+      break;
+    case SIOCGIWENCODE:
+      wscan->b.has_key = 1;
+      wscan->b.key_size = event->u.data.length;
+      wscan->b.key_flags = event->u.data.flags;
+      if(event->u.data.pointer)
+	memcpy(wscan->b.key, event->u.essid.pointer, event->u.data.length);
+      else
+	wscan->b.key_flags |= IW_ENCODE_NOKEY;
+      break;
+    case IWEVQUAL:
+      /* We don't get complete stats, only qual */
+      wscan->has_stats = 1;
+      memcpy(&wscan->stats.qual, &event->u.qual, sizeof(struct iw_quality));
+      break;
+    case SIOCGIWRATE:
+      /* Scan may return a list of bitrates. As we have space for only
+       * a single bitrate, we only keep the largest one. */
+      if((!wscan->has_maxbitrate) ||
+	 (event->u.bitrate.value > wscan->maxbitrate.value))
+	{
+	  wscan->has_maxbitrate = 1;
+	  memcpy(&(wscan->maxbitrate), &(event->u.bitrate), sizeof(iwparam));
+	}
+    case IWEVCUSTOM:
+      /* How can we deal with those sanely ? Jean II */
+    default:
+      break;
+   }	/* switch(event->cmd) */
+
+  return(wscan);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Initiate the scan procedure, and process results.
+ * This is a non-blocking procedure and it will return each time
+ * it would block, returning the amount of time the caller should wait
+ * before calling again.
+ * Return -1 for error, delay to wait for (in ms), or 0 for success.
+ * Error code is in errno
+ */
+int
+iw_process_scan(int			skfd,
+		char *			ifname,
+		int			we_version,
+		wireless_scan_head *	context)
+{
+  struct iwreq		wrq;
+  unsigned char *	buffer = NULL;		/* Results */
+  int			buflen = IW_SCAN_MAX_DATA; /* Min for compat WE<17 */
+  unsigned char *	newbuf;
+
+  /* Don't waste too much time on interfaces (150 * 100 = 15s) */
+  context->retry++;
+  if(context->retry > 150)
+    {
+      errno = ETIME;
+      return(-1);
+    }
+
+  /* If we have not yet initiated scanning on the interface */
+  if(context->retry == 1)
+    {
+      /* Initiate Scan */
+      wrq.u.data.pointer = NULL;		/* Later */
+      wrq.u.data.flags = 0;
+      wrq.u.data.length = 0;
+      /* Remember that as non-root, we will get an EPERM here */
+      if((iw_set_ext(skfd, ifname, SIOCSIWSCAN, &wrq) < 0)
+	 && (errno != EPERM))
+	return(-1);
+      /* Success : now, just wait for event or results */
+      return(250);	/* Wait 250 ms */
+    }
+
+ realloc:
+  /* (Re)allocate the buffer - realloc(NULL, len) == malloc(len) */
+  newbuf = realloc(buffer, buflen);
+  if(newbuf == NULL)
+    {
+      /* man says : If realloc() fails the original block is left untouched */
+      if(buffer)
+	free(buffer);
+      errno = ENOMEM;
+      return(-1);
+    }
+  buffer = newbuf;
+
+  /* Try to read the results */
+  wrq.u.data.pointer = buffer;
+  wrq.u.data.flags = 0;
+  wrq.u.data.length = buflen;
+  if(iw_get_ext(skfd, ifname, SIOCGIWSCAN, &wrq) < 0)
+    {
+      /* Check if buffer was too small (WE-17 only) */
+      if((errno == E2BIG) && (we_version > 16) && (buflen < 0xFFFF))
+	{
+	  /* Some driver may return very large scan results, either
+	   * because there are many cells, or because they have many
+	   * large elements in cells (like IWEVCUSTOM). Most will
+	   * only need the regular sized buffer. We now use a dynamic
+	   * allocation of the buffer to satisfy everybody. Of course,
+	   * as we don't know in advance the size of the array, we try
+	   * various increasing sizes. Jean II */
+
+	  /* Check if the driver gave us any hints. */
+	  if(wrq.u.data.length > buflen)
+	    buflen = wrq.u.data.length;
+	  else
+	    buflen *= 2;
+
+	  /* wrq.u.data.length is 16 bits so max size is 65535 */
+	  if(buflen > 0xFFFF)
+	    buflen = 0xFFFF;
+
+	  /* Try again */
+	  goto realloc;
+	}
+
+      /* Check if results not available yet */
+      if(errno == EAGAIN)
+	{
+	  free(buffer);
+	  /* Wait for only 100ms from now on */
+	  return(100);	/* Wait 100 ms */
+	}
+
+      free(buffer);
+      /* Bad error, please don't come back... */
+      return(-1);
+    }
+
+  /* We have the results, process them */
+  if(wrq.u.data.length)
+    {
+      struct iw_event		iwe;
+      struct stream_descr	stream;
+      struct wireless_scan *	wscan = NULL;
+      int			ret;
+#ifdef DEBUG
+      /* Debugging code. In theory useless, because it's debugged ;-) */
+      int	i;
+      printf("Scan result [%02X", buffer[0]);
+      for(i = 1; i < wrq.u.data.length; i++)
+	printf(":%02X", buffer[i]);
+      printf("]\n");
+#endif
+
+      /* Init */
+      iw_init_event_stream(&stream, (char *) buffer, wrq.u.data.length);
+      /* This is dangerous, we may leak user data... */
+      context->result = NULL;
+
+      /* Look every token */
+      do
+	{
+	  /* Extract an event and print it */
+	  ret = iw_extract_event_stream(&stream, &iwe, we_version);
+	  if(ret > 0)
+	    {
+	      /* Convert to wireless_scan struct */
+	      wscan = iw_process_scanning_token(&iwe, wscan);
+	      /* Check problems */
+	      if(wscan == NULL)
+		{
+		  free(buffer);
+		  errno = ENOMEM;
+		  return(-1);
+		}
+	      /* Save head of list */
+	      if(context->result == NULL)
+		context->result = wscan;
+	    }
+	}
+      while(ret > 0);
+    }
+
+  /* Done with this interface - return success */
+  free(buffer);
+  return(0);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Perform a wireless scan on the specified interface.
+ * This is a blocking procedure and it will when the scan is completed
+ * or when an error occur.
+ *
+ * The scan results are given in a linked list of wireless_scan objects.
+ * The caller *must* free the result himself (by walking the list).
+ * If there is an error, -1 is returned and the error code is available
+ * in errno.
+ *
+ * The parameter we_version can be extracted from the range structure
+ * (range.we_version_compiled - see iw_get_range_info()), or using
+ * iw_get_kernel_we_version(). For performance reason, you should
+ * cache this parameter when possible rather than querying it every time.
+ *
+ * Return -1 for error and 0 for success.
+ */
+int
+iw_scan(int			skfd,
+	char *			ifname,
+	int			we_version,
+	wireless_scan_head *	context)
+{
+  int		delay;		/* in ms */
+
+  /* Clean up context. Potential memory leak if(context.result != NULL) */
+  context->result = NULL;
+  context->retry = 0;
+
+  /* Wait until we get results or error */
+  while(1)
+    {
+      /* Try to get scan results */
+      delay = iw_process_scan(skfd, ifname, we_version, context);
+
+      /* Check termination */
+      if(delay <= 0)
+	break;
+
+      /* Wait a bit */
+      usleep(delay * 1000);
+    }
+
+  /* End - return -1 or 0 */
+  return(delay);
+}
Index: create-30-cross-patch/wireless-tools-30-new
===================================================================
--- create-30-cross-patch/wireless-tools-30-new	(nonexistent)
+++ create-30-cross-patch/wireless-tools-30-new	(revision 5)

Property changes on: create-30-cross-patch/wireless-tools-30-new
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: create-30-cross-patch
===================================================================
--- create-30-cross-patch	(nonexistent)
+++ create-30-cross-patch	(revision 5)

Property changes on: create-30-cross-patch
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: patches/README
===================================================================
--- patches/README	(nonexistent)
+++ patches/README	(revision 5)
@@ -0,0 +1,6 @@
+
+/* begin *
+
+   TODO: Leave some comment here.
+
+ * end */
Index: patches
===================================================================
--- patches	(nonexistent)
+++ patches	(revision 5)

Property changes on: patches
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: .
===================================================================
--- .	(nonexistent)
+++ .	(revision 5)

Property changes on: .
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~