OSDN Git Service

v25
authorchris-kirby <chris.kirby@hpe.com>
Tue, 11 Oct 2016 21:05:29 +0000 (15:05 -0600)
committerchris-kirby <chris.kirby@hpe.com>
Tue, 11 Oct 2016 21:05:29 +0000 (15:05 -0600)
27 files changed:
wireless_tools/CHANGELOG.h
wireless_tools/DISTRIBUTIONS.txt [new file with mode: 0644]
wireless_tools/INSTALL
wireless_tools/Makefile
wireless_tools/PCMCIA.txt
wireless_tools/README
wireless_tools/iwconfig.8
wireless_tools/iwconfig.c
wireless_tools/iwevent.8
wireless_tools/iwevent.c
wireless_tools/iwgetid.8
wireless_tools/iwgetid.c
wireless_tools/iwlib.c
wireless_tools/iwlib.h
wireless_tools/iwlist.8
wireless_tools/iwlist.c
wireless_tools/iwpriv.8
wireless_tools/iwpriv.c
wireless_tools/iwspy.8
wireless_tools/iwspy.c
wireless_tools/sample_enc.c [new file with mode: 0644]
wireless_tools/sample_enc_cs.c [deleted file]
wireless_tools/sample_pm.c [new file with mode: 0644]
wireless_tools/sample_pm_cs.c [deleted file]
wireless_tools/sample_priv_addr.c [new file with mode: 0644]
wireless_tools/wireless.15.h [new file with mode: 0644]
wireless_tools/wireless.7 [new file with mode: 0644]

index cffb6b2..b1944a0 100644 (file)
@@ -91,7 +91,7 @@
  *     o Use proper macros for compilation directives [Makefile]
  *             (From Jean Tourrilhes)
  *     o Put licensing info everywhere (almost). Yes, it's GPL !
  *     o Use proper macros for compilation directives [Makefile]
  *             (From Jean Tourrilhes)
  *     o Put licensing info everywhere (almost). Yes, it's GPL !
- *     o Document the use of /etc/pcmcia/wireless.opts
+ *     o Document the use of /etc/pcmcia/wireless.opts [PCMCIA]
  *     o Add min/max modifiers to power management parameters [iwconfig]
  *             -> requested by Lee Keyser-Allen for the Spectrum24 driver
  *     o Optionally output a second power management parameter [iwconfig]
  *     o Add min/max modifiers to power management parameters [iwconfig]
  *             -> requested by Lee Keyser-Allen for the Spectrum24 driver
  *     o Optionally output a second power management parameter [iwconfig]
  *     o Always send TxPower flags to the driver [iwconfig]
  *             (From John M. Choi <johnchoi@its.caltech.edu>)
  *     o Header definition for Slackware (kernel 2.2/glibc 2.2) [iwlib]
  *     o Always send TxPower flags to the driver [iwconfig]
  *             (From John M. Choi <johnchoi@its.caltech.edu>)
  *     o Header definition for Slackware (kernel 2.2/glibc 2.2) [iwlib]
+ *
+ * wireless 25 :
+ * -----------
+ *     o Remove library symbolic link before creating it [Makefile]
+ *     o Display error and exit if WE < 14 [iwevent]
+ *             (From Sander Jonkers <sander@grachtzicht.cjb.net>)
+ *     o Fix iwconfig usage display to show "enc off" [iwconfig]
+ *             (From Pavel Roskin <proski@gnu.org>)
+ *     o Formating : add spaces after cell/ap addr [iwconfig]
+ *     ---
+ *     o Do driver WE source version verification [iwlib]
+ *             (From Pavel Roskin <proski@gnu.org>)
+ *     o Cleanup user configurable options [Makefile]
+ *     o add FORCE_WEXT_VERSION [Makefile]
+ *     o Add uninstall directived [Makefile]
+ *     o Cleanup version warnings [iwlib]
+ *     o Fix iwconfig usage display to show "mode MODE" [iwconfig]
+ *     o Replace "rm -f + ln -s" with "ln -sfn" in install [Makefile]
+ *     ---
+ *     o Add various documentation in source code of [iwpriv]
+ *     o Allow to get more than 16 private ioctl description [iwlib]
+ *     o Ignore ioctl descriptions with null name [iwpriv]
+ *     o Implement sub-ioctls (simple/iw_point) [iwpriv]
+ *     ---
+ *     o Add DISTRIBUTIONS file with call for help [README]
+ *     o Change iw_byte_size in iw_get_priv_size [iwlib]
+ *     o Document various bugs of new driver API with priv ioctls [iwpriv]
+ *     o Implement float/addr priv data types [iwpriv]
+ *     o Fix off-by-one bug (priv_size <= IFNAMSIZ) [iwpriv]
+ *     o Reformat/beautify ioctl list display [iwpriv]
+ *     o Add "-a" command line to dump all read-only priv ioctls [iwpriv]
+ *     o Add a sample showing new priv features [sample_priv_addr.c]
+ *     o Update other samples with new driver API [sample_enc.c/sample_pm.c]
+ *     ---
+ *     o Fix "iwpriv -a" to not call ioctls not returning anything [iwpriv]
+ *     o Use IW_MAX_GET_SPY in increase number of addresses read [iwspy]
+ *     o Finish fixing the mess of off-by-one on IW_ESSID_MAX_SIZE [iwconfig]
+ *     o Do interface enumeration using /proc/net/dev [iwlib]
+ *     ---
+ *     o Display various --version information [iwlib, iwconfig, iwlist]
+ *     o Filled in Debian 2.3 & Red-Hat 7.3 sections in [DISTRIBUTIONS]
+ *     o Filled in Red-Hat 7.2, Mandrake 8.2 and SuSE 8.0 in [DISTRIBUTIONS]
+ *     o Display current freq/channel after the iwrange list [iwlist]
+ *     o Display current rate after the iwrange list [iwlist]
+ *     o Display current txpower after the iwrange list [iwlist]
+ *     o Add BUILD_NOLIBM to build without libm [Makefile]
+ *     o Fix infinite loop on unknown events/scan elements [iwlib]
+ *     o Add IWEVCUSTOM support [iwevent, iwlist]
+ *     o Add IWEVREGISTERED & IWEVEXPIRED support [iwevent]
+ *             (From Pavel Roskin <proski@gnu.org>)
+ *     o Make $(DYNAMIC_LINK) relative (and not absolute) [Makefile]
+ *     ---
+ *     o Replace all float occurence with double [iwlib, iwlist]
+ *     o Implement iwgetid --mode [iwgetid]
+ *     o Convert frequency to channel [iwlist, iwlib]
+ *             (Suggested by Pavel Roskin <proski@gnu.org> - always him !)
+ *     o Implement --version across the board [iwspy, iwevent, iwpriv]
+ *     o Implement iwgetid --freq [iwgetid]
+ *     o Display "Access Point/Cell" [iwgetid]
+ *     ---
+ *     o New manpage about configuration (placeholder) [wireless.7]
+ *     o Catch properly invalid arg to "iwconfig ethX key" [iwconfig]
+ *     o Put placeholder for Passphrase to key conversion [iwlib]
+ *     o Allow args of "iwconfig ethX key" in any order [iwconfig]
+ *     o Implement token index for private commands [iwpriv]
+ *     o Add IW_MODE_MONITOR for passive monitoring [iwlib]
+ *             I wonder why nobody bothered to ask for it before ;-)
+ *     o Mention distribution specific document in [PCMCIA]
+ *     o Create directories before installing stuff in it [Makefile]
+ *     ---
+ *     o Add Debian 3.0 and PCMCIA in [wireless.7]
+ *     o Add iw_protocol_compare() in [iwlib]
+ *     ---
+ *     o Complain about version mistmatch at runtime only once [iwlib]
+ *     o Fix IWNAME null termination [iwconfig, iwlib]
+ *     o "iwgetid -p" to display protocol name and check WE support [iwgetid]
  */
 
 /* ----------------------------- TODO ----------------------------- */
  */
 
 /* ----------------------------- TODO ----------------------------- */
diff --git a/wireless_tools/DISTRIBUTIONS.txt b/wireless_tools/DISTRIBUTIONS.txt
new file mode 100644 (file)
index 0000000..c6fb878
--- /dev/null
@@ -0,0 +1,282 @@
+       Distribution specific notes on Wireless Configuration
+       -----------------------------------------------------
+
+***** HELP *****
+       If people send me information about the specifics of each
+distribution, I'll try to collect that here. Don't forget to mention
+to which distribution those instructions apply, the tool used (if any)
+and the files modified.
+       Actually, the people packaging my tools for a specific
+distribution have a moral obligation to send me the exact detailed
+instructions of what they have done. I will list in the wireless.7
+man page only distributions that give me an official answer.
+***** HELP *****
+
+                               -----
+
+INTRODUCTION
+------------
+       The tools enable users to change the card settings at run time
+(when running iwconfig, for example). However, most users want the
+card to be configured either at boot time or when the card is
+activated in the system.
+       Each distribution has its own configuration scripts, and
+therefore is slightly different. Some distributions even add some
+graphical setup tool (nice). This file describe the procedure for a
+few of them.
+       Note : if you install the Pcmcia package in source form from
+the official Linux-Pcmcia web site (as opposed to precompiled by a
+distribution, please use the PCMCIA method).
+
+       Please remember : I don't use your distribution, and I have
+absolutely no clue about how your distribution works. I'm just
+collecting random information here without beeing able to verify it.
+
+---------------------------------------------------------------------
+
+PCMCIA METHOD
+-------------
+               (Contributed by Jean Tourrilhes <jt@hpl.hp.com>)
+       This method work for *all* distributions.
+       For Pcmcia cards, it is possible to overwrite the Pcmcia
+configuration files of the distribution with the original Pcmcia
+configuration files from the Pcmcia package (/etc/pcmcia/*). If you
+install the Pcmcia package in source form from the official
+Linux-Pcmcia web site, this will be done automatically.
+       Once this is done, you can no longer use the specific tools
+and configuration files of the distribution, and are required to use
+Pcmcia style of configuration (see Pcmcia Howto).
+       In such a case, Wireless configuration is done through
+wireless.opts, and documented in the file PCMCIA.txt.
+
+---------------------------------------------------------------------
+
+DEBIAN 2.2 (and earlier)
+----------
+               (Contributed by Jean Tourrilhes <jt@hpl.hp.com>)
+       Debian 2.2 (and earlier) doesn't support any Wireless
+Configuration. You are required to use the Pcmcia method. Also, the
+Wireless Tools package is not part of the standard packages.
+
+---------------------------------------------------------------------
+
+DEBIAN 3.0 (and later)
+----------
+               (Contributed by Guus Sliepen <guus@sliepen.eu.org>)
+       Debian also has another way of configuring network devices,
+controlled by /etc/network/interfaces. Users can add a wireless
+interface to /etc/network/interfaces, using the standard options to
+set the address and such, but the wireless-tools package adds new
+option statements that can be used to configure keys, channel,
+etcetera.
+       From the README.Debian script that comes with wireless-tools:
+
+       /etc/network/interfaces
+       -----------------------
+
+You can now add extra statements to the iface sections of the files in
+/etc/network/interfaces that are specific for wireless interfaces. They
+are of the form:
+
+    wireless_<function> <value>
+
+Before the interface is brought up, such a statement will result in the
+execution of the following command:
+
+    iwconfig <interface> <function> <value>
+
+Example:
+
+iface eth0 inet static
+    address 192.168.1.2
+    network 192.168.1.0
+    netmask 255.255.255.0
+    broadcast 192.168.1.255
+    wireless_essid Home
+    wireless_mode ad_hoc
+
+       The current Debian script support all arguments present in
+wireless.opts apart from Nickname. You can check this in the script
+/etc/network/if-pre-up.d/wireless-tool.
+       You will need of course to install the Wireless Tools package
+if it's not already done, which is part of the standard package list
+(use dselect, dpkg, apt or anything you like to get it).
+
+                               -----
+
+               (Contributed by Joey Hess <joey@dragon.kitenet.net>)
+/etc/network/interfaces is much more flexible than it appears. It can probably
+do everything pcmcia schemes can do, and more. Here is part of mine:
+
+auto wlan0
+mapping wlan0
+        script /usr/local/bin/ifscheme
+
+iface wlan0-home inet static
+        address 192.168.1.5
+        gateway 192.168.1.1
+        netmask 255.255.255.0
+        wireless_mode ad_hoc
+        wireless_essid wortroot
+        wireless_nick dragon
+        wireless_channel 1
+
+iface wlan0-away inet dhcp
+        wireless_mode managed
+
+Now I can type 'ifscheme -s away' when I leave home, rather like
+cardctl scheme.
+
+The ifscheme script is at http://bugs.debian.org/154444. If the request in
+bug #154442 is implemented, it will become very flexible indeed..
+
+Debian will hopefully be using this same file eventually for pcmcia network
+devices too. It's already doable but takes a little work. This is all rather
+rough and badly documented so far.
+
+You can also do mapping based on the MAC address, if you want specific
+configuration on specific card.  See
+/usr/share/doc/ifupdown/examples/get-mac-address.sh and the stanza in
+/usr/share/doc/ifupdown/examples/network-interfaces.gz that uses it.
+This comes back to the problem I alluded to with mapping scripts not
+being "nestable" yet, and bug #154442. You can do what you want today,
+but you may need to write your own mapping script which uses a
+combination of MAC address and scheme info to return a stanza name to
+ifupdown.
+
+---------------------------------------------------------------------
+
+RED-HAT 7.2
+-----------
+               (Grabbed from various source - Google is your friend)
+       Configuration is done in the file :
+               /etc/sysconfig/network-scripts/ifcfg-ethN
+       Where 'ethN' is the name of the wireless interface (such as
+eth0, eth1, ...).
+       The following lines may be added in this file :
+               MODE=<mode>
+               ESSID="<essid>"
+               RATE=<rate>
+               TXPOWER=<txpower>
+               KEY="<key>"
+       The full list of configuration can be found in the file :
+               /etc/sysconfig/network-scripts/ifup-wireless
+
+       Note that Brad Allison has other tips for 7.2 :
+       http://jackal.dnsalias.com:8080/public/misc/wireless/wireless.html
+
+---------------------------------------------------------------------
+
+RED-HAT 7.3 and later
+-----------
+               (Cut'n'pasted from Brad Allison web page)
+       http://jackal.dnsalias.com:8080/public/misc/wireless/wireless.html
+
+       If you are running RedHat 7.3, I would tell you to simply run
+/usr/bin/redhat-config-network and click "Devices", Click "Add", then
+select "Wireless Connection". You can find the full instructions in
+RedHat's Customization Guide for RH7.3 in Chapter 6, Network
+Configuration: Wireless Connection.
+               http://www.redhat.com/docs/manuals/linux/
+               http://www.redhat.com/docs/manuals/linux/RHL-7.3-Manual/custom-guide/s1-network-config-wireless.html
+
+       However, according to the Errata: The version of the Red Hat
+Network Administration Tool that shipped with Red Hat Linux 7.3 did
+not include wireless connection in the configuration wizard. An
+enhancement errata will be released soon with this feature. You can
+download the newest version of redhat-config-network from rpmfind.net.
+               http://www.redhat.com/docs/errata/RHL-7.3-Manual/
+               http://www.rpmfind.net/linux/rpm2html/search.php?query=redhat-config-network&submit=Search+...
+
+                               -----
+
+               (Grabbed from various source - Google is your friend)
+       The current graphical user interface support :
+               ESSID, Mode, Freq, Channel, Rate, Key
+
+       Compared to Red-Hat 7.2, the Wireless Setting in the
+configuration file have change to include the WIRELESS_ prefix :
+               WIRELESS_MODE=<mode>
+               WIRELESS_ESSID='<essid>'
+               WIRELESS_ENC_KEY='<key>'
+       The underlying configuration files and configurations options
+seems to be indentical to what is done in Mandrake 8.2 (or vice
+versa), so please check the section below. This allow configuration of
+additional wireless settings not available in the GUI.
+
+                               -----
+
+               (Extrapolated from web page of Martin Pot <m.t.pot@ieee.org>)
+               http://ii.net/~mpot/wireless/router.cgi
+       Red-Hat 7.3 also seem to support configuration in
+wireless.opts to some extent. But for compatibility with the network
+admin tools, I would still recommend to use the above method.
+       Red-Hat 7.3 seems to load wvlan_cs for Orinoco cards and
+friends. The above web page explain how to switch it to orinoco_cs.
+
+---------------------------------------------------------------------
+
+MANDRAKE 8.2 and later
+------------
+               (Grabbed from various source - Google is your friend)
+       Configuration is done in the file :
+               /etc/sysconfig/network-scripts/ifcfg-ethN
+       Where 'ethN' is the name of the wireless interface (such as
+eth0, eth1, ...).
+       The following lines may be added in this file :
+               WIRELESS_MODE=<mode>
+               WIRELESS_ESSID=<essid>
+               WIRELESS_NWID=<nwid>
+               WIRELESS_FREQ=<freq/channel>
+               WIRELESS_SENS=<sensitivity>
+               WIRELESS_RATE=<rate>
+               WIRELESS_ENC_KEY=<keys>
+               WIRELESS_RTS=<rts>
+               WIRELESS_FRAG=<frag>
+               WIRELESS_IWCONFIG=<iwconfig command>
+               WIRELESS_IWSPY=<iwspy command>
+               WIRELESS_IWPRIV=<iwpriv command>
+       Most likely, you only need to add a few of those lines and not
+all of them. The script doing the configuration and where you can
+check the details is :
+               /etc/network/network-scripts/ifup-wireless
+       You will of course need the Wireless Extension package :
+               rpm -Uvh wireless-tools-XX-Xmdk.XXX.rpm
+
+       Mandrake can also have wireless setting added to its
+Auto-Install procedure :
+       http://members.shaw.ca/mandrake/drakx/8.2/HTML/section4-13.html
+
+---------------------------------------------------------------------
+
+SuSE 8.0 and later
+--------
+               (Cut'n'pasted from Unofficial SuSE FAQ, by Keith Winston)
+       http://www.smaug42.com/susefaq/ethernetproblems.html#AEN768
+       The old PCMCIA network scripts used to read
+/etc/pcmcia/wireless.opts to get the wireless options like mode,
+ESSID, encryption key, etc. Well, the wireless.opts file is still
+there but it is NOT used. It would have been nice if there was some
+documentation about it. Instead, the new scripts read this info from
+another brand new file called /etc/sysconfig/network/wireless. You can
+edit this file to store your wireless options. If you don't use key 1,
+you may have to put the other key in the WIRELESS_IWCONFIG_OPTIONS
+variable.
+
+                               -----
+
+               <Need confirmation :>
+       Configuration of wireless settings looks like :
+               WIRELESS_ESSID="<essid>"
+       It also seem that the same directives can be added to the file :
+               /etc/sysconfig/network/ifcfg-ethX
+       Note that there seems to be other problems with SuSE, such as
+the Pcmcia scripts binding the linux-wlan-ng driver to Orinoco cards
+(which of course won't work - see link in FAQ above).
+
+---------------------------------------------------------------------
+
+
+       Have fun...
+
+       Jean
index cf2b323..fa39d77 100644 (file)
@@ -21,19 +21,6 @@ You need :
        Note : more recent kernels and drivers are likely to support
                more wireless extension features...
 
        Note : more recent kernels and drivers are likely to support
                more wireless extension features...
 
-Recommended versions :
---------------------
-       This are the latest updates of the Wireless Extensions :
-       o Kernel (wireless extension definition) :
-               -> Kernel 2.2.14 onward
-               -> Kernel 2.3.24 onward
-               -> Kernel 2.4.0 onward
-       o Pcmcia package :
-               -> Pcmcia 3.1.15 onward
-       o Drivers with wireless extension support :
-               -> Check my web pages for latest list of drivers,
-                       otherwise patch your favourite driver...
-
 Compile wireless tools :
 ----------------------
        In theory, a "make" should suffice to create the tools.
 Compile wireless tools :
 ----------------------
        In theory, a "make" should suffice to create the tools.
@@ -46,7 +33,9 @@ tools but to recompile your own.
 Installation :
 ------------
        If I were you, I would not trust a "make install". If you feel
 Installation :
 ------------
        If I were you, I would not trust a "make install". If you feel
-courageous, just do "make install". It may even do the right thing.
+courageous, just do "make install". It may even do the right
+thing. Actually, with the various bugfixes that happened over the
+time, it nowadays tend to do the right thing.
        I advise to copy the executable (iwconfig, iwspy and iwpriv)
 in /usr/local/sbin or /usr/sbin. The man pages (iwconfig.8, iwspy.8
 and iwpriv.8) should be copied in /usr/local/man/man8 or
        I advise to copy the executable (iwconfig, iwspy and iwpriv)
 in /usr/local/sbin or /usr/sbin. The man pages (iwconfig.8, iwspy.8
 and iwpriv.8) should be copied in /usr/local/man/man8 or
@@ -72,8 +61,5 @@ the latest Wireless Extensions. Even worse, it can sometimes prevent
 the tools from compiling.
        The trick is to copy the file .../include/linux/wireless.h
 from the kernel to the /usr/include headers.
 the tools from compiling.
        The trick is to copy the file .../include/linux/wireless.h
 from the kernel to the /usr/include headers.
-       A similar procedure may be used to update Wireless Extensions
-in an older kernel, but you may want to be careful because from time
-to time changes are required in the kernel as well...
 
        Jean <jt@hpl.hp.com>
 
        Jean <jt@hpl.hp.com>
index 5de0c9a..7a7dec9 100644 (file)
@@ -1,56 +1,88 @@
-#
-# Basic and crude Makefile...
-#
+##
+## Please check the configurion parameters below
+##
+
+## Installation directory. By default, go in /usr/local
+## Distributions should probably use /usr, but they probably know better...
+PREFIX = /usr/local
+
+## Compiler to use
+CC = gcc
+
+## Uncomment this to build against this kernel
+# KERNEL_SRC = /usr/src/linux
+
+## Uncomment this to force a particular version of wireless extensions.
+## This would use private copy of Wireless Extension definition instead
+## of the system wide one in /usr/include/linux. Use with care.
+## Can be used to create multiple versions of the tools on the same system
+## for multiple kernels or get around broken distributions.
+# FORCE_WEXT_VERSION = 14
+
+## Uncomment this to build tools using dynamic version of the library
+# BUILD_SHARED = y
+
+## Uncomment this to build without using libm (less efficient)
+## This is mostly useful for embedded platforms
+# BUILD_NOLIBM = y
+
+# ***************************************************************************
+# ***** Most users should not need to change anything beyond this point *****
+# ***************************************************************************
 
 # Targets to build
 STATIC=libiw.a
 
 # Targets to build
 STATIC=libiw.a
-DYNAMIC=libiw.so.24
+DYNAMIC=libiw.so.25
 PROGS= iwconfig iwlist iwpriv iwspy iwgetid iwevent
 PROGS= iwconfig iwlist iwpriv iwspy iwgetid iwevent
-MANPAGES=iwconfig.8 iwlist.8 iwpriv.8 iwspy.8 iwgetid.8 iwevent.8
+MANPAGES8=iwconfig.8 iwlist.8 iwpriv.8 iwspy.8 iwgetid.8 iwevent.8
+MANPAGES7=wireless.7
 
 # Composition of the library :
 OBJS = iwlib.o
 
 
 # Composition of the library :
 OBJS = iwlib.o
 
-# Define if tools should be built using static or dynamic version of the lib
-IWLIB=$(STATIC)
-#IWLIB=$(DYNAMIC)
+# Select library to link tool with
+ifdef BUILD_SHARED
+  IWLIB=$(DYNAMIC)
+else
+  IWLIB=$(STATIC)
+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
 
 
 # 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
 
-# Installation directory. By default, go in local.
-# Distributions should probably use /usr/sbin, but they probably know better...
-# Don't forget trailing slash to avoid issues
+# Install directories
+INSTALL_DIR= $(PREFIX)/sbin/
+INSTALL_LIB= $(PREFIX)/lib/
+INSTALL_INC= $(PREFIX)/include/
+INSTALL_MAN= $(PREFIX)/man/
 
 
-INSTALL_DIR= /usr/local/sbin/
-INSTALL_LIB= /usr/local/lib/
-INSTALL_INC= /usr/local/include/
-INSTALL_MAN= /usr/local/man
+# Use local header if the version of wireless extensions is specified
+ifdef FORCE_WEXT_VERSION
+  WEXT_FLAG = -DWEXT_HEADER=\"wireless.$(FORCE_WEXT_VERSION).h\"
+endif
 
 
-# Header selection is now supposed to be automatic...
-
-# Use private copy of Wireless Extension definition instead of the
-# system wide one in /usr/include/linux. Use with care.
-# Can be used to create multiple versions of the tools on the same system
-# for multiple kernels or get around broken distributions.
-#WE_HEADER= -DPRIVATE_WE_HEADER
-WE_HEADER=
-
-# ------------ End of config --------------
-
-CC = gcc
 RM = rm -f
 
 RM_CMD = $(RM) *.BAK *.bak *.o *.so ,* *~ *.a *.orig *.rej
 
 RM = rm -f
 
 RM_CMD = $(RM) *.BAK *.bak *.o *.so ,* *~ *.a *.orig *.rej
 
+ifdef KERNEL_SRC
+  KERNEL_INCLUDES = -I $(KERNEL_SRC)/include
+endif
+
+# Do we want to build with or without libm ?
+ifdef BUILD_NOLIBM
+  LIBS=
+  WELIB_FLAG = -DWE_NOLIBM=y
+else
+  LIBS= -lm
+endif
+
 #CFLAGS=-O2 -W -Wall -Wstrict-prototypes -Wmissing-prototypes -Werror
 CFLAGS=-O2 -W -Wall -Wstrict-prototypes
 #CFLAGS=-O2 -W -Wall -Wstrict-prototypes -Wmissing-prototypes -Werror
 CFLAGS=-O2 -W -Wall -Wstrict-prototypes
-XCFLAGS=$(CFLAGS) $(WARN) $(HEADERS) $(WE_HEADER)
+XCFLAGS=$(CFLAGS) $(WARN) $(HEADERS) $(WEXT_FLAG) $(WELIB_FLAG) $(KERNEL_INCLUDES)
 PICFLAG=-fPIC
 
 PICFLAG=-fPIC
 
-LIBS= -lm
-
 all:: $(STATIC) $(DYNAMIC) $(PROGS)
 
 %: %.o
 all:: $(STATIC) $(DYNAMIC) $(PROGS)
 
 %: %.o
@@ -87,13 +119,19 @@ $(STATIC): $(OBJS)
 # So crude but so effective ;-)
 # Less crude thanks to many contributions ;-)
 install::
 # So crude but so effective ;-)
 # Less crude thanks to many contributions ;-)
 install::
+       install -m 755 -d $(INSTALL_DIR)
        install -m 755 $(PROGS) $(INSTALL_DIR)
        install -m 755 $(PROGS) $(INSTALL_DIR)
+       install -m 755 -d $(INSTALL_LIB)
        install -m 644 $(STATIC) $(INSTALL_LIB)
        install -m 755 $(DYNAMIC) $(INSTALL_LIB)
        install -m 644 $(STATIC) $(INSTALL_LIB)
        install -m 755 $(DYNAMIC) $(INSTALL_LIB)
-       ln -s $(INSTALL_LIB)/$(DYNAMIC) $(INSTALL_LIB)/$(DYNAMIC_LINK)
+       ln -sfn $(DYNAMIC) $(INSTALL_LIB)/$(DYNAMIC_LINK)
        echo "Don't forget to add $(INSTALL_LIB) to /etc/ld.so.conf, and run ldconfig."
        echo "Don't forget to add $(INSTALL_LIB) to /etc/ld.so.conf, and run ldconfig."
+       install -m 755 -d $(INSTALL_INC)
        install -m 644 iwlib.h $(INSTALL_INC)
        install -m 644 iwlib.h $(INSTALL_INC)
-       install -m 644 $(MANPAGES) $(INSTALL_MAN)/man8/
+       install -m 755 -d $(INSTALL_MAN)/man8/
+       install -m 644 $(MANPAGES8) $(INSTALL_MAN)/man8/
+       install -m 755 -d $(INSTALL_MAN)/man7/
+       install -m 644 $(MANPAGES7) $(INSTALL_MAN)/man7/
 
 clean::
        $(RM_CMD) 
 
 clean::
        $(RM_CMD) 
@@ -102,6 +140,20 @@ realclean::
        $(RM_CMD) 
        $(RM) $(STATIC) $(DYNAMIC) $(PROGS) macaddr
 
        $(RM_CMD) 
        $(RM) $(STATIC) $(DYNAMIC) $(PROGS) macaddr
 
+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
+       for f in $(MANPAGES8); do \
+         $(RM) $(INSTALL_MAN)/man8/$$f; \
+       for f in $(MANPAGES7); do \
+         $(RM) $(INSTALL_MAN)/man7/$$f; \
+       done
+
 depend::
        makedepend -s "# DO NOT DELETE" -- $(INCLUDES) -- $(SRCS)
 # DO NOT DELETE
 depend::
        makedepend -s "# DO NOT DELETE" -- $(INCLUDES) -- $(SRCS)
 # DO NOT DELETE
index 0ac220d..9225585 100644 (file)
@@ -1,3 +1,6 @@
+       Pcmcia Wireless configuration
+       -----------------------------
+
        One of the most exciting thing having happen after release 20
 is the addition of Wireless Extension support in the Pcmcia init
 scripts. Here is a quick intro on the subject...
        One of the most exciting thing having happen after release 20
 is the addition of Wireless Extension support in the Pcmcia init
 scripts. Here is a quick intro on the subject...
@@ -14,14 +17,22 @@ Raylink driver :
        The Raylink driver as of 1.70 doesn't support yet writable
 Wireless Extensions, so enabling wireless.opts on this driver will
 make thing worse.
        The Raylink driver as of 1.70 doesn't support yet writable
 Wireless Extensions, so enabling wireless.opts on this driver will
 make thing worse.
-
-Pcmcia precompiled package :
---------------------------
-       The Pcmcia package part of many distributions, especially
-those from Red-Hat, include some weird init scripts. Because of this,
-the present feature won't work.
-       On the other hand, the Pcmcia package in source form from the
-official Linux-Pcmcia web site will install the proper init scripts.
+       On the other hand, the latest version of the Raylink driver
+accept Wireless Extensions at boot time, so the procedure described
+below will work.
+
+Distribution specific notes :
+---------------------------
+       Most modern distributions don't use wireless.opts and have
+their own procedure for wireless configuration, which is usually
+compatible with their configuration tools and work for non-Pcmcia
+devices. This is documented in DISTRIBUTIONS.txt.
+       The procedure described here will work only with the original
+Pcmcia configuration scripts. If you use a precompiled package part of
+a distributions, this is usually not the case (see above).
+       On the other hand, if you install the Pcmcia package in source
+form from the official Linux-Pcmcia web site, it will install the
+proper init scripts and those instructions will apply.
 
 Basic support :
 -------------
 
 Basic support :
 -------------
@@ -132,4 +143,18 @@ home,*,*,00:60:1D:*|home,*,*,00:02:2D:*)
 
        I guess you get the idea ;-)
 
 
        I guess you get the idea ;-)
 
+More elaborated configurations :
+------------------------------
+       Some people may need some more complex configurations. For
+example, you might want to do one of the following thing :
+               o cycle through a set of schemes
+               o autodetect the proper scheme
+       There is currently no support to do that. However, the
+Wireless Tools package contains a tool called "iwgetid" that can help
+in this job. The source code contains some hints on how to achieve the
+above thing.
+       If you ever write such a package, please send me the URL.
+       Good luck !
+
+
        Jean <jt@hpl.hp.com>
        Jean <jt@hpl.hp.com>
index 9391e28..e1ab782 100644 (file)
@@ -22,6 +22,12 @@ PCMCIA.txt
        This file describes how to use Pcmcia init script to configure
 Wireless Extensions and how to use Pcmcia schemes.
 
        This file describes how to use Pcmcia init script to configure
 Wireless Extensions and how to use Pcmcia schemes.
 
+DISTRIBUTION
+------------
+       This file will document the specifics of Wireless Extensions
+with a few different distributions. I need your help to complete this
+file.
+
 man pages (iwconfig.8, iwlist.8, iwpriv.8, iwspy.8)
 ---------
        VERY IMPORTANT : I try to keep the man page up to date, so
 man pages (iwconfig.8, iwlist.8, iwpriv.8, iwspy.8)
 ---------
        VERY IMPORTANT : I try to keep the man page up to date, so
@@ -70,17 +76,35 @@ iwevent.c
        Display Wireless Events. This is new, so there is not much support
 in drivers for it yet...
 
        Display Wireless Events. This is new, so there is not much support
 in drivers for it yet...
 
+iwlib.c
+-------
+       The Wireless Tools helper library. May be usefull if you want
+to create your own applications using Wireless Extensions.
+
 Changelog, contributions
 ------------------------
        See CHANGELOG.h
 
 wireless.h
 ----------
 Changelog, contributions
 ------------------------
        See CHANGELOG.h
 
 wireless.h
 ----------
-       Definition of the Wireless Extensions. You may drop this file
-in your kernel headers to update the Wireless Extensions.
+       Definition of the Wireless Extensions. Remember that the
+definition used by the drivers and the tools must match, otherwise
+funny things may happen. The tools try to check for that.
+       Since Wireless Extensions v12, you can no longer drop this
+file in your kernel headers to update the Wireless Extensions, you
+need to use the full patches available on my web page. So, the use is
+more if you plan to do some cross compile or something similar.
        Just for your enjoyement, there is various release of it. If
 your kernel/drivers are old, you may want to try the older releases...
 
        Just for your enjoyement, there is various release of it. If
 your kernel/drivers are old, you may want to try the older releases...
 
+sample_xxx.c :
+------------
+       Various samples of code showing how to implement some of the
+more tricky feature of Wireless Extensions in your driver.
+       Note that there is no guarantee that this code compile, let
+alone work, but it should point you in the proper direction.
+       Also, have a look at existing drivers in the Linux kernel.
+
 Other tools :
 -----------
        My web page list many other tools using Wireless
 Other tools :
 -----------
        My web page list many other tools using Wireless
index 1e8f323..377a3f2 100644 (file)
@@ -22,6 +22,10 @@ iwconfig \- configure a wireless network interface
 .BI "                   [enc " E "] [key " K "] [power " P "] [retry " R ]
 .br
 .BI "                   [commit]
 .BI "                   [enc " E "] [key " K "] [power " P "] [retry " R ]
 .br
 .BI "                   [commit]
+.br
+.BI "iwconfig --help"
+.br
+.BI "iwconfig --version"
 .\"
 .\" DESCRIPTION part
 .\"
 .\"
 .\" DESCRIPTION part
 .\"
@@ -121,18 +125,22 @@ topology. The mode can be
 .I Ad-hoc
 (network composed of only one cell and without Access Point),
 .I Managed
 .I Ad-hoc
 (network composed of only one cell and without Access Point),
 .I Managed
-(network composed of many cells, with roaming or with an Access Point),
+(node connects to a network composed of many Access Points, with roaming),
 .I Master
 (the node is the synchronisation master or act as an Access Point),
 .I Repeater
 .I Master
 (the node is the synchronisation master or act as an Access Point),
 .I Repeater
-(the node forward packets on the air),
+(the node forward packets between other wireless nodes),
 .I Secondary
 .I Secondary
-(the node act as a backup master/repeater) or
+(the node act as a backup master/repeater),
+.I Monitor
+(the node act as a passive monitor and only receives packets) or
 .IR Auto .
 .br
 .B Example :
 .br
 .I "   iwconfig eth0 mode Managed"
 .IR Auto .
 .br
 .B Example :
 .br
 .I "   iwconfig eth0 mode Managed"
+.br
+.I "   iwconfig eth0 mode Ad-Hoc"
 .TP
 .B ap
 Force the card to register to the Access Point given by the address,
 .TP
 .B ap
 Force the card to register to the Access Point given by the address,
@@ -226,12 +234,12 @@ Used to manipulate encryption or scrambling keys and encryption mode.
 .br
 To set the current encryption key, just enter the key in hex digits as
 .IR XXXX-XXXX-XXXX-XXXX " or " XXXXXXXX .
 .br
 To set the current encryption key, just enter the key in hex digits as
 .IR XXXX-XXXX-XXXX-XXXX " or " XXXXXXXX .
-To set a key other than the current key, append
+To set a key other than the current key, prepend or append
 .I [index]
 .I [index]
-to the key itself. You can also enter the key as an ASCII string by
-using the
+to the key itself (this won't change which is the active key). You can
+also enter the key as an ASCII string by using the
 .I s:
 .I s:
-prefix.
+prefix. Passphrase is currently not supported.
 .br
 To change which key is the current active key, just enter
 .I [index]
 .br
 To change which key is the current active key, just enter
 .I [index]
@@ -244,6 +252,12 @@ set the system in open mode (accept non-encrypted packets) and
 .I restricted
 discard non-encrypted packets.
 .br
 .I restricted
 discard non-encrypted packets.
 .br
+If you need to set multiple keys, or set a key and change the active
+key, you need to use multiple
+.B key
+directives. Arguments can be put in any order, the last one will take
+precendence.
+.br
 .B Examples :
 .br
 .I "   iwconfig eth0 key 0123-4567-89"
 .B Examples :
 .br
 .I "   iwconfig eth0 key 0123-4567-89"
@@ -253,6 +267,10 @@ discard non-encrypted packets.
 .I "   iwconfig eth0 key [2] open"
 .br
 .I "   iwconfig eth0 key off"
 .I "   iwconfig eth0 key [2] open"
 .br
 .I "   iwconfig eth0 key off"
+.br
+.I "   iwconfig eth0 key restricted [3] 0123456789"
+.br
+.I "   iwconfig eth0 key 01-23 key 45-67 [4] key [4]"
 .TP
 .BR power
 Used to manipulate power management scheme parameters and mode.
 .TP
 .BR power
 Used to manipulate power management scheme parameters and mode.
index 73e7ec1..c8ffe07 100644 (file)
@@ -24,6 +24,7 @@ iw_usage(void)
 {
   fprintf(stderr, "Usage: iwconfig interface [essid {NN|on|off}]\n");
   fprintf(stderr, "                          [nwid {NN|on|off}]\n");
 {
   fprintf(stderr, "Usage: iwconfig interface [essid {NN|on|off}]\n");
   fprintf(stderr, "                          [nwid {NN|on|off}]\n");
+  fprintf(stderr, "                          [mode {managed|ad-hoc|...}\n");
   fprintf(stderr, "                          [freq N.NNNN[k|M|G]]\n");
   fprintf(stderr, "                          [channel N]\n");
   fprintf(stderr, "                          [sens N]\n");
   fprintf(stderr, "                          [freq N.NNNN[k|M|G]]\n");
   fprintf(stderr, "                          [channel N]\n");
   fprintf(stderr, "                          [sens N]\n");
@@ -31,10 +32,11 @@ iw_usage(void)
   fprintf(stderr, "                          [rate {N|auto|fixed}]\n");
   fprintf(stderr, "                          [rts {N|auto|fixed|off}]\n");
   fprintf(stderr, "                          [frag {N|auto|fixed|off}]\n");
   fprintf(stderr, "                          [rate {N|auto|fixed}]\n");
   fprintf(stderr, "                          [rts {N|auto|fixed|off}]\n");
   fprintf(stderr, "                          [frag {N|auto|fixed|off}]\n");
-  fprintf(stderr, "                          [enc NNNN-NNNN]\n");
-  fprintf(stderr, "                          [power { period N|timeout N}]\n");
+  fprintf(stderr, "                          [enc {NNNN-NNNN|off}]\n");
+  fprintf(stderr, "                          [power {period N|timeout N}]\n");
   fprintf(stderr, "                          [txpower N {mW|dBm}]\n");
   fprintf(stderr, "                          [commit]\n");
   fprintf(stderr, "                          [txpower N {mW|dBm}]\n");
   fprintf(stderr, "                          [commit]\n");
+  fprintf(stderr, "       Check man pages for more details.\n\n");
 }
 
 
 }
 
 
@@ -69,7 +71,10 @@ get_info(int                 skfd,
        return(-ENOTSUP);
     }
   else
        return(-ENOTSUP);
     }
   else
-    strcpy(info->name, wrq.u.name);
+    {
+      strncpy(info->name, wrq.u.name, IFNAMSIZ);
+      info->name[IFNAMSIZ] = '\0';
+    }
 
   /* Get ranges */
   if(iw_get_range_info(skfd, ifname, &(info->range)) >= 0)
 
   /* Get ranges */
   if(iw_get_range_info(skfd, ifname, &(info->range)) >= 0)
@@ -109,7 +114,7 @@ get_info(int                        skfd,
 
   /* Get ESSID */
   wrq.u.essid.pointer = (caddr_t) info->essid;
 
   /* Get ESSID */
   wrq.u.essid.pointer = (caddr_t) info->essid;
-  wrq.u.essid.length = IW_ESSID_MAX_SIZE;
+  wrq.u.essid.length = IW_ESSID_MAX_SIZE + 1;
   wrq.u.essid.flags = 0;
   if(iw_get_ext(skfd, ifname, SIOCGIWESSID, &wrq) >= 0)
     {
   wrq.u.essid.flags = 0;
   if(iw_get_ext(skfd, ifname, SIOCGIWESSID, &wrq) >= 0)
     {
@@ -126,7 +131,7 @@ get_info(int                        skfd,
 
   /* Get NickName */
   wrq.u.essid.pointer = (caddr_t) info->nickname;
 
   /* Get NickName */
   wrq.u.essid.pointer = (caddr_t) info->nickname;
-  wrq.u.essid.length = IW_ESSID_MAX_SIZE;
+  wrq.u.essid.length = IW_ESSID_MAX_SIZE + 1;
   wrq.u.essid.flags = 0;
   if(iw_get_ext(skfd, ifname, SIOCGIWNICKN, &wrq) >= 0)
     if(wrq.u.data.length > 1)
   wrq.u.essid.flags = 0;
   if(iw_get_ext(skfd, ifname, SIOCGIWNICKN, &wrq) >= 0)
     if(wrq.u.data.length > 1)
@@ -283,7 +288,7 @@ display_info(struct wireless_info * info,
        printf("Cell:");
       else
        printf("Access Point:");
        printf("Cell:");
       else
        printf("Access Point:");
-      printf(" %s", iw_pr_ether(buffer, info->ap_addr.sa_data));
+      printf(" %s  ", iw_pr_ether(buffer, info->ap_addr.sa_data));
     }
 
   /* Display the currently used/set bit-rate */
     }
 
   /* Display the currently used/set bit-rate */
@@ -744,7 +749,8 @@ set_info(int                skfd,           /* The socket */
            }
          else
            {
            }
          else
            {
-             int       gotone = 1;
+             int       gotone = 0;
+             int       oldone;
              int       keylen;
              int       temp;
 
              int       keylen;
              int       temp;
 
@@ -752,47 +758,64 @@ set_info(int              skfd,           /* The socket */
              wrq.u.data.flags = 0;
              wrq.u.data.length = 0;
 
              wrq.u.data.flags = 0;
              wrq.u.data.length = 0;
 
-             /* -- Check for the key -- */
-             keylen = iw_in_key(args[i], key);
-             if(keylen > 0)
+             /* Allow arguments in any order (it's safe) */
+             do
                {
                {
-                 wrq.u.data.length = keylen;
-                 wrq.u.data.pointer = (caddr_t) key;
-                 ++i;
-                 gotone = 1;
-               }
+                 oldone = gotone;
 
 
-             /* -- Check for token index -- */
-             if((i < count) &&
-                (sscanf(args[i], "[%d]", &temp) == 1) &&
-                (temp > 0) && (temp < IW_ENCODE_INDEX))
-               {
-                 wrq.u.encoding.flags |= temp;
-                 ++i;
-                 gotone = 1;
-               }
+                 /* -- Check for the key -- */
+                 if(i < count)
+                   {
+                     keylen = iw_in_key(args[i], key);
+                     if(keylen > 0)
+                       {
+                         wrq.u.data.length = keylen;
+                         wrq.u.data.pointer = (caddr_t) key;
+                         ++i;
+                         gotone++;
+                       }
+                   }
 
 
-             /* -- Check the various flags -- */
-             if(i < count)
-               {
-                 if(!strcasecmp(args[i], "off"))
-                   wrq.u.data.flags |= IW_ENCODE_DISABLED;
-                 if(!strcasecmp(args[i], "open"))
-                   wrq.u.data.flags |= IW_ENCODE_OPEN;
-                 if(!strncasecmp(args[i], "restricted", 5))
-                   wrq.u.data.flags |= IW_ENCODE_RESTRICTED;
-                 if(wrq.u.data.flags & IW_ENCODE_FLAGS)
+                 /* -- Check for token index -- */
+                 if((i < count) &&
+                    (sscanf(args[i], "[%d]", &temp) == 1) &&
+                    (temp > 0) && (temp < IW_ENCODE_INDEX))
                    {
                    {
+                     wrq.u.encoding.flags |= temp;
                      ++i;
                      ++i;
-                     gotone = 1;
+                     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++;
                    }
                }
                    }
                }
+             while(gotone != oldone);
+
              /* Pointer is absent in new API */
              if(wrq.u.data.pointer == NULL)
                wrq.u.data.flags |= IW_ENCODE_NOKEY;
 
              /* 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)
                ABORT_ARG_TYPE("Set Encode", SIOCSIWENCODE, args[i]);
              if(!gotone)
                ABORT_ARG_TYPE("Set Encode", SIOCSIWENCODE, args[i]);
+             /* Get back to last processed argument */
              --i;
            }
 
              --i;
            }
 
@@ -1335,16 +1358,19 @@ main(int        argc,
     iw_enum_devices(skfd, &print_info, NULL, 0);
   else
     /* Special case for help... */
     iw_enum_devices(skfd, &print_info, NULL, 0);
   else
     /* Special case for help... */
-    if((!strncmp(argv[1], "-h", 9)) ||
-       (!strcmp(argv[1], "--help")))
+    if((!strcmp(argv[1], "-h")) || (!strcmp(argv[1], "--help")))
       iw_usage();
     else
       iw_usage();
     else
-      /* The device name must be the first argument */
-      if(argc == 2)
-       print_info(skfd, argv[1], NULL, 0);
+      /* Special case for version... */
+      if (!strcmp(argv[1], "-v") || !strcmp(argv[1], "--version"))
+       goterr = iw_print_version_info("iwconfig");
       else
       else
-       /* The other args on the line specify options to be set... */
-       goterr = set_info(skfd, argv + 2, argc - 2, argv[1]);
+       /* The device name must be the first argument */
+       if(argc == 2)
+         print_info(skfd, argv[1], NULL, 0);
+       else
+         /* The other args on the line specify options to be set... */
+         goterr = set_info(skfd, argv + 2, argc - 2, argv[1]);
 
   /* Close the socket. */
   close(skfd);
 
   /* Close the socket. */
   close(skfd);
index 2a73d6d..719e131 100644 (file)
@@ -67,13 +67,27 @@ available (see
 .BR iwlist ).
 .TP
 .B Tx packet dropped
 .BR iwlist ).
 .TP
 .B Tx packet dropped
-A packet directed at this address has been dropped because the card
-believes this node doesn't answer anymore. An early indication that
-the node may have left the cell or gone out of range.
+A packet directed at this address has been dropped because the
+interface believes this node doesn't answer anymore. An early
+indication that the node may have left the cell or gone out of range.
+.TP
+.B Custom driver event
+Event specific to the driver. Please check the driver documentation.
+.TP
+.B Registered node
+The interface has successfully registered a new wireless
+client/peer. Will be generated mostly when the interface act as an
+Access Point (mode master).
+.TP
+.B Expired node
+The registration of the client/peer on this interface has
+expired. Will be generated mostly when the interface act as an Access
+Point (mode master).
 .PP
 Only some of those events will be generated on some wireless
 interfaces by the wireless driver, and their support depend on the
 .PP
 Only some of those events will be generated on some wireless
 interfaces by the wireless driver, and their support depend on the
-specific hardware/driver combination.
+specific hardware/driver combination. Please refer to driver
+documentation for details.
 .\"
 .\" AUTHOR part
 .\"
 .\"
 .\" AUTHOR part
 .\"
index 6a1de90..54bf96b 100644 (file)
@@ -190,8 +190,27 @@ print_event_token(struct iw_event *        event,  /* Extracted token */
       break;
     case IWEVTXDROP:
       printf("Tx packet dropped:%s\n",
       break;
     case IWEVTXDROP:
       printf("Tx packet dropped:%s\n",
-            iw_pr_ether(buffer, event->u.ap_addr.sa_data));
+            iw_pr_ether(buffer, event->u.addr.sa_data));
+      break;
+#if WIRELESS_EXT > 14
+    case IWEVCUSTOM:
+      {
+       char custom[IW_CUSTOM_MAX+1];
+       if((event->u.data.pointer) && (event->u.data.length))
+         memcpy(custom, event->u.data.pointer, event->u.data.length);
+       custom[event->u.data.length] = '\0';
+       printf("Custom driver event:%s\n", custom);
+      }
+      break;
+    case IWEVREGISTERED:
+      printf("Registered node:%s\n",
+            iw_pr_ether(buffer, event->u.addr.sa_data));
+      break;
+    case IWEVEXPIRED:
+      printf("Expired node:%s\n",
+            iw_pr_ether(buffer, event->u.addr.sa_data));
       break;
       break;
+#endif /* WIRELESS_EXT > 14 */
       /* ----- junk ----- */
       /* other junk not currently in use */
     case SIOCGIWRATE:
       /* ----- junk ----- */
       /* other junk not currently in use */
     case SIOCGIWRATE:
@@ -481,13 +500,15 @@ iw_usage(int status)
   fputs("Usage: iwevent [OPTIONS]\n"
        "   Monitors and displays Wireless Events.\n"
        "   Options are:\n"
   fputs("Usage: iwevent [OPTIONS]\n"
        "   Monitors and displays Wireless Events.\n"
        "   Options are:\n"
-       "     -h,--help  Print this message.\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' },
        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 }
 };
 
   { NULL, 0, NULL, 0 }
 };
 
@@ -503,7 +524,7 @@ main(int    argc,
   int opt;
 
   /* Check command line options */
   int opt;
 
   /* Check command line options */
-  while((opt = getopt_long(argc, argv, "h", long_opts, NULL)) > 0)
+  while((opt = getopt_long(argc, argv, "hv", long_opts, NULL)) > 0)
     {
       switch(opt)
        {
     {
       switch(opt)
        {
@@ -511,6 +532,10 @@ main(int   argc,
          iw_usage(0);
          break;
 
          iw_usage(0);
          break;
 
+       case 'v':
+         return(iw_print_version_info("iwevent"));
+         break;
+
        default:
          iw_usage(1);
          break;
        default:
          iw_usage(1);
          break;
@@ -529,6 +554,13 @@ main(int   argc,
       return(1);
     }
 
       return(1);
     }
 
+#if WIRELESS_EXT > 13
+  fprintf(stderr, "Waiting for Wireless Events...\n");
+#else  /* WIRELESS_EXT > 13 */
+  fprintf(stderr, "Unsupported in Wireless Extensions <= 14 :-(\n");
+  return(-1);
+#endif /* WIRELESS_EXT > 13 */
+
   /* Do what we have to do */
   wait_for_event(&rth);
 
   /* Do what we have to do */
   wait_for_event(&rth);
 
index 323ce8c..30c8890 100644 (file)
@@ -12,7 +12,9 @@ iwgetid \- Report ESSID, NWID or AP/Cell Address of wireless network
 .\" SYNOPSIS part
 .\"
 .SH SYNOPSIS
 .\" SYNOPSIS part
 .\"
 .SH SYNOPSIS
-.BI "iwgetid " [interface] " [--scheme] [--ap]"
+.BI "iwgetid " [interface] " [--scheme] [--ap] [--freq] [--mode]"
+.br
+.BI "                   [--protocol]
 .br
 .\"
 .\" DESCRIPTION part
 .br
 .\"
 .\" DESCRIPTION part
@@ -43,7 +45,8 @@ ESSID (or NWID, or AP Address) is printed. Also, characters that are
 not alphanumerics (like space, punctuation and control characters) are
 skipped.
 .br
 not alphanumerics (like space, punctuation and control characters) are
 skipped.
 .br
-The resulting output is a valid Pcmcia scheme identifier (that may be used as an argument of the command
+The resulting output is a valid Pcmcia scheme identifier (that may be
+used as an argument of the command
 .BR "cardctl scheme" ).
 This format is also ideal when using the result of iwgetid as a
 variable in
 .BR "cardctl scheme" ).
 This format is also ideal when using the result of iwgetid as a
 variable in
@@ -57,6 +60,30 @@ Display the MAC address of the Wireless
 .I Access Point
 or the
 .IR Cell .
 .I Access Point
 or the
 .IR Cell .
+.TP
+.B --freq
+Display the current
+.I frequency
+or
+.I channel
+used by the interface.
+.TP
+.B --mode
+Display the current
+.I mode
+of the interface.
+.TP
+.B --protocol
+Display the
+.I protocol name
+of the interface. This allow to identify all the cards that are
+compatible with each other and accept the same type of
+configuration.
+.br
+This can also be used to
+.I check Wireless Extension support
+on the interface, as this is the only attribute that all drivers
+supporting Wireless Extension are mandated to support.
 .\"
 .\" SEE ALSO part
 .\"
 .\"
 .\" SEE ALSO part
 .\"
index f573209..1d74910 100644 (file)
@@ -17,6 +17,9 @@
 #define FORMAT_SCHEME  1       /* To be used as a Pcmcia Scheme */
 #define WTYPE_ESSID    0       /* Display ESSID or NWID */
 #define WTYPE_AP       1       /* Display AP/Cell Address */
 #define FORMAT_SCHEME  1       /* To be used as a Pcmcia Scheme */
 #define WTYPE_ESSID    0       /* Display ESSID or NWID */
 #define WTYPE_AP       1       /* Display AP/Cell Address */
+#define WTYPE_FREQ     2       /* Display frequency/channel */
+#define WTYPE_MODE     3       /* Display mode */
+#define WTYPE_PROTO    4       /* Display protocol name */
 
 /*
  * Note on Pcmcia Schemes :
 
 /*
  * Note on Pcmcia Schemes :
 /*
  * Just for the heck of it, let's try to not link with iwlib.
  * This will keep the binary small and tiny...
 /*
  * Just for the heck of it, let's try to not link with iwlib.
  * This will keep the binary small and tiny...
+ *
+ * Note : maybe it's time to admit that we have lost the battle
+ * and we start using iwlib ? Maybe we should default to dynamic
+ * lib first...
  */
 
 /*------------------------------------------------------------------*/
  */
 
 /*------------------------------------------------------------------*/
@@ -122,6 +129,59 @@ iw_ether_ntop(const struct ether_addr* eth, char* buf)
          eth->ether_addr_octet[4], eth->ether_addr_octet[5]);
 }
 
          eth->ether_addr_octet[4], eth->ether_addr_octet[5]);
 }
 
+/*------------------------------------------------------------------*/
+/*
+ * Convert our internal representation of frequencies to a floating point.
+ */
+double
+iw_freq2float(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(char *   buffer,
+             double    freq)
+{
+  if(freq < KILO)
+    sprintf(buffer, "Channel:%g", freq);
+  else
+    {
+      if(freq >= GIGA)
+       sprintf(buffer, "Frequency:%gGHz", freq / GIGA);
+      else
+       {
+         if(freq >= MEGA)
+           sprintf(buffer, "Frequency:%gMHz", freq / MEGA);
+         else
+           sprintf(buffer, "Frequency:%gkHz", freq / KILO);
+       }
+    }
+}
+
+/*------------------------------------------------------------------*/
+const char * const iw_operation_mode[] = { "Auto",
+                                       "Ad-Hoc",
+                                       "Managed",
+                                       "Master",
+                                       "Repeater",
+                                       "Secondary",
+                                       "Monitor" };
+
 /************************ DISPLAY ESSID/NWID ************************/
 
 /*------------------------------------------------------------------*/
 /************************ DISPLAY ESSID/NWID ************************/
 
 /*------------------------------------------------------------------*/
@@ -142,7 +202,7 @@ print_essid(int                     skfd,
   /* Get ESSID */
   strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
   wrq.u.essid.pointer = (caddr_t) essid;
   /* Get ESSID */
   strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
   wrq.u.essid.pointer = (caddr_t) essid;
-  wrq.u.essid.length = 0;
+  wrq.u.essid.length = IW_ESSID_MAX_SIZE + 1;
   wrq.u.essid.flags = 0;
   if(ioctl(skfd, SIOCGIWESSID, &wrq) < 0)
     return(-1);
   wrq.u.essid.flags = 0;
   if(ioctl(skfd, SIOCGIWESSID, &wrq) < 0)
     return(-1);
@@ -227,7 +287,118 @@ print_ap(int              skfd,
       printf("%s\n", buffer);
       break;
     default:
       printf("%s\n", buffer);
       break;
     default:
-      printf("%-8.8s  Access Point: %s\n", ifname, buffer);
+      printf("%-8.8s  Access Point/Cell: %s\n", ifname, buffer);
+      break;
+    }
+
+  return(0);
+}
+
+/****************************** OTHER ******************************/
+
+/*------------------------------------------------------------------*/
+/*
+ * Display the frequency (or channel) if possible
+ */
+static int
+print_freq(int         skfd,
+          const char * ifname,
+          int          format)
+{
+  struct iwreq         wrq;
+  double               freq;
+  char                 buffer[64];
+
+  /* Get frequency / channel */
+  strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
+  if(ioctl(skfd, SIOCGIWFREQ, &wrq) < 0)
+    return(-1);
+
+  /* Print */
+  freq = iw_freq2float(&(wrq.u.freq));
+  switch(format)
+    {
+    case FORMAT_SCHEME:
+      printf("%g\n", freq);
+      break;
+    default:
+      iw_print_freq(buffer, freq);
+      printf("%-8.8s  %s\n", ifname, buffer);
+      break;
+    }
+
+  return(0);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Display the mode if possible
+ */
+static int
+print_mode(int         skfd,
+          const char * ifname,
+          int          format)
+{
+  struct iwreq         wrq;
+
+  /* Get frequency / channel */
+  strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
+  if(ioctl(skfd, SIOCGIWMODE, &wrq) < 0)
+    return(-1);
+  if(wrq.u.mode >= IW_NUM_OPER_MODE)
+    return(-2);
+
+  /* Print */
+  switch(format)
+    {
+    case FORMAT_SCHEME:
+      printf("%d\n", wrq.u.mode);
+      break;
+    default:
+      printf("%-8.8s  Mode:%s\n", ifname, iw_operation_mode[wrq.u.mode]);
+      break;
+    }
+
+  return(0);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Display the ESSID if possible
+ */
+static int
+print_protocol(int             skfd,
+              const char *     ifname,
+              int              format)
+{
+  struct iwreq         wrq;
+  char                 proto[IFNAMSIZ + 1];    /* Protocol */
+  char                 pproto[IFNAMSIZ + 1];   /* Pcmcia format */
+  unsigned int         i;
+  unsigned int         j;
+
+  /* Get Protocol name */
+  strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
+  if(ioctl(skfd, SIOCGIWNAME, &wrq) < 0)
+    return(-1);
+  strncpy(proto, wrq.u.name, IFNAMSIZ);
+  proto[IFNAMSIZ] = '\0';
+
+  switch(format)
+    {
+    case FORMAT_SCHEME:
+      /* Strip all white space and stuff */
+      j = 0;
+      for(i = 0; i < strlen(proto); i++)
+       if(isalnum(proto[i]))
+         pproto[j++] = proto[i];
+      pproto[j] = '\0';
+      if((j == 0) || (j > 32))
+       return(-2);
+      printf("%s\n", pproto);
+      break;
+    default:
+      printf("%-8.8s  Protocol Name:\"%s\"\n", ifname, proto);
       break;
     }
 
       break;
     }
 
@@ -249,20 +420,36 @@ print_one_device(int              skfd,
   int ret;
 
   /* Check wtype */
   int ret;
 
   /* Check wtype */
-  if(wtype == WTYPE_AP)
+  switch(wtype)
     {
     {
+    case WTYPE_AP:
       /* Try to print an AP */
       ret = print_ap(skfd, ifname, format);
       /* Try to print an AP */
       ret = print_ap(skfd, ifname, format);
-      return(ret);
-    }
+      break;
 
 
-  /* Try to print an ESSID */
-  ret = print_essid(skfd, ifname, format);
+    case WTYPE_FREQ:
+      /* Try to print frequency */
+      ret = print_freq(skfd, ifname, format);
+      break;
 
 
-  if(ret < 0)
-    {
-      /* Try to print a nwid */
-      ret = print_nwid(skfd, ifname, format);
+    case WTYPE_MODE:
+      /* Try to print the mode */
+      ret = print_mode(skfd, ifname, format);
+      break;
+
+    case WTYPE_PROTO:
+      /* Try to print the protocol */
+      ret = print_protocol(skfd, ifname, format);
+      break;
+
+    default:
+      /* Try to print an ESSID */
+      ret = print_essid(skfd, ifname, format);
+      if(ret < 0)
+       {
+         /* Try to print a nwid */
+         ret = print_nwid(skfd, ifname, format);
+       }
     }
 
   return(ret);
     }
 
   return(ret);
@@ -310,15 +497,21 @@ iw_usage(int status)
 {
   fputs("Usage iwgetid [OPTIONS] [ifname]\n"
        "  Options are:\n"
 {
   fputs("Usage iwgetid [OPTIONS] [ifname]\n"
        "  Options are:\n"
-       "    -a,--ap      Print the access point address\n"
-       "    -h,--help    Print this message\n"
-       "    -s,--scheme  Format the output as a PCMCIA scheme identifier\n",
+       "    -a,--ap       Print the access point address\n"
+       "    -f,--freq     Print the current frequency\n"
+       "    -m,--mode     Print the current mode\n"
+       "    -p,--protocol Print the protocol name\n"
+       "    -s,--scheme   Format the output as a PCMCIA scheme identifier\n"
+       "    -h,--help     Print this message\n",
        status ? stderr : stdout);
   exit(status);
 }
 
 static const struct option long_opts[] = {
   { "ap", no_argument, NULL, 'a' },
        status ? stderr : stdout);
   exit(status);
 }
 
 static const struct option long_opts[] = {
   { "ap", no_argument, NULL, 'a' },
+  { "freq", no_argument, NULL, 'f' },
+  { "mode", no_argument, NULL, 'm' },
+  { "protocol", no_argument, NULL, 'p' },
   { "help", no_argument, NULL, 'h' },
   { "scheme", no_argument, NULL, 's' },
   { NULL, 0, NULL, 0 }
   { "help", no_argument, NULL, 'h' },
   { "scheme", no_argument, NULL, 's' },
   { NULL, 0, NULL, 0 }
@@ -339,7 +532,7 @@ main(int    argc,
   int  ret = -1;
 
   /* Check command line arguments */
   int  ret = -1;
 
   /* Check command line arguments */
-  while((opt = getopt_long(argc, argv, "ahs", long_opts, NULL)) > 0)
+  while((opt = getopt_long(argc, argv, "afhmps", long_opts, NULL)) > 0)
     {
       switch(opt)
        {
     {
       switch(opt)
        {
@@ -348,6 +541,21 @@ main(int   argc,
          wtype = WTYPE_AP;
          break;
 
          wtype = WTYPE_AP;
          break;
 
+       case 'f':
+         /* User wants frequency/channel */
+         wtype = WTYPE_FREQ;
+         break;
+
+       case 'm':
+         /* User wants the mode */
+         wtype = WTYPE_MODE;
+         break;
+
+       case 'p':
+         /* User wants the protocol */
+         wtype = WTYPE_PROTO;
+         break;
+
        case 'h':
          iw_usage(0);
          break;
        case 'h':
          iw_usage(0);
          break;
index 9d0f575..64c2d78 100644 (file)
@@ -9,8 +9,44 @@
  *     Copyright (c) 1997-2002 Jean Tourrilhes <jt@hpl.hp.com>
  */
 
  *     Copyright (c) 1997-2002 Jean Tourrilhes <jt@hpl.hp.com>
  */
 
+/***************************** INCLUDES *****************************/
+
 #include "iwlib.h"             /* Header */
 
 #include "iwlib.h"             /* Header */
 
+/************************ CONSTANTS & MACROS ************************/
+
+/* Various versions information */
+/* Recommended Wireless Extension version */
+#define WE_VERSION     15
+/* Version of Wireless Tools */
+#define WT_VERSION     25
+
+/*
+ * Verify a few things about Wireless Extensions.
+ * I try to maximise backward and forward compatibility, but things are
+ * tricky because I'm fixing bugs and adding new features.
+ * Wireless Tools *must* be compiled with the same version of WE
+ * as the driver. Sometime, the size or layout of some structure changes,
+ * and might produce interesting results.
+ * Wireless Tools will usually compile properly against different
+ * versions of WE, thanks to the zillions of #ifdefs in my code.
+ * Jean II
+ */
+#if WIRELESS_EXT < 9
+#error "Wireless Extension v9 or newer required :-("
+#error "Use Wireless Tools v19 or update your kernel headers !"
+#endif
+#if WIRELESS_EXT < WE_VERSION && !defined(WEXT_HEADER)
+#warning "Wireless Extension earlier than v15 detected,"
+#warning "Not all tools features will be compiled in !"
+#warning "No worry, I'll try to make the best of it ;-)"
+#endif
+#if WIRELESS_EXT > WE_VERSION && !defined(WEXT_HEADER)
+#warning "Wireless Extension later than v15 detected,"
+#warning "Maybe you should get a more recent version"
+#warning "of the Wireless Tools package !"
+#endif
+
 /**************************** VARIABLES ****************************/
 
 const char * const iw_operation_mode[] = { "Auto",
 /**************************** VARIABLES ****************************/
 
 const char * const iw_operation_mode[] = { "Auto",
@@ -18,7 +54,11 @@ const char * const iw_operation_mode[] = { "Auto",
                                        "Managed",
                                        "Master",
                                        "Repeater",
                                        "Managed",
                                        "Master",
                                        "Repeater",
-                                       "Secondary" };
+                                       "Secondary",
+                                       "Monitor" };
+
+/* Disable runtime version warning in iw_get_range_info() */
+int    iw_ignore_version = 0;
 
 /************************ SOCKET SUBROUTINES *************************/
 
 
 /************************ SOCKET SUBROUTINES *************************/
 
@@ -60,9 +100,7 @@ iw_sockets_open(void)
 
 /*------------------------------------------------------------------*/
 /*
 
 /*------------------------------------------------------------------*/
 /*
- * Extract the interface name out of /proc/net/wireless
- * Important note : this procedure will work only with /proc/net/wireless
- * and not /proc/net/dev, because it doesn't guarantee a ' ' after the ':'.
+ * 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 */
  */
 static inline char *
 iw_get_ifname(char *   name,   /* Where to store the name */
@@ -75,10 +113,17 @@ iw_get_ifname(char *       name,   /* Where to store the name */
   while(isspace(*buf))
     buf++;
 
   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
   /* Get name up to ": "
    * Note : we compare to ": " to make sure to process aliased interfaces
-   * properly. */
+   * properly. Doesn't work on /proc/net/dev, because it doesn't guarantee
+   * a ' ' after the ':'*/
   end = strstr(buf, ": ");
   end = strstr(buf, ": ");
+#endif
 
   /* Not found ??? To big ??? */
   if((end == NULL) || (((end - buf) + 1) > nsize))
 
   /* Not found ??? To big ??? */
   if((end == NULL) || (((end - buf) + 1) > nsize))
@@ -111,8 +156,13 @@ iw_enum_devices(int                skfd,
   struct ifreq *ifr;
   int          i;
 
   struct ifreq *ifr;
   int          i;
 
+#ifndef IW_RESTRIC_ENUM
+  /* Check if /proc/net/wireless is available */
+  fh = fopen(PROC_NET_DEV, "r");
+#else
   /* Check if /proc/net/wireless is available */
   fh = fopen(PROC_NET_WIRELESS, "r");
   /* Check if /proc/net/wireless is available */
   fh = fopen(PROC_NET_WIRELESS, "r");
+#endif
 
   if(fh != NULL)
     {
 
   if(fh != NULL)
     {
@@ -189,53 +239,152 @@ iw_get_range_info(int            skfd,
    * Extensions are concerned. It's because /usr/include/linux/wireless.h
    * and /usr/src/linux/include/linux/wireless.h are different.
    * We try to catch this stuff here... */
    * Extensions are concerned. It's because /usr/include/linux/wireless.h
    * and /usr/src/linux/include/linux/wireless.h are different.
    * We try to catch this stuff here... */
+  if(!iw_ignore_version)
+    {
+      /* 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((WIRELESS_EXT > 10) && (wrq.u.data.length >= 300))
+       {
+#if WIRELESS_EXT > 10
+         /* Version verification - for new versions */
+         if(range->we_version_compiled != WIRELESS_EXT)
+           {
+             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 is using version %d.\n", WIRELESS_EXT);
+             fprintf(stderr, "Some things may be broken...\n\n");
+           }
+         /* Driver version verification */
+         if(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");
+           }
+#endif /* WIRELESS_EXT > 10 */
+       }
+      else
+       {
+         /* Version verification - for old versions */
+         if(wrq.u.data.length != sizeof(iwrange))
+           {
+             fprintf(stderr, "Warning: Driver for device %s has been compiled with an ancient version\n", ifname);
+             fprintf(stderr, "of Wireless Extension, while this program is using version %d.\n", WIRELESS_EXT);
+             fprintf(stderr, "Some things may be broken...\n\n");
+           }
+       }
+    }
+  /* Don't complain twice.
+   * In theory, the test apply to each individual driver, but usually
+   * all drivers are compiled from the same kernel, and most often
+   * problem is the system/glibc headers. */
+  iw_ignore_version = 1;
+
+  /* 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 */
+
+  return(0);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * 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;
+
+  /* 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)
+    return(-1);
+
+  /* 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((WIRELESS_EXT > 10) && (wrq.u.data.length >= 300))
     {
 #if WIRELESS_EXT > 10
 
   /* 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((WIRELESS_EXT > 10) && (wrq.u.data.length >= 300))
     {
 #if WIRELESS_EXT > 10
-      /* Version verification - for new versions */
-      if(range->we_version_compiled != WIRELESS_EXT)
-       {
-         fprintf(stderr, "Warning : Device %s has been compiled with version %d\n", ifname, range->we_version_compiled);
-         fprintf(stderr, "of Wireless Extension, while we are using version %d.\n", WIRELESS_EXT);
-         fprintf(stderr, "Some things may be broken...\n\n");
-       }
+      printf("%-8.8s  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);
 #endif /* WIRELESS_EXT > 10 */
     }
   else
     {
 #endif /* WIRELESS_EXT > 10 */
     }
   else
     {
-      /* Version verification - for old versions */
-      if(wrq.u.data.length != sizeof(iwrange))
-       {
-         fprintf(stderr, "Warning : Device %s has been compiled with a different version\n", ifname);
-         fprintf(stderr, "of Wireless Extension than ours (we are using version %d).\n", WIRELESS_EXT);
-         fprintf(stderr, "Some things may be broken...\n\n");
-       }
+#if 0
+      fprintf(stderr, "%-8.8s  no Wireless Extension version information.\n\n",
+                     ifname);
+#endif
     }
 
     }
 
-  /* 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 */
 
   return(0);
 }
 
 /*------------------------------------------------------------------*/
 /*
 
   return(0);
 }
 
 /*------------------------------------------------------------------*/
 /*
+ * Print the WE versions of the tools.
+ */
+int
+iw_print_version_info(char *   toolname)
+{
+  int skfd;                    /* generic raw socket desc.     */
+
+  /* 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.8s  Version %d\n", toolname, WT_VERSION);
+  printf("          Compatible with Wireless Extension v%d or earlier,\n",
+        WE_VERSION);
+  printf("          Currently compiled with Wireless Extension v%d.\n\n",
+        WIRELESS_EXT);
+
+  /* Version for each device */
+  iw_enum_devices(skfd, &print_iface_version_info, NULL, 0);
+
+  close(skfd);
+
+  return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
  * Get information about what private ioctls are supported by the driver
  */
 int
 iw_get_priv_info(int           skfd,
                 char *         ifname,
  * Get information about what private ioctls are supported by the driver
  */
 int
 iw_get_priv_info(int           skfd,
                 char *         ifname,
-                iwprivargs *   priv)
+                iwprivargs *   priv,
+                int            maxpriv)
 {
   struct iwreq         wrq;
 
   /* Ask the driver */
   wrq.u.data.pointer = (caddr_t) priv;
 {
   struct iwreq         wrq;
 
   /* Ask the driver */
   wrq.u.data.pointer = (caddr_t) priv;
-  wrq.u.data.length = 32;
+  wrq.u.data.length = maxpriv;
   wrq.u.data.flags = 0;
   if(iw_get_ext(skfd, ifname, SIOCGIWPRIV, &wrq) < 0)
     return(-1);
   wrq.u.data.flags = 0;
   if(iw_get_ext(skfd, ifname, SIOCGIWPRIV, &wrq) < 0)
     return(-1);
@@ -266,7 +415,10 @@ iw_get_basic_config(int                    skfd,
     /* If no wireless name : no wireless extensions */
     return(-1);
   else
     /* If no wireless name : no wireless extensions */
     return(-1);
   else
-    strcpy(info->name, wrq.u.name);
+    {
+      strncpy(info->name, wrq.u.name, IFNAMSIZ);
+      info->name[IFNAMSIZ] = '\0';
+    }
 
   /* Get network ID */
   if(iw_get_ext(skfd, ifname, SIOCGIWNWID, &wrq) >= 0)
 
   /* Get network ID */
   if(iw_get_ext(skfd, ifname, SIOCGIWNWID, &wrq) >= 0)
@@ -295,7 +447,7 @@ iw_get_basic_config(int                     skfd,
 
   /* Get ESSID */
   wrq.u.essid.pointer = (caddr_t) info->essid;
 
   /* Get ESSID */
   wrq.u.essid.pointer = (caddr_t) info->essid;
-  wrq.u.essid.length = IW_ESSID_MAX_SIZE;
+  wrq.u.essid.length = IW_ESSID_MAX_SIZE + 1;
   wrq.u.essid.flags = 0;
   if(iw_get_ext(skfd, ifname, SIOCGIWESSID, &wrq) >= 0)
     {
   wrq.u.essid.flags = 0;
   if(iw_get_ext(skfd, ifname, SIOCGIWESSID, &wrq) >= 0)
     {
@@ -426,7 +578,64 @@ iw_set_basic_config(int                    skfd,
   return(ret);
 }
 
   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
+ */
+int
+iw_protocol_compare(char *     protocol1,
+                   char *      protocol2)
+{
+  char *       dot11 = "IEEE 802.11";
+  char *       dot11_ds = "Dbg";
+
+  /* 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))) )
+    {
+      char *   sub1 = protocol1 + strlen(dot11);
+      char *   sub2 = protocol2 + strlen(dot11);
+
+      /* Skip optional separator */
+      if(*sub1 == '-')
+       sub1++;
+      if(*sub2 == '-')
+       sub2++;
+
+      /* Check if they are both 2.4 GHz Direct Sequence compatible */
+      if( (strchr(dot11_ds, *sub1) != NULL) &&
+         (strchr(dot11_ds, *sub2) != NULL) )
+       return(1);
+    }
+  /* Not compatible */
+  return(0);
+}
+
 /********************** FREQUENCY SUBROUTINES ***********************/
 /********************** 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
+ */
 
 /*------------------------------------------------------------------*/
 /*
 
 /*------------------------------------------------------------------*/
 /*
@@ -439,6 +648,17 @@ void
 iw_float2freq(double   in,
              iwfreq *  out)
 {
 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->e = (short) (floor(log10(in)));
   if(out->e > 8)
     {
@@ -447,9 +667,10 @@ iw_float2freq(double       in,
     }
   else
     {
     }
   else
     {
-      out->m = in;
+      out->m = (long) in;
       out->e = 0;
     }
       out->e = 0;
     }
+#endif /* WE_NOLIBM */
 }
 
 /*------------------------------------------------------------------*/
 }
 
 /*------------------------------------------------------------------*/
@@ -459,7 +680,17 @@ iw_float2freq(double       in,
 double
 iw_freq2float(iwfreq * in)
 {
 double
 iw_freq2float(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);
   return ((double) in->m) * pow(10,in->e);
+#endif /* WE_NOLIBM */
 }
 
 /*------------------------------------------------------------------*/
 }
 
 /*------------------------------------------------------------------*/
@@ -468,7 +699,7 @@ iw_freq2float(iwfreq *      in)
  */
 void
 iw_print_freq(char *   buffer,
  */
 void
 iw_print_freq(char *   buffer,
-             float     freq)
+             double    freq)
 {
   if(freq < KILO)
     sprintf(buffer, "Channel:%g", freq);
 {
   if(freq < KILO)
     sprintf(buffer, "Channel:%g", freq);
@@ -486,6 +717,33 @@ iw_print_freq(char *       buffer,
     }
 }
 
     }
 }
 
+/*------------------------------------------------------------------*/
+/*
+ * Convert a frequency to a channel (negative -> error)
+ */
+int
+iw_freq_to_channel(double              freq,
+                  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);
+}
+
 /*********************** BITRATE SUBROUTINES ***********************/
 
 /*------------------------------------------------------------------*/
 /*********************** BITRATE SUBROUTINES ***********************/
 
 /*------------------------------------------------------------------*/
@@ -700,6 +958,21 @@ iw_print_key(char *                buffer,
 
 /*------------------------------------------------------------------*/
 /*
 
 /*------------------------------------------------------------------*/
 /*
+ * Convert a passphrase into a key
+ * ### NOT IMPLEMENTED ###
+ * Return size of the key, or 0 (no key) or -1 (error)
+ */
+int
+iw_pass_key(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)
  */
  * Parse a key from the command line.
  * Return size of the key, or 0 (no key) or -1 (error)
  */
@@ -715,38 +988,44 @@ iw_in_key(char *          input,
   /* Check the type of key */
   if(!strncmp(input, "s:", 2))
     {
   /* Check the type of key */
   if(!strncmp(input, "s:", 2))
     {
-      /* First case : as an ASCII string */
+      /* 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;
       strncpy(key, input + 2, keylen);
     }
   else
       keylen = strlen(input + 2);              /* skip "s:" */
       if(keylen > IW_ENCODING_TOKEN_MAX)
        keylen = IW_ENCODING_TOKEN_MAX;
       strncpy(key, input + 2, keylen);
     }
   else
-    {
-      /* Second case : as hexadecimal digits */
-      buff = malloc(strlen(input) + 1);
-      if(buff == NULL)
-       {
-         fprintf(stderr, "Malloc failed (string too long ?)\n");
-         return(-1);
-       }
-      /* Preserve original buffer */
-      strcpy(buff, input);
-
-      /* Parse */
-      p = strtok(buff, "-:;.,");
-      while((p != (char *) NULL) && (keylen < IW_ENCODING_TOKEN_MAX))
-       {
-         if(sscanf(p, "%2X", &temp) != 1)
-           return(-1);         /* Error */
-         key[keylen++] = (unsigned char) (temp & 0xFF);
-         if(strlen(p) > 2)     /* Token not finished yet */
-           p += 2;
-         else
-           p = strtok((char *) NULL, "-:;.,");
-       }
-      free(buff);
-    }
+    if(!strncmp(input, "p:", 2))
+      {
+       /* Second case : as a passphrase (PrismII cards) */
+       return(iw_pass_key(input + 2, key));            /* skip "p:" */
+      }
+    else
+      {
+       /* Third case : as hexadecimal digits */
+       buff = malloc(strlen(input) + 1);
+       if(buff == NULL)
+         {
+           fprintf(stderr, "Malloc failed (string too long ?)\n");
+           return(-1);
+         }
+       /* Preserve original buffer */
+       strcpy(buff, input);
+
+       /* Parse */
+       p = strtok(buff, "-:;.,");
+       while((p != (char *) NULL) && (keylen < IW_ENCODING_TOKEN_MAX))
+         {
+           if(sscanf(p, "%2X", &temp) != 1)
+             return(-1);               /* Error */
+           key[keylen++] = (unsigned char) (temp & 0xFF);
+           if(strlen(p) > 2)   /* Token not finished yet */
+             p += 2;
+           else
+             p = strtok((char *) NULL, "-:;.,");
+         }
+       free(buff);
+      }
 
   return(keylen);
 }
 
   return(keylen);
 }
@@ -1094,6 +1373,7 @@ iw_in_inet(char *name, struct sockaddr *sap)
        return(1);
   }
 
        return(1);
   }
 
+  /* Always use the resolver (DNS name + IP addresses) */
   if ((hp = gethostbyname(name)) == (struct hostent *)NULL) {
        errno = h_errno;
        return(-1);
   if ((hp = gethostbyname(name)) == (struct hostent *)NULL) {
        errno = h_errno;
        return(-1);
@@ -1186,23 +1466,29 @@ iw_in_addr(int          skfd,
 
 /************************* MISC SUBROUTINES **************************/
 
 
 /************************* 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
 /*------------------------------------------------------------------*/
 /*
  * Max size in bytes of an private argument.
  */
 int
-iw_byte_size(int       args)
+iw_get_priv_size(int   args)
 {
 {
-  int  ret = args & IW_PRIV_SIZE_MASK;
+  int  num = args & IW_PRIV_SIZE_MASK;
+  int  type = (args & IW_PRIV_TYPE_MASK) >> 12;
 
 
-  if(((args & IW_PRIV_TYPE_MASK) == IW_PRIV_TYPE_INT) ||
-     ((args & IW_PRIV_TYPE_MASK) == IW_PRIV_TYPE_FLOAT))
-    ret <<= 2;
-
-  if((args & IW_PRIV_TYPE_MASK) == IW_PRIV_TYPE_NONE)
-    return 0;
-
-  return ret;
+  return(num * priv_type_size[type]);
 }
 
 /************************ EVENT SUBROUTINES ************************/
 }
 
 /************************ EVENT SUBROUTINES ************************/
@@ -1219,10 +1505,10 @@ iw_byte_size(int        args)
 #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_CHAR    2       /* char [IFNAMSIZ] */
 #define IW_HEADER_TYPE_UINT    4       /* __u32 */
 #define IW_HEADER_TYPE_FREQ    5       /* struct iw_freq */
-#define IW_HEADER_TYPE_POINT   6       /* struct iw_point */
-#define IW_HEADER_TYPE_PARAM   7       /* struct iw_param */
-#define IW_HEADER_TYPE_ADDR    8       /* struct sockaddr */
-#define IW_HEADER_TYPE_QUAL          /* struct iw_quality */
+#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 */
 
 /* Headers for the various requests */
 static const char standard_ioctl_hdr[] = {
 
 /* Headers for the various requests */
 static const char standard_ioctl_hdr[] = {
@@ -1282,21 +1568,25 @@ static const unsigned int standard_ioctl_num = sizeof(standard_ioctl_hdr);
 static const char      standard_event_hdr[] = {
        IW_HEADER_TYPE_ADDR,    /* IWEVTXDROP */
        IW_HEADER_TYPE_QUAL,    /* IWEVQUAL */
 static const char      standard_event_hdr[] = {
        IW_HEADER_TYPE_ADDR,    /* IWEVTXDROP */
        IW_HEADER_TYPE_QUAL,    /* IWEVQUAL */
+       IW_HEADER_TYPE_POINT,   /* IWEVCUSTOM */
+       IW_HEADER_TYPE_ADDR,    /* IWEVREGISTERED */
+       IW_HEADER_TYPE_ADDR,    /* IWEVEXPIRED */
 };
 static const unsigned int standard_event_num = sizeof(standard_event_hdr);
 
 /* Size (in bytes) of various events */
 static const int event_type_size[] = {
 };
 static const unsigned int standard_event_num = sizeof(standard_event_hdr);
 
 /* Size (in bytes) of various events */
 static const int event_type_size[] = {
-       IW_EV_LCP_LEN,
+       IW_EV_LCP_LEN,          /* IW_HEADER_TYPE_NULL */
        0,
        0,
-       IW_EV_CHAR_LEN,
+       IW_EV_CHAR_LEN,         /* IW_HEADER_TYPE_CHAR */
        0,
        0,
-       IW_EV_UINT_LEN,
-       IW_EV_FREQ_LEN,
-       IW_EV_POINT_LEN,                /* Without variable payload */
-       IW_EV_PARAM_LEN,
-       IW_EV_ADDR_LEN,
-       IW_EV_QUAL_LEN,
+       IW_EV_UINT_LEN,         /* IW_HEADER_TYPE_UINT */
+       IW_EV_FREQ_LEN,         /* IW_HEADER_TYPE_FREQ */
+       IW_EV_ADDR_LEN,         /* IW_HEADER_TYPE_ADDR */
+       0,
+       IW_EV_POINT_LEN,        /* Without variable payload */
+       IW_EV_PARAM_LEN,        /* IW_HEADER_TYPE_PARAM */
+       IW_EV_QUAL_LEN,         /* IW_HEADER_TYPE_QUAL */
 };
 
 /*------------------------------------------------------------------*/
 };
 
 /*------------------------------------------------------------------*/
@@ -1326,7 +1616,7 @@ iw_extract_event_stream(struct stream_descr *     stream, /* Stream of events */
                        struct iw_event *       iwe)    /* Extracted event */
 {
   int          event_type = 0;
                        struct iw_event *       iwe)    /* Extracted event */
 {
   int          event_type = 0;
-  int          event_len = 1;          /* Invalid */
+  unsigned int event_len = 1;          /* Invalid */
   char *       pointer;
   /* Don't "optimise" the following variable, it will crash */
   unsigned     cmd_index;              /* *MUST* be unsigned */
   char *       pointer;
   /* Don't "optimise" the following variable, it will crash */
   unsigned     cmd_index;              /* *MUST* be unsigned */
@@ -1349,7 +1639,11 @@ iw_extract_event_stream(struct stream_descr *    stream, /* Stream of events */
         iwe->cmd, iwe->len);
 #endif
 
         iwe->cmd, iwe->len);
 #endif
 
-   /* Get the type and length of that event */
+  /* Check invalid events */
+  if(iwe->len <= IW_EV_LCP_LEN)
+    return(-1);
+
+  /* Get the type and length of that event */
   if(iwe->cmd <= SIOCIWLAST)
     {
       cmd_index = iwe->cmd - SIOCIWFIRST;
   if(iwe->cmd <= SIOCIWLAST)
     {
       cmd_index = iwe->cmd - SIOCIWFIRST;
@@ -1362,11 +1656,16 @@ iw_extract_event_stream(struct stream_descr *   stream, /* Stream of events */
       if(cmd_index < standard_event_num)
        event_type = standard_event_hdr[cmd_index];
     }
       if(cmd_index < standard_event_num)
        event_type = standard_event_hdr[cmd_index];
     }
+  /* Unknown events -> event_type=0 => IW_EV_LCP_LEN */
   event_len = event_type_size[event_type];
 
   /* Check if we know about this event */
   event_len = event_type_size[event_type];
 
   /* Check if we know about this event */
-  if((event_len == 0) || (iwe->len == 0))
-    return(-1);
+  if(event_len <= IW_EV_LCP_LEN)
+    {
+      /* Skip to next event */
+      stream->current += iwe->len;
+      return(2);
+    }
   event_len -= IW_EV_LCP_LEN;
 
   /* Set pointer on data */
   event_len -= IW_EV_LCP_LEN;
 
   /* Set pointer on data */
@@ -1382,7 +1681,11 @@ iw_extract_event_stream(struct stream_descr *    stream, /* Stream of events */
 
   /* Copy the rest of the event (at least, fixed part) */
   if((pointer + event_len) > stream->end)
 
   /* Copy the rest of the event (at least, fixed part) */
   if((pointer + event_len) > stream->end)
-    return(-2);
+    {
+      /* Go to next event */
+      stream->current += iwe->len;
+      return(-2);
+    }
   memcpy((char *) iwe + IW_EV_LCP_LEN, pointer, event_len);
 
   /* Skip event in the stream */
   memcpy((char *) iwe + IW_EV_LCP_LEN, pointer, event_len);
 
   /* Skip event in the stream */
@@ -1399,7 +1702,7 @@ iw_extract_event_stream(struct stream_descr *     stream, /* Stream of events */
        /* No data */
        iwe->u.data.pointer = NULL;
 
        /* No data */
        iwe->u.data.pointer = NULL;
 
-       /* Go to next event */
+      /* Go to next event */
       stream->current += iwe->len;
     }
   else
       stream->current += iwe->len;
     }
   else
index 475e67e..5818a08 100644 (file)
 #include <linux/in.h>          /* For struct sockaddr_in */
 #endif /* LIBC5_HEADERS */
 
 #include <linux/in.h>          /* For struct sockaddr_in */
 #endif /* LIBC5_HEADERS */
 
-#ifdef PRIVATE_WE_HEADER
+#ifdef WEXT_HEADER
 /* Private copy of Wireless extensions */
 /* Private copy of Wireless extensions */
-#include "wireless.h"
-#else  /* PRIVATE_WE_HEADER */
+#include WEXT_HEADER
+#else  /* !WEXT_HEADER */
 /* System wide Wireless extensions */
 #include <linux/wireless.h>
 /* System wide Wireless extensions */
 #include <linux/wireless.h>
-#endif /* PRIVATE_WE_HEADER */
-
-#if WIRELESS_EXT < 9
-#error "Wireless Extension v9 or newer required :-( - \
-Use Wireless Tools v19 or update your kernel headers"
-#endif
-#if WIRELESS_EXT < 14
-#warning "Wireless Extension v14 recommended (but not mandatory)... - \
-You may update your kernel and/or system headers to get the new features, \
-or you may just ignore this message"
-#endif
+#endif /* !WEXT_HEADER */
 
 /****************************** DEBUG ******************************/
 
 
 /****************************** DEBUG ******************************/
 
@@ -147,6 +137,7 @@ or you may just ignore this message"
 
 /* Paths */
 #define PROC_NET_WIRELESS      "/proc/net/wireless"
 
 /* Paths */
 #define PROC_NET_WIRELESS      "/proc/net/wireless"
+#define PROC_NET_DEV           "/proc/net/dev"
 
 /* Some usefull constants */
 #define KILO   1e3
 
 /* Some usefull constants */
 #define KILO   1e3
@@ -186,11 +177,11 @@ typedef struct sockaddr           sockaddr;
  * This is pretty exhaustive... */
 typedef struct wireless_info
 {
  * This is pretty exhaustive... */
 typedef struct wireless_info
 {
-  char         name[IFNAMSIZ];         /* Wireless/protocol name */
+  char         name[IFNAMSIZ + 1];     /* Wireless/protocol name */
   int          has_nwid;
   iwparam      nwid;                   /* Network ID */
   int          has_freq;
   int          has_nwid;
   iwparam      nwid;                   /* Network ID */
   int          has_freq;
-  float                freq;                   /* Frequency/channel */
+  double       freq;                   /* Frequency/channel */
   int          has_sens;
   iwparam      sens;                   /* sensitivity */
   int          has_key;
   int          has_sens;
   iwparam      sens;                   /* sensitivity */
   int          has_key;
@@ -232,11 +223,11 @@ typedef struct wireless_info
  * Don't add other junk, I'll remove it... */
 typedef struct wireless_config
 {
  * Don't add other junk, I'll remove it... */
 typedef struct wireless_config
 {
-  char         name[IFNAMSIZ];         /* Wireless/protocol name */
+  char         name[IFNAMSIZ + 1];     /* Wireless/protocol name */
   int          has_nwid;
   iwparam      nwid;                   /* Network ID */
   int          has_freq;
   int          has_nwid;
   iwparam      nwid;                   /* Network ID */
   int          has_freq;
-  float                freq;                   /* Frequency/channel */
+  double       freq;                   /* Frequency/channel */
   int          has_key;
   unsigned char        key[IW_ENCODING_TOKEN_MAX];     /* Encoding key used */
   int          key_size;               /* Number of bytes */
   int          has_key;
   unsigned char        key[IW_ENCODING_TOKEN_MAX];     /* Encoding key used */
   int          key_size;               /* Number of bytes */
@@ -280,9 +271,12 @@ int
                          char *        ifname,
                          iwrange *     range);
 int
                          char *        ifname,
                          iwrange *     range);
 int
+       iw_print_version_info(char *    toolname);
+int
        iw_get_priv_info(int            skfd,
                         char *         ifname,
        iw_get_priv_info(int            skfd,
                         char *         ifname,
-                        iwprivargs *   priv);
+                        iwprivargs *   priv,
+                        int            maxpriv);
 int
        iw_get_basic_config(int                 skfd,
                            char *              ifname,
 int
        iw_get_basic_config(int                 skfd,
                            char *              ifname,
@@ -291,6 +285,10 @@ int
        iw_set_basic_config(int                 skfd,
                            char *              ifname,
                            wireless_config *   info);
        iw_set_basic_config(int                 skfd,
                            char *              ifname,
                            wireless_config *   info);
+/* --------------------- PROTOCOL SUBROUTINES --------------------- */
+int
+       iw_protocol_compare(char *      protocol1,
+                           char *      protocol2);
 /* -------------------- FREQUENCY SUBROUTINES --------------------- */
 void
        iw_float2freq(double    in,
 /* -------------------- FREQUENCY SUBROUTINES --------------------- */
 void
        iw_float2freq(double    in,
@@ -299,7 +297,10 @@ double
        iw_freq2float(iwfreq *  in);
 void
        iw_print_freq(char *    buffer,
        iw_freq2float(iwfreq *  in);
 void
        iw_print_freq(char *    buffer,
-                     float     freq);
+                     double    freq);
+int
+       iw_freq_to_channel(double               freq,
+                          struct iw_range *    range);
 void
        iw_print_bitrate(char * buffer,
                         int    bitrate);
 void
        iw_print_bitrate(char * buffer,
                         int    bitrate);
@@ -373,7 +374,7 @@ int
                   struct sockaddr *    sap);
 /* ----------------------- MISC SUBROUTINES ------------------------ */
 int
                   struct sockaddr *    sap);
 /* ----------------------- MISC SUBROUTINES ------------------------ */
 int
-       iw_byte_size(int                args);
+       iw_get_priv_size(int            args);
 
 #if WIRELESS_EXT > 13
 /* ---------------------- EVENT SUBROUTINES ---------------------- */
 
 #if WIRELESS_EXT > 13
 /* ---------------------- EVENT SUBROUTINES ---------------------- */
@@ -389,7 +390,7 @@ int
 /**************************** VARIABLES ****************************/
 
 extern const char * const      iw_operation_mode[];
 /**************************** VARIABLES ****************************/
 
 extern const char * const      iw_operation_mode[];
-#define IW_NUM_OPER_MODE       6
+#define IW_NUM_OPER_MODE       7
 
 /************************* INLINE FUNTIONS *************************/
 /*
 
 /************************* INLINE FUNTIONS *************************/
 /*
index 09a4981..3623626 100644 (file)
@@ -26,6 +26,10 @@ iwlist \- Get wireless statistics from specific nodes
 .BI "iwlist " interface " txpower"
 .br
 .BI "iwlist " interface " retry"
 .BI "iwlist " interface " txpower"
 .br
 .BI "iwlist " interface " retry"
+.br
+.BI "iwlist --help"
+.br
+.BI "iwlist --version"
 .\"
 .\" DESCRIPTION part
 .\"
 .\"
 .\" DESCRIPTION part
 .\"
@@ -80,6 +84,11 @@ List the various Transmit Power available on the device.
 .TP
 .B retry
 List the transmit retry limits and retry lifetime on the device.
 .TP
 .B retry
 List the transmit retry limits and retry lifetime on the device.
+.TP
+.B --version
+Display the version of the tools, as well as the recommended and
+current Wireless Extensions version for the tool and the various
+wireless interfaces.
 .\"
 .\" FILES part
 .\"
 .\"
 .\" FILES part
 .\"
index 0703f3e..8b751c2 100644 (file)
@@ -26,13 +26,17 @@ print_freq_info(int         skfd,
                char *          args[],         /* Command line args */
                int             count)          /* Args count */
 {
                char *          args[],         /* Command line args */
                int             count)          /* Args count */
 {
-  float                        freq;
+  struct iwreq         wrq;
   struct iw_range      range;
   struct iw_range      range;
+  double               freq;
   int                  k;
   int                  k;
+  int                  channel;
+  char                 buffer[128];    /* Temporary buffer */
 
   /* Avoid "Unused parameter" warning */
   args = args; count = count;
 
 
   /* Avoid "Unused parameter" warning */
   args = args; count = count;
 
+  /* Get list of frequencies / channels */
   if(iw_get_range_info(skfd, ifname, &range) < 0)
       fprintf(stderr, "%-8.8s  no frequency information.\n\n",
                      ifname);
   if(iw_get_range_info(skfd, ifname, &range) < 0)
       fprintf(stderr, "%-8.8s  no frequency information.\n\n",
                      ifname);
@@ -45,7 +49,7 @@ print_freq_info(int           skfd,
          /* Print them all */
          for(k = 0; k < range.num_frequency; k++)
            {
          /* Print them all */
          for(k = 0; k < range.num_frequency; k++)
            {
-             printf("\t  Channel %.2d : ", range.freq[k].i);
+             printf("          Channel %.2d : ", range.freq[k].i);
              freq = iw_freq2float(&(range.freq[k]));
              if(freq >= GIGA)
                printf("%g GHz\n", freq / GIGA);
              freq = iw_freq2float(&(range.freq[k]));
              if(freq >= GIGA)
                printf("%g GHz\n", freq / GIGA);
@@ -55,16 +59,31 @@ print_freq_info(int         skfd,
                else
                  printf("%g kHz\n", freq / KILO);
            }
                else
                  printf("%g kHz\n", freq / KILO);
            }
-         printf("\n\n");
        }
       else
        }
       else
-       printf("%-8.8s  %d channels\n\n",
+       printf("%-8.8s  %d channels\n",
               ifname, range.num_channels);
               ifname, range.num_channels);
+
+      /* Get current frequency / channel and display it */
+      if(iw_get_ext(skfd, ifname, SIOCGIWFREQ, &wrq) >= 0)
+       {
+         freq = iw_freq2float(&(wrq.u.freq));
+         iw_print_freq(buffer, freq);
+         channel = iw_freq_to_channel(freq, &range);
+         if(channel >= 0)
+           printf("          Current %s (channel %.2d)\n\n", buffer, channel);
+         else
+           printf("          Current %s\n\n", buffer);
+       }
     }
   return(0);
 }
 
 /************************ ACCESS POINT LIST ************************/
     }
   return(0);
 }
 
 /************************ ACCESS POINT LIST ************************/
+/*
+ * Note : now that we have scanning support, this is depracted and
+ * won't survive long. Actually, next version it's out !
+ */
 
 /*------------------------------------------------------------------*/
 /*
 
 /*------------------------------------------------------------------*/
 /*
@@ -155,6 +174,7 @@ print_bitrate_info(int              skfd,
                   char *       args[],         /* Command line args */
                   int          count)          /* Args count */
 {
                   char *       args[],         /* Command line args */
                   int          count)          /* Args count */
 {
+  struct iwreq         wrq;
   struct iw_range      range;
   int                  k;
   char                 buffer[128];
   struct iw_range      range;
   int                  k;
   char                 buffer[128];
@@ -179,10 +199,17 @@ print_bitrate_info(int            skfd,
              /* Maybe this should be %10s */
              printf("\t  %s\n", buffer);
            }
              /* Maybe this should be %10s */
              printf("\t  %s\n", buffer);
            }
-         printf("\n\n");
        }
       else
        }
       else
-       printf("%-8.8s  No bit-rates ? Please update driver...\n\n", ifname);
+       printf("%-8.8s  No bit-rates ? Please update driver...\n", ifname);
+
+      /* Get current bit rate */
+      if(iw_get_ext(skfd, ifname, SIOCGIWRATE, &wrq) >= 0)
+       {
+         iw_print_bitrate(buffer, wrq.u.bitrate.value);
+         printf("          Current Bit Rate%c%s\n\n",
+                (wrq.u.bitrate.fixed ? '=' : ':'), buffer);
+       }
     }
   return(0);
 }
     }
   return(0);
 }
@@ -454,6 +481,7 @@ print_txpower_info(int              skfd,
                   char *       args[],         /* Command line args */
                   int          count)          /* Args count */
 {
                   char *       args[],         /* Command line args */
                   int          count)          /* Args count */
 {
+  struct iwreq         wrq;
   struct iw_range      range;
   int                  dbm;
   int                  mwatt;
   struct iw_range      range;
   int                  dbm;
   int                  mwatt;
@@ -469,7 +497,9 @@ print_txpower_info(int              skfd,
                      ifname);
   else
     {
                      ifname);
   else
     {
-      if((range.num_txpower > 0) && (range.num_txpower < IW_MAX_TXPOWER))
+      if((range.num_txpower <= 0) || (range.num_txpower > IW_MAX_TXPOWER))
+       printf("%-8.8s  No transmit-powers ? Please update driver...\n\n", ifname);
+      else
        {
          printf("%-8.8s  %d available transmit-powers :\n",
                 ifname, range.num_txpower);
        {
          printf("%-8.8s  %d available transmit-powers :\n",
                 ifname, range.num_txpower);
@@ -488,10 +518,35 @@ print_txpower_info(int            skfd,
                }
              printf("\t  %d dBm  \t(%d mW)\n", dbm, mwatt);
            }
                }
              printf("\t  %d dBm  \t(%d mW)\n", dbm, mwatt);
            }
-         printf("\n\n");
+
+         /* Get current Transmit Power */
+         if(iw_get_ext(skfd, ifname, SIOCGIWTXPOW, &wrq) >= 0)
+           {
+             printf("          Current Tx-Power");
+             /* Disabled ? */
+             if(wrq.u.txpower.disabled)
+               printf(":off\n\n");
+             else
+               {
+                 /* Fixed ? */
+                 if(wrq.u.txpower.fixed)
+                   printf("=");
+                 else
+                   printf(":");
+                 if(wrq.u.txpower.flags & IW_TXPOW_MWATT)
+                   {
+                     dbm = iw_mwatt2dbm(wrq.u.txpower.value);
+                     mwatt = wrq.u.txpower.value;
+                   }
+                 else
+                   {
+                     dbm = wrq.u.txpower.value;
+                     mwatt = iw_dbm2mwatt(wrq.u.txpower.value);
+                   }
+                 printf("%d dBm  \t(%d mW)\n\n", dbm, mwatt);
+               }
+           }
        }
        }
-      else
-       printf("%-8.8s  No transmit-powers ? Please update driver...\n\n", ifname);
     }
 #endif /* WIRELESS_EXT > 9 */
   return(0);
     }
 #endif /* WIRELESS_EXT > 9 */
   return(0);
@@ -680,7 +735,7 @@ print_scanning_token(struct iw_event *      event,  /* Extracted token */
       break;
     case SIOCGIWFREQ:
       {
       break;
     case SIOCGIWFREQ:
       {
-       float           freq;                   /* Frequency/channel */
+       double          freq;                   /* Frequency/channel */
        freq = iw_freq2float(&(event->u.freq));
        iw_print_freq(buffer, freq);
        printf("                    %s\n", buffer);
        freq = iw_freq2float(&(event->u.freq));
        iw_print_freq(buffer, freq);
        printf("                    %s\n", buffer);
@@ -748,6 +803,17 @@ print_scanning_token(struct iw_event *     event,  /* Extracted token */
        printf("                    %s\n", buffer);
        break;
       }
        printf("                    %s\n", buffer);
        break;
       }
+#if WIRELESS_EXT > 14
+    case IWEVCUSTOM:
+      {
+       char custom[IW_CUSTOM_MAX+1];
+       if((event->u.data.pointer) && (event->u.data.length))
+         memcpy(custom, event->u.data.pointer, event->u.data.length);
+       custom[event->u.data.length] = '\0';
+       printf("                    Extra:%s\n", custom);
+      }
+      break;
+#endif /* WIRELESS_EXT > 14 */
     default:
       printf("                    (Unknown Wireless Token 0x%04X)\n",
             event->cmd);
     default:
       printf("                    (Unknown Wireless Token 0x%04X)\n",
             event->cmd);
@@ -1021,6 +1087,10 @@ main(int argc,
   if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))
     iw_usage(0);
 
   if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))
     iw_usage(0);
 
+  /* This is also handled slightly differently */
+  if (!strcmp(argv[1], "-v") || !strcmp(argv[1], "--version"))
+    return(iw_print_version_info("iwlist"));
+
   if (argc == 2)
     {
       cmd = argv[1];
   if (argc == 2)
     {
       cmd = argv[1];
index 2f51651..d662840 100644 (file)
@@ -14,7 +14,11 @@ network interface
 .SH SYNOPSIS
 .BI "iwpriv [" interface ]
 .br
 .SH SYNOPSIS
 .BI "iwpriv [" interface ]
 .br
-.BI "iwpriv " interface " " private-command " [" private-parameters ]
+.BI "iwpriv " "interface private-command " "[" private-parameters ]
+.br
+.BI "iwpriv " "interface private-command [I] " "[" private-parameters ]
+.br
+.BI "iwpriv " interface " --all"
 .br
 .BI "iwpriv " interface " roam " {on,off}
 .br
 .br
 .BI "iwpriv " interface " roam " {on,off}
 .br
@@ -29,9 +33,7 @@ is the companion tool to
 .B Iwpriv
 deals with parameters and setting specific to each driver (as opposed to
 .I iwconfig
 .B Iwpriv
 deals with parameters and setting specific to each driver (as opposed to
 .I iwconfig
-which deals with generic ones) and a few commands that doesn't fit well in
-.I iwconfig
-(like listing the available frequencies).
+which deals with generic ones).
 .PP
 Without any argument,
 .B iwpriv
 .PP
 Without any argument,
 .B iwpriv
@@ -46,6 +48,34 @@ to use those interface specific commands and their effect.
 .\"
 .SH PARAMETERS
 .TP
 .\"
 .SH PARAMETERS
 .TP
+.IR private-command " [" private-parameters ]
+Execute the specified
+.I private-command
+on the interface.
+.br
+The command may optionally take or require arguments, and may display
+information. Therefore, the command line parameters may or may not be
+needed and should match the command expectations. The list of commands
+that
+.B iwpriv
+displays (when called without argument) should give you some hints
+about those parameters.
+.br
+However you should refer to the device driver documentation for
+information on how to properly use the command and the effect.
+.TP
+.I "private-command [I]" "[" private-parameters ]
+Idem, except that
+.I I
+(an integer) is passed to the command as a
+.IR "Token Index" .
+Only some command will use the Token Index (most will ignore it), and
+the driver documentation should tell you when it's needed.
+.TP
+.BR -a / --all
+Execute and display all the private commands that don't take any
+arguments (i.e.  read only).
+.TP
 .B roam
 Enable or disable roaming, if supported. Call the private command
 .IR setroam .
 .B roam
 Enable or disable roaming, if supported. Call the private command
 .IR setroam .
@@ -58,13 +88,6 @@ Read or configure the port type. Call the private commands
 .IR gport_type ", " sport_type ", " get_port " or " set_port
 found in the
 .IR wavelan2_cs " and " wvlan_cs " drivers."
 .IR gport_type ", " sport_type ", " get_port " or " set_port
 found in the
 .IR wavelan2_cs " and " wvlan_cs " drivers."
-.TP
-.I private-command
-Execute the specified
-.I private-command
-on the interface. The command may take or require arguments, and may
-display information. Refer to the device driver documentation for
-information on how to use and the effect.
 .\"
 .\" DISPLAY part
 .\"
 .\"
 .\" DISPLAY part
 .\"
index 333f98f..986ffd8 100644 (file)
 
 #include "iwlib.h"             /* Header */
 
 
 #include "iwlib.h"             /* Header */
 
+/************************** DOCUMENTATION **************************/
+
+/*
+ * IOCTL RANGES :
+ * ------------
+ *     The initial implementation of iwpriv was using the SIOCDEVPRIVATE
+ * ioctl range (up to 16 ioctls - driver specific). However, this was
+ * causing some compatibility problems with other usages of those
+ * ioctls, and those ioctls are supposed to be removed.
+ *     Therefore, I created a new ioctl range, at SIOCIWFIRSTPRIV. Those
+ * ioctls are specific to Wireless Extensions, so you don't have to
+ * worry about collisions with other usages. On the other hand, in the
+ * new range, the SET convention is enforced (see below).
+ *     The differences are :           SIOCDEVPRIVATE  SIOCIWFIRSTPRIV
+ *             o availability :        <= 2.5.X        WE > 11 (>= 2.4.13)
+ *             o collisions            yes             no
+ *             o SET convention        optional        enforced
+ *             o number                16              32
+ *
+ * NEW DRIVER API :
+ * --------------
+ *     Wireless Extension 13 introduce a new driver API. Wireless
+ * Extensions requests can be handled via a iw_handler table instead
+ * of through the regular ioctl handler.
+ *     The new driver API can be handled only with the new ioctl range
+ * and enforce the GET convention (see below).
+ *     The differences are :           old API         new API
+ *             o handler               do_ioctl()      struct iw_handler_def
+ *             o SIOCIWFIRSTPRIV       WE > 11         yes
+ *             o SIOCDEVPRIVATE        yes             no
+ *             o GET convention        optional        enforced
+ *     Note that the new API before Wireless Extension 15 contains bugs
+ * with regards to handling sub-ioctls and addr/float data types.
+ *
+ * SET/GET CONVENTION :
+ * ------------------
+ *     The regular Wireless Extensions use a SET/GET convention, where
+ * the low order bit identify a SET (0) or a GET (1) request.
+ *     The new ioctl range enforce the SET convention : SET request will
+ * be available to root only and can't return any arguments. If you don't
+ * like that, just use every other two ioctl.
+ *     The new driver API enforce the GET convention : GET request won't
+ * be able to accept any arguments (except if its fits within (union
+ * iwreq_data)). If you don't like that, just use the old API (aka the
+ * ioctl handler).
+ *     In any case, it's a good idea to not have ioctl with both SET
+ * and GET arguments. If the GET arguments doesn't fit within
+ * (union iwreq_data) and SET do, or vice versa, the current code in iwpriv
+ * won't work. One exception is if both SET and GET arguments fit within
+ * (union iwreq_data), this case should be handled safely in a GET
+ * request.
+ *
+ * SUB-IOCTLS :
+ * ----------
+ *     Wireless Extension 15 introduce sub-ioctls. For some applications,
+ * 32 ioctl is not enough, and this simple mechanism allow to increase
+ * the number of ioctls by adding a sub-ioctl index to some of the ioctl
+ * (so basically a two level addressing).
+ *     One might argue that at the point, some other mechanisms might be
+ * better, like using a real filesystem abstraction (/proc, driverfs, ...),
+ * but sub-ioctls are simple enough to not have much drawbacks (which means
+ * that it's a quick and dirty hack ;-).
+ *
+ *     There is two slightly different variation of the sub-ioctl scheme :
+ *     If the payload fit within (union iwreq_data), the first int (4 bytes)
+ * is reserved as the sub-ioctl number and the regular payload shifted by
+ * 4 bytes.
+ *     If the ioctl use (struct iw_point), the sub-ioctl number is in the
+ * flags member of the structure.
+ *     Then, in your handler you would just extract the sub-ioctl number
+ * and do the appropriate processing.
+ *
+ *     Sub-ioctls are declared normally in the private definition table,
+ * with cmd (first arg) beeing the sub-ioctl number. Then, you need to
+ * declare the real ioctl which will process the sub-ioctls with the
+ * SAME ARGUMENTS and a NULL NAME.
+ *     It could look like, for example :
+ * --------------------------------------------
+       // --- Raw access to sub-ioctl handlers ---
+       { 0x8BE0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "set_paramN" },
+       { 0x8BE1, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+         IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_paramN" },
+       // --- sub-ioctls handlers ---
+       { 0x8BE0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "" },
+       { 0x8BE1, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "" },
+       // --- sub-ioctls definitions ---
+       { 1, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_param1" },
+       { 1, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_param1" },
+       { 2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_param2" },
+       { 2, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_param2" },
+ * --------------------------------------------
+ *     And iwpriv should do the rest for you ;-)
+ *
+ *     Note that version of iwpriv up to v24 (included) expect at most
+ * 16 ioctls definitions and will likely crash when given more.
+ *     There is no fix that I can see, apart from recommending an upgrade
+ * of Wireless Tools. Wireless Extensions 15 will check this condition, so
+ * another workaround is restricting those extra definitions to WE-15.
+ *
+ *     Another problem is that new API before Wireless Extension 15
+ * will get it wrong when passing fixed arguments of 12-15 bytes. It will
+ * try to get them inline instead of by pointer. You can fool the new API
+ * to do the right thing using fake ioctl definitions (but remember that
+ * you will get more likely to hit the limit of 16 ioctl definitions).
+ *     For safety, use the ioctl handler before v15.
+ *
+ * NEW DATA TYPES (ADDR/FLOAT) :
+ * ---------------------------
+ *     Wireless Tools 25 introduce two new data types, addr and float,
+ * corresponding to struct sockaddr and struct iwfreq.
+ *     Those types are properly handled with Wireless Extensions 15.
+ * However, the new API before v15 won't handle them properly.
+ *
+ *     The first problem is that the new API won't know their size, so
+ * won't copy them. This can be workaround with a fake ioctl definition.
+ *     The second problem is that a fixed single addr won't be inlined
+ * in struct iwreq and will be passed as a pointer. This is due to an
+ * off-by-one error, where all fixed data of 16 bytes is considered too
+ * big to fit in struct iwreq.
+ *
+ *     For those reasons, I would recommend to use the ioctl handler
+ * before v15 when manipulating those data.
+ *
+ * TOKEN INDEX :
+ * -----------
+ *     Token index is very similar to sub-ioctl. It allow the user
+ * to specify an integer index in front of a bunch of other arguments
+ * (addresses, strings, ...).
+ *     Token index works only with data passed as pointer, and is
+ * otherwise ignored. If your data would fit within struct iwreq, you
+ * need to declare the command *without* IW_PRIV_SIZE_FIXED to force
+ * this to happen (and check arg number yourself).
+ * --------------------------------------------
+       // --- Commands that would fit in struct iwreq ---
+       { 0x8BE0, IW_PRIV_TYPE_ADDR | 1, 0, "set_param_with_token" },
+       // --- No problem here ---
+       { 0x8BE1, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 2, 0, "again" },
+ * --------------------------------------------
+ *     The token index feature is pretty transparent, the token index
+ * will just be in the flags member of (struct iw_point). Default value
+ * (if the user doesn't specify it) will be 0. Token index itself will
+ * work with any version of Wireless Extensions.
+ *     Token index is not compatible with sub-ioctl (both use the same
+ * field of struct iw_point). However, token index can be use to offer
+ * raw access to the sub-ioctl handlers (if it uses struct iw_point) :
+ * --------------------------------------------
+       // --- sub-ioctls handler ---
+       { 0x8BE0, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "" },
+       // --- sub-ioctls definitions ---
+       { 0, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "setaddr" },
+       { 1, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "deladdr" },
+       // --- raw access with token index (+ iwreq workaround) ---
+       { 0x8BE0, IW_PRIV_TYPE_ADDR | 1, 0, "rawaddr" },
+ * --------------------------------------------
+ *
+ * Jean II
+ */
+
 /**************************** CONSTANTS ****************************/
 
 static const char *    argtype[] = {
 /**************************** CONSTANTS ****************************/
 
 static const char *    argtype[] = {
-  "    ", "byte", "char", "", "int ", "float" };
+  "     ", "byte ", "char ", "", "int  ", "float", "addr " };
+
+#define IW_MAX_PRIV_DEF        128
+
+/* Backward compatibility */
+#ifndef IW_PRIV_TYPE_ADDR
+#define IW_PRIV_TYPE_ADDR      0x6000
+#endif /* IW_PRIV_TYPE_ADDR */
 
 /************************* MISC SUBROUTINES **************************/
 
 
 /************************* MISC SUBROUTINES **************************/
 
@@ -32,52 +197,6 @@ iw_usage(void)
   fprintf(stderr, "              interface [port {ad-hoc|managed|N}]\n");
 }
 
   fprintf(stderr, "              interface [port {ad-hoc|managed|N}]\n");
 }
 
-/************************ GENERIC FUNCTIONS *************************/
-
-/*------------------------------------------------------------------*/
-/*
- * Print on the screen in a neat fashion all the info we have collected
- * on a device.
- */
-static int
-print_priv_info(int            skfd,
-               char *          ifname,
-               char *          args[],
-               int             count)
-{
-  int          k;
-  iwprivargs   priv[32];
-  int          n;
-
-  /* Avoid "Unused parameter" warning */
-  args = args; count = count;
-
-  /* Read the private ioctls */
-  n = iw_get_priv_info(skfd, ifname, priv);
-
-  /* Is there any ? */
-  if(n <= 0)
-    {
-      /* Could skip this message ? */
-      fprintf(stderr, "%-8.8s  no private ioctls.\n\n",
-             ifname);
-    }
-  else
-    {
-      printf("%-8.8s  Available private ioctl :\n", ifname);
-      /* Print them all */
-      for(k = 0; k < n; k++)
-       printf("          %s (%X) : set %3d %s & get %3d %s\n",
-              priv[k].name, priv[k].cmd,
-              priv[k].set_args & IW_PRIV_SIZE_MASK,
-              argtype[(priv[k].set_args & IW_PRIV_TYPE_MASK) >> 12],
-              priv[k].get_args & IW_PRIV_SIZE_MASK,
-              argtype[(priv[k].get_args & IW_PRIV_TYPE_MASK) >> 12]);
-      printf("\n");
-    }
-  return(0);
-}
-
 /************************* SETTING ROUTINES **************************/
 
 /*------------------------------------------------------------------*/
 /************************* SETTING ROUTINES **************************/
 
 /*------------------------------------------------------------------*/
@@ -85,44 +204,71 @@ print_priv_info(int                skfd,
  * Execute a private command on the interface
  */
 static int
  * Execute a private command on the interface
  */
 static int
-set_private(int                skfd,           /* Socket */
-           char *      args[],         /* Command line args */
-           int         count,          /* Args count */
-           char *      ifname)         /* Dev name */
+set_private_cmd(int            skfd,           /* Socket */
+               char *          args[],         /* Command line args */
+               int             count,          /* Args count */
+               char *          ifname,         /* Dev name */
+               char *          cmdname,        /* Command name */
+               iwprivargs *    priv,           /* Private ioctl description */
+               int             priv_num)       /* Number of descriptions */
 {
 {
-  u_char       buffer[1024];
-  struct iwreq         wrq;
-  int          i = 0;          /* Start with first arg */
-  int          k;
-  iwprivargs   priv[16];
-  int          number;
+  struct iwreq wrq;
+  u_char       buffer[4096];   /* Only that big in v25 and later */
+  int          i = 0;          /* Start with first command arg */
+  int          k;              /* Index in private description table */
   int          temp;
   int          temp;
+  int          subcmd = 0;     /* sub-ioctl index */
+  int          offset = 0;     /* Space for sub-ioctl index */
 
 
-  /* Read the private ioctls */
-  number = iw_get_priv_info(skfd, ifname, priv);
-
-  /* Is there any ? */
-  if(number <= 0)
+  /* Check if we have a token index.
+   * Do it know so that sub-ioctl takes precendence, and so that we
+   * don't have to bother with it later on... */
+  if((count > 1) && (sscanf(args[0], "[%d]", &temp) == 1))
     {
     {
-      /* Could skip this message ? */
-      fprintf(stderr, "%-8.8s  no private ioctls.\n\n",
-             ifname);
-      return(-1);
+      subcmd = temp;
+      args++;
+      count--;
     }
 
   /* Search the correct ioctl */
   k = -1;
     }
 
   /* Search the correct ioctl */
   k = -1;
-  while((++k < number) && strcmp(priv[k].name, args[i]));
+  while((++k < priv_num) && strcmp(priv[k].name, cmdname));
 
   /* If not found... */
 
   /* If not found... */
-  if(k == number)
+  if(k == priv_num)
     {
     {
-      fprintf(stderr, "Invalid command : %s\n", args[i]);
+      fprintf(stderr, "Invalid command : %s\n", cmdname);
       return(-1);
     }
          
       return(-1);
     }
          
-  /* Next arg */
-  i++;
+  /* Watch out for sub-ioctls ! */
+  if(priv[k].cmd < SIOCDEVPRIVATE)
+    {
+      int      j = -1;
+
+      /* Find the matching *real* ioctl */
+      while((++j < priv_num) && ((priv[j].name[0] != '\0') ||
+                                (priv[j].set_args != priv[k].set_args) ||
+                                (priv[j].get_args != priv[k].get_args)));
+
+      /* If not found... */
+      if(j == priv_num)
+       {
+         fprintf(stderr, "Invalid private ioctl definition for : %s\n",
+                 cmdname);
+         return(-1);
+       }
+
+      /* Save sub-ioctl number */
+      subcmd = priv[k].cmd;
+      /* Reserve one int (simplify alignement issues) */
+      offset = sizeof(__u32);
+      /* Use real ioctl definition from now on */
+      k = j;
+
+      printf("<mapping sub-ioctl %s to cmd 0x%X-%d>\n", cmdname,
+            priv[k].cmd, subcmd);
+    }
 
   /* If we have to set some data */
   if((priv[k].set_args & IW_PRIV_TYPE_MASK) &&
 
   /* If we have to set some data */
   if((priv[k].set_args & IW_PRIV_TYPE_MASK) &&
@@ -132,26 +278,28 @@ set_private(int           skfd,           /* Socket */
        {
        case IW_PRIV_TYPE_BYTE:
          /* Number of args to fetch */
        {
        case IW_PRIV_TYPE_BYTE:
          /* Number of args to fetch */
-         wrq.u.data.length = count - 1;
+         wrq.u.data.length = count;
          if(wrq.u.data.length > (priv[k].set_args & IW_PRIV_SIZE_MASK))
            wrq.u.data.length = priv[k].set_args & IW_PRIV_SIZE_MASK;
 
          /* Fetch args */
          if(wrq.u.data.length > (priv[k].set_args & IW_PRIV_SIZE_MASK))
            wrq.u.data.length = priv[k].set_args & IW_PRIV_SIZE_MASK;
 
          /* Fetch args */
-         for(; i < wrq.u.data.length + 1; i++) {
+         for(; i < wrq.u.data.length; i++) {
            sscanf(args[i], "%d", &temp);
            sscanf(args[i], "%d", &temp);
-           buffer[i - 1] = (char) temp;
+           buffer[i] = (char) temp;
          }
          break;
 
        case IW_PRIV_TYPE_INT:
          /* Number of args to fetch */
          }
          break;
 
        case IW_PRIV_TYPE_INT:
          /* Number of args to fetch */
-         wrq.u.data.length = count - 1;
+         wrq.u.data.length = count;
          if(wrq.u.data.length > (priv[k].set_args & IW_PRIV_SIZE_MASK))
            wrq.u.data.length = priv[k].set_args & IW_PRIV_SIZE_MASK;
 
          /* Fetch args */
          if(wrq.u.data.length > (priv[k].set_args & IW_PRIV_SIZE_MASK))
            wrq.u.data.length = priv[k].set_args & IW_PRIV_SIZE_MASK;
 
          /* Fetch args */
-         for(; i < wrq.u.data.length + 1; i++)
-           sscanf(args[i], "%d", ((u_int *) buffer) + i - 1);
+         for(; i < wrq.u.data.length; i++) {
+           sscanf(args[i], "%d", &temp);
+           ((__s32 *) buffer)[i] = (__s32) temp;
+         }
          break;
 
        case IW_PRIV_TYPE_CHAR:
          break;
 
        case IW_PRIV_TYPE_CHAR:
@@ -174,6 +322,45 @@ set_private(int            skfd,           /* Socket */
            }
          break;
 
            }
          break;
 
+       case IW_PRIV_TYPE_FLOAT:
+         /* Number of args to fetch */
+         wrq.u.data.length = count;
+         if(wrq.u.data.length > (priv[k].set_args & IW_PRIV_SIZE_MASK))
+           wrq.u.data.length = priv[k].set_args & IW_PRIV_SIZE_MASK;
+
+         /* Fetch args */
+         for(; i < wrq.u.data.length; i++) {
+           double              freq;
+           if(sscanf(args[i], "%lg", &(freq)) != 1)
+             {
+               printf("Invalid float [%s]...\n", args[i]);
+               return(-1);
+             }    
+           if(index(args[i], 'G')) freq *= GIGA;
+           if(index(args[i], 'M')) freq *= MEGA;
+           if(index(args[i], 'k')) freq *= KILO;
+           sscanf(args[i], "%d", &temp);
+           iw_float2freq(freq, ((struct iw_freq *) buffer) + i);
+         }
+         break;
+
+       case IW_PRIV_TYPE_ADDR:
+         /* Number of args to fetch */
+         wrq.u.data.length = count;
+         if(wrq.u.data.length > (priv[k].set_args & IW_PRIV_SIZE_MASK))
+           wrq.u.data.length = priv[k].set_args & IW_PRIV_SIZE_MASK;
+
+         /* Fetch args */
+         for(; i < wrq.u.data.length; i++) {
+           if(iw_in_addr(skfd, ifname, args[i],
+                         ((struct sockaddr *) buffer) + i) < 0)
+             {
+               printf("Invalid address [%s]...\n", args[i]);
+               return(-1);
+             }
+         }
+         break;
+
        default:
          fprintf(stderr, "Not yet implemented...\n");
          return(-1);
        default:
          fprintf(stderr, "Not yet implemented...\n");
          return(-1);
@@ -183,7 +370,7 @@ set_private(int             skfd,           /* Socket */
         (wrq.u.data.length != (priv[k].set_args & IW_PRIV_SIZE_MASK)))
        {
          printf("The command %s need exactly %d argument...\n",
         (wrq.u.data.length != (priv[k].set_args & IW_PRIV_SIZE_MASK)))
        {
          printf("The command %s need exactly %d argument...\n",
-                priv[k].name, priv[k].set_args & IW_PRIV_SIZE_MASK);
+                cmdname, priv[k].set_args & IW_PRIV_SIZE_MASK);
          return(-1);
        }
     }  /* if args to set */
          return(-1);
        }
     }  /* if args to set */
@@ -194,20 +381,39 @@ set_private(int           skfd,           /* Socket */
 
   strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
 
 
   strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
 
+  /* Those two tests are important. They define how the driver
+   * will have to handle the data */
   if((priv[k].set_args & IW_PRIV_SIZE_FIXED) &&
   if((priv[k].set_args & IW_PRIV_SIZE_FIXED) &&
-     (iw_byte_size(priv[k].set_args) < IFNAMSIZ))
-    memcpy(wrq.u.name, buffer, IFNAMSIZ);
+      ((iw_get_priv_size(priv[k].set_args) + offset) <= IFNAMSIZ))
+    {
+      /* First case : all SET args fit within wrq */
+      if(offset)
+       wrq.u.mode = subcmd;
+      memcpy(wrq.u.name + offset, buffer, IFNAMSIZ - offset);
+    }
   else
     {
   else
     {
-      wrq.u.data.pointer = (caddr_t) buffer;
-      wrq.u.data.flags = 0;
+      if((priv[k].set_args == 0) &&
+        (priv[k].get_args & IW_PRIV_SIZE_FIXED) &&
+        (iw_get_priv_size(priv[k].get_args) <= IFNAMSIZ))
+       {
+         /* Second case : no SET args, GET args fit within wrq */
+         if(offset)
+           wrq.u.mode = subcmd;
+       }
+      else
+       {
+         /* Thirst case : args won't fit in wrq, or variable number of args */
+         wrq.u.data.pointer = (caddr_t) buffer;
+         wrq.u.data.flags = subcmd;
+       }
     }
 
   /* Perform the private ioctl */
   if(ioctl(skfd, priv[k].cmd, &wrq) < 0)
     {
       fprintf(stderr, "Interface doesn't accept private ioctl...\n");
     }
 
   /* Perform the private ioctl */
   if(ioctl(skfd, priv[k].cmd, &wrq) < 0)
     {
       fprintf(stderr, "Interface doesn't accept private ioctl...\n");
-      fprintf(stderr, "%X: %s\n", priv[k].cmd, strerror(errno));
+      fprintf(stderr, "%s (%X): %s\n", cmdname, priv[k].cmd, strerror(errno));
       return(-1);
     }
 
       return(-1);
     }
 
@@ -218,10 +424,11 @@ set_private(int           skfd,           /* Socket */
       int      j;
       int      n = 0;          /* number of args */
 
       int      j;
       int      n = 0;          /* number of args */
 
-      printf("%-8.8s  %s:", ifname, priv[k].name);
+      printf("%-8.8s  %s:", ifname, cmdname);
 
 
+      /* Check where is the returned data */
       if((priv[k].get_args & IW_PRIV_SIZE_FIXED) &&
       if((priv[k].get_args & IW_PRIV_SIZE_FIXED) &&
-        (iw_byte_size(priv[k].get_args) < IFNAMSIZ))
+        (iw_get_priv_size(priv[k].get_args) <= IFNAMSIZ))
        {
          memcpy(buffer, wrq.u.name, IFNAMSIZ);
          n = priv[k].get_args & IW_PRIV_SIZE_MASK;
        {
          memcpy(buffer, wrq.u.name, IFNAMSIZ);
          n = priv[k].get_args & IW_PRIV_SIZE_MASK;
@@ -241,7 +448,7 @@ set_private(int             skfd,           /* Socket */
        case IW_PRIV_TYPE_INT:
          /* Display args */
          for(j = 0; j < n; j++)
        case IW_PRIV_TYPE_INT:
          /* Display args */
          for(j = 0; j < n; j++)
-           printf("%d  ", ((u_int *) buffer)[j]);
+           printf("%d  ", ((__s32 *) buffer)[j]);
          printf("\n");
          break;
 
          printf("\n");
          break;
 
@@ -251,6 +458,41 @@ set_private(int            skfd,           /* Socket */
          printf("%s\n", buffer);
          break;
 
          printf("%s\n", buffer);
          break;
 
+       case IW_PRIV_TYPE_FLOAT:
+         {
+           double              freq;
+           /* Display args */
+           for(j = 0; j < n; j++)
+             {
+               freq = iw_freq2float(((struct iw_freq *) buffer) + j);
+               if(freq >= GIGA)
+                 printf("%gG  ", freq / GIGA);
+               else
+                 if(freq >= MEGA)
+                 printf("%gM  ", freq / MEGA);
+               else
+                 printf("%gk  ", freq / KILO);
+             }
+           printf("\n");
+         }
+         break;
+
+       case IW_PRIV_TYPE_ADDR:
+         {
+           char                scratch[128];
+           struct sockaddr *   hwa;
+           /* Display args */
+           for(j = 0; j < n; j++)
+             {
+               hwa = ((struct sockaddr *) buffer) + j;
+               if(j)
+                 printf("           %.*s", 
+                        (int) strlen(cmdname), "                ");
+               printf("%s\n", iw_pr_ether(scratch, hwa->sa_data));
+             }
+         }
+         break;
+
        default:
          fprintf(stderr, "Not yet implemented...\n");
          return(-1);
        default:
          fprintf(stderr, "Not yet implemented...\n");
          return(-1);
@@ -260,6 +502,133 @@ set_private(int           skfd,           /* Socket */
   return(0);
 }
 
   return(0);
 }
 
+/*------------------------------------------------------------------*/
+/*
+ * Execute a private command on the interface
+ */
+static inline int
+set_private(int                skfd,           /* Socket */
+           char *      args[],         /* Command line args */
+           int         count,          /* Args count */
+           char *      ifname)         /* Dev name */
+{
+  iwprivargs   priv[IW_MAX_PRIV_DEF];
+  int          number;         /* Max of private ioctl */
+
+  /* Read the private ioctls */
+  number = iw_get_priv_info(skfd, ifname, priv, IW_MAX_PRIV_DEF);
+
+  /* Is there any ? */
+  if(number <= 0)
+    {
+      /* Could skip this message ? */
+      fprintf(stderr, "%-8.8s  no private ioctls.\n\n",
+             ifname);
+      return(-1);
+    }
+
+  return(set_private_cmd(skfd, args + 1, count - 1, ifname, args[0],
+                        priv, number));
+}
+
+/************************ CATALOG FUNCTIONS ************************/
+
+/*------------------------------------------------------------------*/
+/*
+ * Print on the screen in a neat fashion all the info we have collected
+ * on a device.
+ */
+static int
+print_priv_info(int            skfd,
+               char *          ifname,
+               char *          args[],
+               int             count)
+{
+  int          k;
+  iwprivargs   priv[IW_MAX_PRIV_DEF];
+  int          n;
+
+  /* Avoid "Unused parameter" warning */
+  args = args; count = count;
+
+  /* Read the private ioctls */
+  n = iw_get_priv_info(skfd, ifname, priv, IW_MAX_PRIV_DEF);
+
+  /* Is there any ? */
+  if(n <= 0)
+    {
+      /* Could skip this message ? */
+      fprintf(stderr, "%-8.8s  no private ioctls.\n\n",
+             ifname);
+    }
+  else
+    {
+      printf("%-8.8s  Available private ioctl :\n", ifname);
+      /* Print them all */
+      for(k = 0; k < n; k++)
+       if(priv[k].name[0] != '\0')
+         printf("          %-16.16s (%.4X) : set %3d %s & get %3d %s\n",
+                priv[k].name, priv[k].cmd,
+                priv[k].set_args & IW_PRIV_SIZE_MASK,
+                argtype[(priv[k].set_args & IW_PRIV_TYPE_MASK) >> 12],
+                priv[k].get_args & IW_PRIV_SIZE_MASK,
+                argtype[(priv[k].get_args & IW_PRIV_TYPE_MASK) >> 12]);
+      printf("\n");
+    }
+  return(0);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Print on the screen in a neat fashion all the info we have collected
+ * on a device.
+ */
+static int
+print_priv_all(int             skfd,
+              char *           ifname,
+              char *           args[],
+              int              count)
+{
+  int          k;
+  iwprivargs   priv[IW_MAX_PRIV_DEF];
+  int          n;
+
+  /* Avoid "Unused parameter" warning */
+  args = args; count = count;
+
+  /* Read the private ioctls */
+  n = iw_get_priv_info(skfd, ifname, priv, IW_MAX_PRIV_DEF);
+
+  /* Is there any ? */
+  if(n <= 0)
+    {
+      /* Could skip this message ? */
+      fprintf(stderr, "%-8.8s  no private ioctls.\n\n",
+             ifname);
+    }
+  else
+    {
+      printf("%-8.8s  Available read-only private ioctl :\n", ifname);
+      /* Print them all */
+      for(k = 0; k < n; k++)
+       /* We call all ioctl that don't have a null name, don't require
+        * args and return some (avoid triggering "reset" commands) */
+       if((priv[k].name[0] != '\0') && (priv[k].set_args == 0) &&
+          (priv[k].get_args != 0))
+         set_private_cmd(skfd, NULL, 0, ifname, priv[k].name,
+                         priv, n);
+      printf("\n");
+    }
+#if 0
+  // Debug
+  printf("struct ifreq = %d ; struct iwreq = %d ; IFNAMSIZ = %d\n",
+        sizeof(struct ifreq), sizeof(struct iwreq), IFNAMSIZ);
+  printf("struct iw_freq = %d ; struct sockaddr = %d\n",
+        sizeof(struct iw_freq), sizeof(struct sockaddr));
+#endif
+  return(0);
+}
+
 /********************** PRIVATE IOCTLS MANIPS ***********************/
 /*
  * Convenient access to some private ioctls of some devices
 /********************** PRIVATE IOCTLS MANIPS ***********************/
 /*
  * Convenient access to some private ioctls of some devices
@@ -280,14 +649,14 @@ set_roaming(int           skfd,           /* Socket */
   struct iwreq         wrq;
   int          i = 0;          /* Start with first arg */
   int          k;
   struct iwreq         wrq;
   int          i = 0;          /* Start with first arg */
   int          k;
-  iwprivargs   priv[16];
+  iwprivargs   priv[IW_MAX_PRIV_DEF];
   int          number;
   char         RoamState;              /* buffer to hold new roam state */
   char         ChangeRoamState=0;      /* whether or not we are going to
                                           change roam states */
 
   /* Read the private ioctls */
   int          number;
   char         RoamState;              /* buffer to hold new roam state */
   char         ChangeRoamState=0;      /* whether or not we are going to
                                           change roam states */
 
   /* Read the private ioctls */
-  number = iw_get_priv_info(skfd, ifname, priv);
+  number = iw_get_priv_info(skfd, ifname, priv, IW_MAX_PRIV_DEF);
 
   /* Is there any ? */
   if(number <= 0)
 
   /* Is there any ? */
   if(number <= 0)
@@ -373,13 +742,13 @@ port_type(int             skfd,           /* Socket */
   struct iwreq wrq;
   int          i = 0;          /* Start with first arg */
   int          k;
   struct iwreq wrq;
   int          i = 0;          /* Start with first arg */
   int          k;
-  iwprivargs   priv[16];
+  iwprivargs   priv[IW_MAX_PRIV_DEF];
   int          number;
   char         ptype = 0;
   char *       modes[] = { "invalid", "managed (BSS)", "reserved", "ad-hoc" };
 
   /* Read the private ioctls */
   int          number;
   char         ptype = 0;
   char *       modes[] = { "invalid", "managed (BSS)", "reserved", "ad-hoc" };
 
   /* Read the private ioctls */
-  number = iw_get_priv_info(skfd, ifname, priv);
+  number = iw_get_priv_info(skfd, ifname, priv, IW_MAX_PRIV_DEF);
 
   /* Is there any ? */
   if(number <= 0)
 
   /* Is there any ? */
   if(number <= 0)
@@ -485,27 +854,40 @@ main(int  argc,
     iw_enum_devices(skfd, &print_priv_info, NULL, 0);
   else
     /* Special cases take one... */
     iw_enum_devices(skfd, &print_priv_info, NULL, 0);
   else
     /* Special cases take one... */
-    /* Help */
-    if((!strncmp(argv[1], "-h", 9)) ||
-       (!strcmp(argv[1], "--help")))
-      iw_usage();
+    /* All */
+    if((!strncmp(argv[1], "-a", 2)) || (!strcmp(argv[1], "--all")))
+      iw_enum_devices(skfd, &print_priv_all, NULL, 0);
     else
     else
-      /* The device name must be the first argument */
-      /* Name only : show for that device only */
-      if(argc == 2)
-       print_priv_info(skfd, argv[1], NULL, 0);
+      /* Help */
+      if((!strncmp(argv[1], "-h", 2)) || (!strcmp(argv[1], "--help")))
+       iw_usage();
       else
       else
-       /* Special cases take two... */
-       /* Roaming */
-       if(!strncmp(argv[2], "roam", 4))
-         goterr = set_roaming(skfd, argv + 3, argc - 3, argv[1]);
+       /* Version */
+       if (!strcmp(argv[1], "-v") || !strcmp(argv[1], "--version"))
+         goterr = iw_print_version_info("iwpriv");
        else
        else
-         /* Port type */
-         if(!strncmp(argv[2], "port", 4))
-           goterr = port_type(skfd, argv + 3, argc - 3, argv[1]);
+         /* The device name must be the first argument */
+         /* Name only : show for that device only */
+         if(argc == 2)
+           print_priv_info(skfd, argv[1], NULL, 0);
          else
          else
-           /* Otherwise, it's a private ioctl */
-           goterr = set_private(skfd, argv + 2, argc - 2, argv[1]);
+           /* Special cases take two... */
+           /* All */
+           if((!strncmp(argv[2], "-a", 2)) ||
+              (!strcmp(argv[2], "--all")))
+             print_priv_all(skfd, argv[1], NULL, 0);
+           else
+             /* Roaming */
+             if(!strncmp(argv[2], "roam", 4))
+               goterr = set_roaming(skfd, argv + 3, argc - 3, argv[1]);
+             else
+               /* Port type */
+               if(!strncmp(argv[2], "port", 4))
+                 goterr = port_type(skfd, argv + 3, argc - 3, argv[1]);
+               else
+                 /*-------------*/
+                 /* Otherwise, it's a private ioctl */
+                 goterr = set_private(skfd, argv + 2, argc - 2, argv[1]);
 
   /* Close the socket. */
   close(skfd);
 
   /* Close the socket. */
   close(skfd);
index d550281..9eec627 100644 (file)
@@ -13,7 +13,7 @@ iwspy \- Get wireless statistics from specific nodes
 .SH SYNOPSIS
 .BI "iwspy " interface
 .br
 .SH SYNOPSIS
 .BI "iwspy " interface
 .br
-.BI "iwspy " interface " [+] " IPADDR " | " HWADDR " [...]"
+.BI "iwspy " interface " [+] " DNSNAME " | " IPADDR " | " HWADDR " [...]"
 .br
 .BI "iwspy " interface " off"
 .\"
 .br
 .BI "iwspy " interface " off"
 .\"
@@ -38,21 +38,21 @@ wireless cells.
 .SH PARAMETERS
 You may set any number of addresses up to 8.
 .TP
 .SH PARAMETERS
 You may set any number of addresses up to 8.
 .TP
-.B IPADDR
-Set an IP address, or in some cases a domain name. As the hardware
-work with hardware addresses,
+.BR DNSNAME " | " IPADDR
+Set an IP address, or in some cases a DNS name (using the name
+resolver). As the hardware work with hardware addresses,
 .B iwspy
 .B iwspy
-will translate this address through
+will translate this IP address through
 .IR ARP .
 In some case, this address might not be in the ARP cache and
 .B iwspy
 will fail. In those case,
 .IR ping (8)
 .IR ARP .
 In some case, this address might not be in the ARP cache and
 .B iwspy
 will fail. In those case,
 .IR ping (8)
-this address and retry.
+this name/address and retry.
 .TP
 .B HWADDR
 Set a hardware (MAC) address (this address is not translated & checked
 .TP
 .B HWADDR
 Set a hardware (MAC) address (this address is not translated & checked
-like the IP one). The address must contain a semicolon
+like the IP one). The address must contain a colon
 .RB ( : )
 to be recognised as a hardware address.
 .TP
 .RB ( : )
 to be recognised as a hardware address.
 .TP
index 6b02c1b..21726e6 100644 (file)
 
 #include "iwlib.h"             /* Header */
 
 
 #include "iwlib.h"             /* Header */
 
+/* Backward compatibility */
+#ifndef IW_MAX_GET_SPY
+#define IW_MAX_GET_SPY 64
+#endif /* IW_MAX_GET_SPY */
+
 /************************* DISPLAY ROUTINES **************************/
 
 /*------------------------------------------------------------------*/
 /************************* DISPLAY ROUTINES **************************/
 
 /*------------------------------------------------------------------*/
@@ -26,10 +31,10 @@ print_spy_info(int  skfd,
 {
   struct iwreq         wrq;
   char         buffer[(sizeof(struct iw_quality) +
 {
   struct iwreq         wrq;
   char         buffer[(sizeof(struct iw_quality) +
-                       sizeof(struct sockaddr)) * IW_MAX_SPY];
+                       sizeof(struct sockaddr)) * IW_MAX_GET_SPY];
   char         temp[128];
   char         temp[128];
-  struct sockaddr      hwa[IW_MAX_SPY];
-  struct iw_quality    qual[IW_MAX_SPY];
+  struct sockaddr *    hwa;
+  struct iw_quality *  qual;
   iwrange      range;
   int          has_range = 0;
   int          n;
   iwrange      range;
   int          has_range = 0;
   int          n;
@@ -40,7 +45,7 @@ print_spy_info(int    skfd,
 
   /* Collect stats */
   wrq.u.data.pointer = (caddr_t) buffer;
 
   /* Collect stats */
   wrq.u.data.pointer = (caddr_t) buffer;
-  wrq.u.data.length = IW_MAX_SPY;
+  wrq.u.data.length = IW_MAX_GET_SPY;
   wrq.u.data.flags = 0;
   if(iw_get_ext(skfd, ifname, SIOCGIWSPY, &wrq) < 0)
     {
   wrq.u.data.flags = 0;
   if(iw_get_ext(skfd, ifname, SIOCGIWSPY, &wrq) < 0)
     {
@@ -69,9 +74,8 @@ print_spy_info(int    skfd,
     printf("%-8.8s  Statistics collected:\n", ifname);
  
   /* The two lists */
     printf("%-8.8s  Statistics collected:\n", ifname);
  
   /* The two lists */
-
-  memcpy(hwa, buffer, n * sizeof(struct sockaddr));
-  memcpy(qual, buffer + n*sizeof(struct sockaddr), n*sizeof(struct iw_quality));
+  hwa = (struct sockaddr *) buffer;
+  qual = (struct iw_quality *) (buffer + (sizeof(struct sockaddr) * n));
 
   for(i = 0; i < n; i++)
     {
 
   for(i = 0; i < n; i++)
     {
@@ -211,17 +215,20 @@ main(int  argc,
   else
     /* Special cases take one... */
     /* Help */
   else
     /* Special cases take one... */
     /* Help */
-    if((!strncmp(argv[1], "-h", 9)) ||
-       (!strcmp(argv[1], "--help")))
+    if((!strcmp(argv[1], "-h")) || (!strcmp(argv[1], "--help")))
       fprintf(stderr, "Usage: iwspy interface [+] [MAC address] [IP address]\n");
     else
       fprintf(stderr, "Usage: iwspy interface [+] [MAC address] [IP address]\n");
     else
-      /* The device name must be the first argument */
-      /* Name only : show spy list for that device only */
-      if(argc == 2)
-       print_spy_info(skfd, argv[1], NULL, 0);
+      /* Version */
+      if (!strcmp(argv[1], "-v") || !strcmp(argv[1], "--version"))
+       goterr = iw_print_version_info("iwspy");
       else
       else
-       /* Otherwise, it's a list of address to set in the spy list */
-       goterr = set_spy_info(skfd, argv + 2, argc - 2, argv[1]);
+       /* The device name must be the first argument */
+       /* Name only : show spy list for that device only */
+       if(argc == 2)
+         print_spy_info(skfd, argv[1], NULL, 0);
+       else
+         /* Otherwise, it's a list of address to set in the spy list */
+         goterr = set_spy_info(skfd, argv + 2, argc - 2, argv[1]);
 
   /* Close the socket. */
   close(skfd);
 
   /* Close the socket. */
   close(skfd);
diff --git a/wireless_tools/sample_enc.c b/wireless_tools/sample_enc.c
new file mode 100644 (file)
index 0000000..a1a90e2
--- /dev/null
@@ -0,0 +1,191 @@
+/* Note : this particular snipset of code is available under
+ * the LGPL, MPL or BSD license (at your choice).
+ * Jean II
+ */
+
+/* --------------------------- INCLUDE --------------------------- */
+
+#define MAX_KEY_SIZE   16
+#define        MAX_KEYS        8
+int    key_on = 0;
+int    key_open = 1;
+int    key_current = 0;
+char   key_table[MAX_KEYS][MAX_KEY_SIZE];
+int    key_size[MAX_KEYS];
+
+/* --------------------------- HANDLERS --------------------------- */
+
+static int ioctl_set_encode(struct net_device *dev,
+                           struct iw_request_info *info,
+                           struct iw_point *erq,
+                           char *key)
+{
+  int  index = (erq->flags & IW_ENCODE_INDEX) - 1;
+
+  if (erq->length > 0)
+    {
+      /* Check the size of the key */
+      if(erq->length > MAX_KEY_SIZE)
+       return(-EINVAL);
+
+      /* Check the index */
+      if((index < 0) || (index >= MAX_KEYS))
+       index = key_current;
+
+      /* Copy the key in the driver */
+      memcpy(key_table[index], key, erq->length);
+      key_size[index] = erq->length;
+      key_on = 1;
+    }
+  else
+    {
+      /* Do we want to just set the current key ? */
+      if((index >= 0) && (index < MAX_KEYS))
+       {
+         if(key_size[index] > 0)
+           {
+             key_current = index;
+             key_on = 1;
+           }
+         else
+           return(-EINVAL);
+       }
+    }
+
+  /* Read the flags */
+  if(erq->flags & IW_ENCODE_DISABLED)
+    key_on = 0;                /* disable encryption */
+  if(erq->flags & IW_ENCODE_RESTRICTED)
+    key_open = 0;      /* disable open mode */
+  if(erq->flags & IW_ENCODE_OPEN)
+    key_open = 1;      /* enable open mode */
+
+  return(0);
+}
+
+static int ioctl_get_encode(struct net_device *dev,
+                           struct iw_request_info *info,
+                           struct iw_point *erq,
+                           char *key)
+{
+  int  index = (erq->flags & IW_ENCODE_INDEX) - 1;
+
+  /* Set the flags */
+  erq->flags = 0;
+  if(key_on == 0)
+    erq->flags |= IW_ENCODE_DISABLED;
+  if(key_open == 0)
+    erq->flags |= IW_ENCODE_RESTRICTED;
+  else
+    erq->flags |= IW_ENCODE_OPEN;
+
+  /* Which key do we want */
+  if((index < 0) || (index >= MAX_KEYS))
+    index = key_current;
+  erq->flags |= index + 1;
+
+  /* Copy the key to the user buffer */
+  erq->length = key_size[index];
+  memcpy(key, key_table[index], key_size[index]);
+
+  return(0);
+}
+
+static int ioctl_get_range(struct net_device *dev,
+                          struct iw_request_info *info,
+                          struct iw_point *rrq,
+                          char *extra)
+{
+  struct iw_range *range = (struct iw_range *) extra;
+
+  rrq->length = sizeof(struct iw_range);
+
+  memset(range, 0, sizeof(struct iw_range));
+
+#if WIRELESS_EXT > 10
+  /* Version we are compiled with */
+  range->we_version_compiled = WIRELESS_EXT;
+  /* Minimum version we recommend */
+  range->we_version_source = 8;
+#endif /* WIRELESS_EXT > 10 */
+
+#if WIRELESS_EXT > 8
+  range->encoding_size[0] = 8; /* DES = 64 bits key */
+  range->encoding_size[1] = 16;
+  range->num_encoding_sizes = 2;
+  range->max_encoding_tokens = 8;
+#endif /* WIRELESS_EXT > 8 */
+  return(0);
+}
+
+/* --------------------------- BINDING --------------------------- */
+
+#if WIRELESS_EXT > 12
+static const iw_handler                handler_table[] =
+{
+       ...
+       (iw_handler) ioctl_set_encode,          /* SIOCSIWENCODE */
+       (iw_handler) ioctl_get_encode,          /* SIOCGIWENCODE */
+};
+#else  /* WIRELESS_EXT < 12 */
+static int
+do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+  struct iwreq *wrq = (struct iwreq *) ifr;
+  int          err = 0;
+
+  switch (cmd)
+    {
+#if WIRELESS_EXT > 8
+    case SIOCSIWENCODE:
+      {
+       char keybuf[MAX_KEY_SIZE];
+       if(wrq->u.encoding.pointer)
+         {
+           /* We actually have a key to set */
+           if(wrq->u.encoding.length > MAX_KEY_SIZE)
+             {
+               err = -E2BIG;
+               break;
+             }
+           if(copy_from_user(keybuf, wrq->u.encoding.pointer,
+                             wrq->u.encoding.length))
+             {
+               err = -EFAULT;
+               break;
+             }
+         }
+       else
+         if(wrq->u.encoding.length != 0)
+           {
+             err = -EINVAL;
+             break;
+           }
+       err = ioctl_set_encode(dev, NULL, &(wrq->u.encoding), keybuf);
+      }
+      break;
+
+    case SIOCGIWENCODE:
+      /* only super-user can see encryption key */
+      if(! capable(CAP_NET_ADMIN))
+       {
+         err = -EPERM;
+         break;
+       }
+      {
+       char keybuf[MAX_KEY_SIZE];
+       err = ioctl_get_encode(dev, NULL, &(wrq->u.encoding), keybuf);
+       if(wrq->u.encoding.pointer)
+         {
+           if (copy_to_user(wrq->u.encoding.pointer, keybuf,
+                            wrq->u.encoding.length))
+             err= -EFAULT;
+         }
+      }
+      break;
+#endif /* WIRELESS_EXT > 8 */
+    }
+  return(err);
+}
+#endif /* WIRELESS_EXT < 12 */
+
diff --git a/wireless_tools/sample_enc_cs.c b/wireless_tools/sample_enc_cs.c
deleted file mode 100644 (file)
index f72ca2f..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-/* Note : this particular snipset of code is available under
- * the LGPL, MPL or BSD license (at your choice).
- * Jean II
- */
-
-#define MAX_KEY_SIZE   16
-#define        MAX_KEYS        8
-int    key_on = 0;
-int    key_open = 1;
-int    key_current = 0;
-char   key_table[MAX_KEYS][MAX_KEY_SIZE];
-int    key_size[MAX_KEYS];
-
-#if WIRELESS_EXT > 8
-     case SIOCSIWENCODE:
-       /* Basic checking... */
-       if(wrq->u.encoding.pointer != (caddr_t) 0)
-        {
-          int  index = (wrq->u.encoding.flags & IW_ENCODE_INDEX) - 1;
-
-          /* Check the size of the key */
-          if(wrq->u.encoding.length > MAX_KEY_SIZE)
-            {
-              ret = -EINVAL;
-              break;
-            }
-
-          /* Check the index */
-          if((index < 0) || (index >= MAX_KEYS))
-            index = key_current;
-
-          /* Copy the key in the driver */
-          if(copy_from_user(key_table[index], wrq->u.encoding.pointer,
-                            wrq->u.encoding.length))
-            {
-              key_size[index] = 0;
-              ret = -EFAULT;
-              break;
-            }
-          key_size[index] = wrq->u.encoding.length;
-          key_on = 1;
-        }
-       else
-        {
-          int  index = (wrq->u.encoding.flags & IW_ENCODE_INDEX) - 1;
-          /* Do we want to just set the current key ? */
-          if((index >= 0) && (index < MAX_KEYS))
-            {
-              if(key_size[index] > 0)
-                {
-                  key_current = index;
-                  key_on = 1;
-                }
-              else
-                ret = -EINVAL;
-            }
-        }
-
-       /* Read the flags */
-       if(wrq->u.encoding.flags & IW_ENCODE_DISABLED)
-        key_on = 0;    /* disable encryption */
-       if(wrq->u.encoding.flags & IW_ENCODE_RESTRICTED)
-        key_open = 0;  /* disable open mode */
-       if(wrq->u.encoding.flags & IW_ENCODE_OPEN)
-        key_open = 1;  /* enable open mode */
-
-       break;
-
-     case SIOCGIWENCODE:
-       /* only super-user can see encryption key */
-       if(!suser())
-        {
-          ret = -EPERM;
-          break;
-        }
-
-       /* Basic checking... */
-       if(wrq->u.encoding.pointer != (caddr_t) 0)
-        {
-          int  index = (wrq->u.encoding.flags & IW_ENCODE_INDEX) - 1;
-
-          /* Set the flags */
-          wrq->u.encoding.flags = 0;
-          if(key_on == 0)
-             wrq->u.encoding.flags |= IW_ENCODE_DISABLED;
-          if(key_open == 0)
-            wrq->u.encoding.flags |= IW_ENCODE_RESTRICTED;
-          else
-            wrq->u.encoding.flags |= IW_ENCODE_OPEN;
-
-          /* Which key do we want */
-          if((index < 0) || (index >= MAX_KEYS))
-            index = key_current;
-          wrq->u.encoding.flags |= index + 1;
-
-          /* Copy the key to the user buffer */
-          wrq->u.encoding.length = key_size[index];
-          if(copy_to_user(wrq->u.encoding.pointer, key_table[index],
-                          key_size[index]))
-            ret = -EFAULT;
-       }
-       break;
-#endif /* WIRELESS_EXT > 8 */
-
-#if WIRELESS_EXT > 8
-         range.encoding_size[0] = 8;   /* DES = 64 bits key */
-         range.encoding_size[1] = 16;
-         range.num_encoding_sizes = 2;
-         range.max_encoding_tokens = 8;
-#endif /* WIRELESS_EXT > 8 */
diff --git a/wireless_tools/sample_pm.c b/wireless_tools/sample_pm.c
new file mode 100644 (file)
index 0000000..8735cc8
--- /dev/null
@@ -0,0 +1,215 @@
+/* Note : this particular snipset of code is available under
+ * the LGPL, MPL or BSD license (at your choice).
+ * Jean II
+ */
+
+/* --------------------------- INCLUDE --------------------------- */
+
+/* Backward compatibility for Wireless Extension 9 */
+#ifndef IW_POWER_MODIFIER
+#define IW_POWER_MODIFIER      0x000F  /* Modify a parameter */
+#define IW_POWER_MIN           0x0001  /* Value is a minimum  */
+#define IW_POWER_MAX           0x0002  /* Value is a maximum */
+#define IW_POWER_RELATIVE      0x0004  /* Value is not in seconds/ms/us */
+#endif IW_POWER_MODIFIER
+
+struct net_local {
+  int          pm_on;          // Power Management enabled
+  int          pm_multi;       // Receive multicasts
+  int          pm_period;      // Power Management period
+  int          pm_period_auto; // Power Management auto mode
+  int          pm_max_period;  // Power Management max period
+  int          pm_min_period;  // Power Management min period
+  int          pm_timeout;     // Power Management timeout
+};
+
+/* --------------------------- HANDLERS --------------------------- */
+
+static int ioctl_set_power(struct net_device *dev,
+                          struct iw_request_info *info,
+                          struct iw_param *prq,
+                          char *extra)
+{
+  /* Disable it ? */
+  if(prq->disabled)
+    {
+      local->pm_on = 0;
+    }
+  else
+    {
+      /* Check mode */
+      switch(prq->flags & IW_POWER_MODE)
+       {
+       case IW_POWER_UNICAST_R:
+         local->pm_multi = 0;
+         local->need_commit = 1;
+         break;
+       case IW_POWER_ALL_R:
+         local->pm_multi = 1;
+         local->need_commit = 1;
+         break;
+       case IW_POWER_ON:       /* None = ok */
+         break;
+       default:        /* Invalid */
+         return(-EINVAL);
+       }
+      /* Set period */
+      if(prq->flags & IW_POWER_PERIOD)
+       {
+         int   period = prq->value/1000000;
+         /* Hum: check if within bounds... */
+
+         /* Activate PM */
+         local->pm_on = 1;
+         local->need_commit = 1;
+
+         /* Check min value */
+         if(prq->flags & IW_POWER_MIN)
+           {
+             local->pm_min_period = period;
+             local->pm_period_auto = 1;
+           }
+         else
+           /* Check max value */
+           if(prq->flags & IW_POWER_MAX)
+             {
+               local->pm_max_period = period;
+               local->pm_period_auto = 1;
+             }
+           else
+             {
+               /* Fixed value */
+               local->pm_period = period;
+               local->pm_period_auto = 0;
+             }
+       }
+      /* Set timeout */
+      if(prq->flags & IW_POWER_TIMEOUT)
+       {
+         /* Activate PM */
+         local->pm_on = 1;
+         local->need_commit = 1;
+         /* Fixed value in ms */
+         local->pm_timeout = prq->value/1000;
+       }
+    }
+
+  return(0);
+}
+
+static int ioctl_get_power(struct net_device *dev,
+                          struct iw_request_info *info,
+                          struct iw_param *prq,
+                          char *extra)
+{
+  prq->disabled = !local->pm_on;
+  /* By default, display the period */
+  if(!(prq->flags & IW_POWER_TIMEOUT))
+    {
+      int      inc_flags = prq->flags;
+      prq->flags = IW_POWER_PERIOD | IW_POWER_RELATIVE;
+      /* Check if auto */
+      if(local->pm_period_auto)
+       {
+         /* By default, the min */
+         if(!(inc_flags & IW_POWER_MAX))
+           {
+             prq->value = local->pm_min_period * 1000000;
+             prq->flags |= IW_POWER_MIN;
+           }
+         else
+           {
+             prq->value = local->pm_max_period * 1000000;
+             prq->flags |= IW_POWER_MAX;
+           }
+       }
+      else
+       {
+         /* Fixed value. Check the flags */
+         if(inc_flags & (IW_POWER_MIN | IW_POWER_MAX))
+           return(-EINVAL);
+         else
+           prq->value = local->pm_period * 1000000;
+       }
+    }
+  else
+    {
+      /* Deal with the timeout - always fixed */
+      prq->flags = IW_POWER_TIMEOUT;
+      prq->value = local->pm_timeout * 1000;
+    }
+  if(local->pm_multi)
+    prq->flags |= IW_POWER_ALL_R;
+  else
+    prq->flags |= IW_POWER_UNICAST_R;
+
+  return(0);
+}
+
+static int ioctl_get_range(struct net_device *dev,
+                          struct iw_request_info *info,
+                          struct iw_point *rrq,
+                          char *extra)
+{
+  struct iw_range *range = (struct iw_range *) extra;
+
+  rrq->length = sizeof(struct iw_range);
+
+  memset(range, 0, sizeof(struct iw_range));
+
+#if WIRELESS_EXT > 10
+  /* Version we are compiled with */
+  range->we_version_compiled = WIRELESS_EXT;
+  /* Minimum version we recommend */
+  range->we_version_source = 8;
+#endif /* WIRELESS_EXT > 10 */
+
+#if WIRELESS_EXT > 9
+      range.min_pmp = 1000000; /* 1 units */
+      range.max_pmp = 12000000;        /* 12 units */
+      range.min_pmt = 1000;    /* 1 ms */
+      range.max_pmt = 1000000; /* 1 s */
+      range.pmp_flags = IW_POWER_PERIOD | IW_POWER_RELATIVE |
+        IW_POWER_MIN | IW_POWER_MAX;
+      range.pmt_flags = IW_POWER_TIMEOUT;
+      range.pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_UNICAST_R;
+#endif /* WIRELESS_EXT > 9 */
+  return(0);
+}
+
+/* --------------------------- BINDING --------------------------- */
+
+#if WIRELESS_EXT > 12
+/* Use the new driver API, save overhead */
+static const iw_handler                handler_table[] =
+{
+       ...
+       (iw_handler) ioctl_set_power,           /* SIOCSIWPOWER */
+       (iw_handler) ioctl_get_power,           /* SIOCGIWPOWER */
+};
+#else  /* WIRELESS_EXT < 12 */
+/* Use old API in the ioctl handler */
+static int
+do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+  struct iwreq *wrq = (struct iwreq *) ifr;
+  int          err = 0;
+
+  switch (cmd)
+    {
+#if WIRELESS_EXT > 8
+      /* Set the desired Power Management mode */
+    case SIOCSIWPOWER:
+      err = ioctl_set_power(dev, NULL, &(wrq->u.power), NULL);
+      break;
+
+      /* Get the power management settings */
+    case SIOCGIWPOWER:
+      err = ioctl_get_power(dev, NULL, &(wrq->u.power), NULL);
+      break;
+#endif /* WIRELESS_EXT > 8 */
+    }
+  return(err);
+}
+#endif /* WIRELESS_EXT < 12 */
+
diff --git a/wireless_tools/sample_pm_cs.c b/wireless_tools/sample_pm_cs.c
deleted file mode 100644 (file)
index 9cecad0..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-/* Note : this particular snipset of code is available under
- * the LGPL, MPL or BSD license (at your choice).
- * Jean II
- */
-
-/* Backward compatibility for Wireless Extension 9 */
-#ifndef IW_POWER_MODIFIER
-#define IW_POWER_MODIFIER      0x000F  /* Modify a parameter */
-#define IW_POWER_MIN           0x0001  /* Value is a minimum  */
-#define IW_POWER_MAX           0x0002  /* Value is a maximum */
-#define IW_POWER_RELATIVE      0x0004  /* Value is not in seconds/ms/us */
-#endif IW_POWER_MODIFIER
-
-struct net_local {
-  int          pm_on;          // Power Management enabled
-  int          pm_multi;       // Receive multicasts
-  int          pm_period;      // Power Management period
-  int          pm_period_auto; // Power Management auto mode
-  int          pm_max_period;  // Power Management max period
-  int          pm_min_period;  // Power Management min period
-  int          pm_timeout;     // Power Management timeout
-};
-
-      /* Set the desired Power Management mode */
-    case SIOCSIWPOWER:
-      /* Disable it ? */
-      if(wrq->u.power.disabled)
-       {
-         local->pm_on = 0;
-         local->need_commit = 1;
-       }
-      else
-       {
-         /* Check mode */
-         switch(wrq->u.power.flags & IW_POWER_MODE)
-           {
-           case IW_POWER_UNICAST_R:
-             local->pm_multi = 0;
-             local->need_commit = 1;
-             break;
-           case IW_POWER_ALL_R:
-             local->pm_multi = 1;
-             local->need_commit = 1;
-             break;
-           case IW_POWER_ON:   /* None = ok */
-             break;
-           default:    /* Invalid */
-             rc = -EINVAL;
-           }
-         /* Set period */
-         if(wrq->u.power.flags & IW_POWER_PERIOD)
-           {
-             int       period = wrq->u.power.value/1000000;
-             /* Hum: check if within bounds... */
-
-             /* Activate PM */
-             local->pm_on = 1;
-             local->need_commit = 1;
-
-             /* Check min value */
-             if(wrq->u.power.flags & IW_POWER_MIN)
-               {
-                 local->pm_min_period = period;
-                 local->pm_period_auto = 1;
-               }
-             else
-               /* Check max value */
-               if(wrq->u.power.flags & IW_POWER_MAX)
-                 {
-                   local->pm_max_period = period;
-                   local->pm_period_auto = 1;
-                 }
-               else
-                 {
-                   /* Fixed value */
-                   local->pm_period = period;
-                   local->pm_period_auto = 0;
-                 }
-           }
-         /* Set timeout */
-         if(wrq->u.power.flags & IW_POWER_TIMEOUT)
-           {
-             /* Activate PM */
-             local->pm_on = 1;
-             local->need_commit = 1;
-             /* Fixed value in ms */
-             local->pm_timeout = wrq->u.power.value/1000;
-           }
-       }
-      break;
-
-      /* Get the power management settings */
-    case SIOCGIWPOWER:
-      wrq->u.power.disabled = !local->pm_on;
-      /* By default, display the period */
-      if(!(wrq->u.power.flags & IW_POWER_TIMEOUT))
-       {
-         int   inc_flags = wrq->u.power.flags;
-         wrq->u.power.flags = IW_POWER_PERIOD | IW_POWER_RELATIVE;
-         /* Check if auto */
-         if(local->pm_period_auto)
-           {
-             /* By default, the min */
-             if(!(inc_flags & IW_POWER_MAX))
-               {
-                 wrq->u.power.value = local->pm_min_period * 1000000;
-                 wrq->u.power.flags |= IW_POWER_MIN;
-               }
-             else
-               {
-                 wrq->u.power.value = local->pm_max_period * 1000000;
-                 wrq->u.power.flags |= IW_POWER_MAX;
-               }
-           }
-         else
-           {
-             /* Fixed value. Check the flags */
-             if(inc_flags & (IW_POWER_MIN | IW_POWER_MAX))
-               rc = -EINVAL;
-             else
-               wrq->u.power.value = local->pm_period * 1000000;
-           }
-       }
-      else
-       {
-         /* Deal with the timeout - always fixed */
-         wrq->u.power.flags = IW_POWER_TIMEOUT;
-         wrq->u.power.value = local->pm_timeout * 1000;
-       }
-      if(local->pm_multi)
-       wrq->u.power.flags |= IW_POWER_ALL_R;
-      else
-       wrq->u.power.flags |= IW_POWER_UNICAST_R;
-      break;
-#endif /* WIRELESS_EXT > 8 */
-
-#if WIRELESS_EXT > 9
-      range.min_pmp = 1000000; /* 1 units */
-      range.max_pmp = 12000000;        /* 12 units */
-      range.min_pmt = 1000;    /* 1 ms */
-      range.max_pmt = 1000000; /* 1 s */
-      range.pmp_flags = IW_POWER_PERIOD | IW_POWER_RELATIVE |
-        IW_POWER_MIN | IW_POWER_MAX;
-      range.pmt_flags = IW_POWER_TIMEOUT;
-      range.pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_UNICAST_R;
-#endif /* WIRELESS_EXT > 9 */
diff --git a/wireless_tools/sample_priv_addr.c b/wireless_tools/sample_priv_addr.c
new file mode 100644 (file)
index 0000000..fd5793d
--- /dev/null
@@ -0,0 +1,210 @@
+/* Note : this particular snipset of code is available under
+ * the LGPL, MPL or BSD license (at your choice).
+ * Jean II
+ */
+
+// Require Wireless Tools 25 for sub-ioctl and addr support
+
+/* --------------------------- INCLUDE --------------------------- */
+
+#if WIRELESS_EXT <= 12
+/* Wireless extensions backward compatibility */
+
+/* We need the full definition for private ioctls */
+struct iw_request_info
+{
+       __u16           cmd;            /* Wireless Extension command */
+       __u16           flags;          /* More to come ;-) */
+};
+#endif /* WIRELESS_EXT <= 12 */
+
+#ifndef IW_PRIV_TYPE_ADDR
+#define IW_PRIV_TYPE_ADDR      0x6000
+#endif /* IW_PRIV_TYPE_ADDR */
+
+/* --------------------------- HANDLERS --------------------------- */
+
+/* First method : using sub-ioctls.
+ * Note that sizeof(int + struct sockaddr) = 20 > 16, therefore the
+ * data is passed in (char *) extra, and sub-ioctl in data->flags. */
+static int sample_ioctl_set_mac(struct net_device *dev,
+                               struct iw_request_info *info,
+                               struct iw_point *data,
+                               struct sockaddr *mac_addr)
+{
+       unsigned char * addr = (char *) &mac_addr->sa_data;
+
+       switch(data->flags) {
+       case 0:
+               printk(KERN_DEBUG "%s: mac_add %02X:%02X:%02X:%02X:%02X:%02X\n", dev->name, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+               break;
+       case 1:
+               printk(KERN_DEBUG "%s: mac_del %02X:%02X:%02X:%02X:%02X:%02X\n", dev->name, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+               break;
+       case 2:
+               printk(KERN_DEBUG "%s: mac_kick %02X:%02X:%02X:%02X:%02X:%02X\n", dev->name, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+               break;
+       default:
+               printk(KERN_DEBUG "%s: mac_undefined %02X:%02X:%02X:%02X:%02X:%02X\n", dev->name, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+               break;
+       }
+
+       return 0;
+}
+
+/* Second method : bind single handler to multiple ioctls.
+ * Note that sizeof(struct sockaddr) = 16 <= 16, therefore the
+ * data is passed in (struct iwreq) (and also mapped in extra).
+ */
+static int sample_ioctl_set_addr(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct sockaddr *mac_addr, char *extra)
+{
+       unsigned char * addr = (char *) &mac_addr->sa_data;
+
+       switch(info->cmd) {
+       case SIOCIWFIRSTPRIV + 28:
+               printk(KERN_DEBUG "%s: addr_add %02X:%02X:%02X:%02X:%02X:%02X\n", dev->name, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+               break;
+       case SIOCIWFIRSTPRIV + 30:
+               printk(KERN_DEBUG "%s: addr_del %02X:%02X:%02X:%02X:%02X:%02X\n", dev->name, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+               break;
+       default:
+               printk(KERN_DEBUG "%s: mac_undefined %02X:%02X:%02X:%02X:%02X:%02X\n", dev->name, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+               break;
+       }
+
+       return 0;
+}
+
+// Extra fun for testing
+static int sample_ioctl_get_mac(struct net_device *dev,
+                               struct iw_request_info *info,
+                               struct iw_point *data,
+                               struct sockaddr *mac_addr)
+{
+       unsigned char   fake_addr[6];
+       int             i;
+       int             j;
+
+       for(i = 0; i < 16; i++) {
+               /* Create a fake address */
+               for(j = 0; j < 6; j++)
+                       fake_addr[j] = (unsigned char) ((j << 4) + i);
+               /* Put in in the table */
+               memcpy(&(mac_addr[i]).sa_data, fake_addr, ETH_ALEN);
+               mac_addr[i].sa_family = ARPHRD_ETHER;
+       }
+       data->length = 16;
+
+       return 0;
+}
+
+static int sample_ioctl_set_float(struct net_device *dev,
+                                 struct iw_request_info *info,
+                                 struct iw_freq *freq, char *extra)
+{
+       printk(KERN_DEBUG "%s: set_float %d;%d\n",
+              dev->name, freq->m, freq->e);
+
+       return 0;
+}
+
+/* --------------------------- BINDING --------------------------- */
+
+static const struct iw_priv_args sample_priv[] = {
+       // *** Method 1 : using sub-ioctls ***
+       /* --- sub-ioctls handler --- */
+       { SIOCIWFIRSTPRIV + 0,
+         IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "" },
+       /* --- sub-ioctls definitions --- */
+       { 0,
+         IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "macadd" },
+       { 1,
+         IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "macdel" },
+       { 2,
+         IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "mackick" },
+       // *** Method 2 : binding one handler to multiple ioctls ***
+       { SIOCIWFIRSTPRIV + 2,
+         IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "addradd" },
+       { SIOCIWFIRSTPRIV + 4,
+         IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "addrdel" },
+       // *** Extra fun ***
+       { SIOCIWFIRSTPRIV + 1,
+         0, IW_PRIV_TYPE_ADDR | 16, "macget" },
+       { SIOCIWFIRSTPRIV + 6,
+         IW_PRIV_TYPE_FLOAT | IW_PRIV_SIZE_FIXED | 1, 0, "setfloat" },
+};
+
+static const iw_handler sample_private_handler[] =
+{                                                      /* SIOCIWFIRSTPRIV + */
+#if WIRELESS_EXT >= 15
+       /* Various little annoying bugs in the new API before
+        * version 15 make it difficult to use the new API for those ioctls.
+        * For example, it doesn't know about the new data type.
+        * Rather than littering the code with workarounds,
+        * let's use the regular ioctl handler. - Jean II */
+       (iw_handler) sample_ioctl_set_mac,              /* 0 */
+       (iw_handler) sample_ioctl_get_mac,              /* 1 */
+       (iw_handler) sample_ioctl_set_addr,             /* 2 */
+       (iw_handler) NULL,                              /* 3 */
+       (iw_handler) sample_ioctl_set_addr,             /* 4 */
+       (iw_handler) NULL,                              /* 5 */
+       (iw_handler) sample_ioctl_set_float,            /* 6 */
+#endif /* WIRELESS_EXT >= 15 */
+};
+
+#if WIRELESS_EXT < 15
+               /* Various little annoying bugs in the new API before
+                * version 15 make it difficult to use those ioctls.
+                * For example, it doesn't know about the new data type.
+                * Rather than littering the code with workarounds,
+                * let's use this code that just works. - Jean II */
+       case SIOCIWFIRSTPRIV + 0:
+               if (wrq->u.data.length > 1)
+                       ret = -E2BIG;
+               else if (wrq->u.data.pointer) {
+                       struct sockaddr mac_addr;
+                       if (copy_from_user(&mac_addr, wrq->u.data.pointer,
+                                          sizeof(struct sockaddr))) {
+                               ret = -EFAULT;
+                               break;
+                       }
+                       ret = sample_ioctl_set_mac(dev, NULL, &wrq->u.data,
+                                                  &mac_addr);
+               }
+               break;
+       case SIOCIWFIRSTPRIV + 2:
+       case SIOCIWFIRSTPRIV + 4:
+               if (!capable(CAP_NET_ADMIN))
+                       ret = -EPERM;
+               else {
+                       struct iw_request_info info;
+                       info.cmd = cmd;
+                       ret = sample_ioctl_set_addr(dev, &info,
+                                                   &wrq->u.ap_addr,
+                                                   NULL);
+               }
+               break;
+       case SIOCIWFIRSTPRIV + 1:
+               if (wrq->u.essid.pointer) {
+                       struct sockaddr mac_addr[16];
+                       char nickbuf[IW_ESSID_MAX_SIZE + 1];
+                       ret = sample_ioctl_get_mac(dev, NULL, &wrq->u.data,
+                                                  mac_addr);
+                       if (copy_to_user(wrq->u.data.pointer, nickbuf,
+                                        wrq->u.data.length *
+                                        sizeof(struct sockaddr)))
+                               ret = -EFAULT;
+               }
+               break;
+       case SIOCIWFIRSTPRIV + 6:
+               if (!capable(CAP_NET_ADMIN))
+                       ret = -EPERM;
+               else {
+                       ret = sample_ioctl_set_float(dev, NULL,
+                                                    &wrq->u.freq,
+                                                    NULL);
+               }
+               break;
+#endif /* WIRELESS_EXT < 15 */
diff --git a/wireless_tools/wireless.15.h b/wireless_tools/wireless.15.h
new file mode 100644 (file)
index 0000000..bacf44b
--- /dev/null
@@ -0,0 +1,698 @@
+/*
+ * This file define a set of standard wireless extensions
+ *
+ * Version :   15      12.7.02
+ *
+ * Authors :   Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+ * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved.
+ */
+
+#ifndef _LINUX_WIRELESS_H
+#define _LINUX_WIRELESS_H
+
+/************************** DOCUMENTATION **************************/
+/*
+ * Initial APIs (1996 -> onward) :
+ * -----------------------------
+ * Basically, the wireless extensions are for now a set of standard ioctl
+ * call + /proc/net/wireless
+ *
+ * The entry /proc/net/wireless give statistics and information on the
+ * driver.
+ * This is better than having each driver having its entry because
+ * its centralised and we may remove the driver module safely.
+ *
+ * Ioctl are used to configure the driver and issue commands.  This is
+ * better than command line options of insmod because we may want to
+ * change dynamically (while the driver is running) some parameters.
+ *
+ * The ioctl mechanimsm are copied from standard devices ioctl.
+ * We have the list of command plus a structure descibing the
+ * data exchanged...
+ * Note that to add these ioctl, I was obliged to modify :
+ *     # net/core/dev.c (two place + add include)
+ *     # net/ipv4/af_inet.c (one place + add include)
+ *
+ * /proc/net/wireless is a copy of /proc/net/dev.
+ * We have a structure for data passed from the driver to /proc/net/wireless
+ * Too add this, I've modified :
+ *     # net/core/dev.c (two other places)
+ *     # include/linux/netdevice.h (one place)
+ *     # include/linux/proc_fs.h (one place)
+ *
+ * New driver API (2002 -> onward) :
+ * -------------------------------
+ * This file is only concerned with the user space API and common definitions.
+ * The new driver API is defined and documented in :
+ *     # include/net/iw_handler.h
+ *
+ * Note as well that /proc/net/wireless implementation has now moved in :
+ *     # include/linux/wireless.c
+ *
+ * Wireless Events (2002 -> onward) :
+ * --------------------------------
+ * Events are defined at the end of this file, and implemented in :
+ *     # include/linux/wireless.c
+ *
+ * Other comments :
+ * --------------
+ * Do not add here things that are redundant with other mechanisms
+ * (drivers init, ifconfig, /proc/net/dev, ...) and with are not
+ * wireless specific.
+ *
+ * These wireless extensions are not magic : each driver has to provide
+ * support for them...
+ *
+ * IMPORTANT NOTE : As everything in the kernel, this is very much a
+ * work in progress. Contact me if you have ideas of improvements...
+ */
+
+/***************************** INCLUDES *****************************/
+
+#include <linux/types.h>               /* for "caddr_t" et al          */
+#include <linux/socket.h>              /* for "struct sockaddr" et al  */
+#include <linux/if.h>                  /* for IFNAMSIZ and co... */
+
+/***************************** VERSION *****************************/
+/*
+ * This constant is used to know the availability of the wireless
+ * extensions and to know which version of wireless extensions it is
+ * (there is some stuff that will be added in the future...)
+ * I just plan to increment with each new version.
+ */
+#define WIRELESS_EXT   15
+
+/*
+ * Changes :
+ *
+ * V2 to V3
+ * --------
+ *     Alan Cox start some incompatibles changes. I've integrated a bit more.
+ *     - Encryption renamed to Encode to avoid US regulation problems
+ *     - Frequency changed from float to struct to avoid problems on old 386
+ *
+ * V3 to V4
+ * --------
+ *     - Add sensitivity
+ *
+ * V4 to V5
+ * --------
+ *     - Missing encoding definitions in range
+ *     - Access points stuff
+ *
+ * V5 to V6
+ * --------
+ *     - 802.11 support (ESSID ioctls)
+ *
+ * V6 to V7
+ * --------
+ *     - define IW_ESSID_MAX_SIZE and IW_MAX_AP
+ *
+ * V7 to V8
+ * --------
+ *     - Changed my e-mail address
+ *     - More 802.11 support (nickname, rate, rts, frag)
+ *     - List index in frequencies
+ *
+ * V8 to V9
+ * --------
+ *     - Support for 'mode of operation' (ad-hoc, managed...)
+ *     - Support for unicast and multicast power saving
+ *     - Change encoding to support larger tokens (>64 bits)
+ *     - Updated iw_params (disable, flags) and use it for NWID
+ *     - Extracted iw_point from iwreq for clarity
+ *
+ * V9 to V10
+ * ---------
+ *     - Add PM capability to range structure
+ *     - Add PM modifier : MAX/MIN/RELATIVE
+ *     - Add encoding option : IW_ENCODE_NOKEY
+ *     - Add TxPower ioctls (work like TxRate)
+ *
+ * V10 to V11
+ * ----------
+ *     - Add WE version in range (help backward/forward compatibility)
+ *     - Add retry ioctls (work like PM)
+ *
+ * V11 to V12
+ * ----------
+ *     - Add SIOCSIWSTATS to get /proc/net/wireless programatically
+ *     - Add DEV PRIVATE IOCTL to avoid collisions in SIOCDEVPRIVATE space
+ *     - Add new statistics (frag, retry, beacon)
+ *     - Add average quality (for user space calibration)
+ *
+ * V12 to V13
+ * ----------
+ *     - Document creation of new driver API.
+ *     - Extract union iwreq_data from struct iwreq (for new driver API).
+ *     - Rename SIOCSIWNAME as SIOCSIWCOMMIT
+ *
+ * V13 to V14
+ * ----------
+ *     - Wireless Events support : define struct iw_event
+ *     - Define additional specific event numbers
+ *     - Add "addr" and "param" fields in union iwreq_data
+ *     - AP scanning stuff (SIOCSIWSCAN and friends)
+ *
+ * V14 to V15
+ * ----------
+ *     - Add IW_PRIV_TYPE_ADDR for struct sockaddr private arg
+ *     - Make struct iw_freq signed (both m & e), add explicit padding
+ *     - Add IWEVCUSTOM for driver specific event/scanning token
+ *     - Add IW_MAX_GET_SPY for driver returning a lot of addresses
+ *     - Add IW_TXPOW_RANGE for range of Tx Powers
+ *     - Add IWEVREGISTERED & IWEVEXPIRED events for Access Points
+ *     - Add IW_MODE_MONITOR for passive monitor
+ */
+
+/**************************** CONSTANTS ****************************/
+
+/* -------------------------- IOCTL LIST -------------------------- */
+
+/* Wireless Identification */
+#define SIOCSIWCOMMIT  0x8B00          /* Commit pending changes to driver */
+#define SIOCGIWNAME    0x8B01          /* get name == wireless protocol */
+/* SIOCGIWNAME is used to verify the presence of Wireless Extensions.
+ * Common values : "IEEE 802.11-DS", "IEEE 802.11-FH", "IEEE 802.11b"...
+ * Don't put the name of your driver there, it's useless. */
+
+/* Basic operations */
+#define SIOCSIWNWID    0x8B02          /* set network id (pre-802.11) */
+#define SIOCGIWNWID    0x8B03          /* get network id (the cell) */
+#define SIOCSIWFREQ    0x8B04          /* set channel/frequency (Hz) */
+#define SIOCGIWFREQ    0x8B05          /* get channel/frequency (Hz) */
+#define SIOCSIWMODE    0x8B06          /* set operation mode */
+#define SIOCGIWMODE    0x8B07          /* get operation mode */
+#define SIOCSIWSENS    0x8B08          /* set sensitivity (dBm) */
+#define SIOCGIWSENS    0x8B09          /* get sensitivity (dBm) */
+
+/* Informative stuff */
+#define SIOCSIWRANGE   0x8B0A          /* Unused */
+#define SIOCGIWRANGE   0x8B0B          /* Get range of parameters */
+#define SIOCSIWPRIV    0x8B0C          /* Unused */
+#define SIOCGIWPRIV    0x8B0D          /* get private ioctl interface info */
+#define SIOCSIWSTATS   0x8B0E          /* Unused */
+#define SIOCGIWSTATS   0x8B0F          /* Get /proc/net/wireless stats */
+/* SIOCGIWSTATS is strictly used between user space and the kernel, and
+ * is never passed to the driver (i.e. the driver will never see it). */
+
+/* Mobile IP support (statistics per MAC address) */
+#define SIOCSIWSPY     0x8B10          /* set spy addresses */
+#define SIOCGIWSPY     0x8B11          /* get spy info (quality of link) */
+
+/* Access Point manipulation */
+#define SIOCSIWAP      0x8B14          /* set access point MAC addresses */
+#define SIOCGIWAP      0x8B15          /* get access point MAC addresses */
+#define SIOCGIWAPLIST  0x8B17          /* Deprecated in favor of scanning */
+#define SIOCSIWSCAN    0x8B18          /* trigger scanning (list cells) */
+#define SIOCGIWSCAN    0x8B19          /* get scanning results */
+
+/* 802.11 specific support */
+#define SIOCSIWESSID   0x8B1A          /* set ESSID (network name) */
+#define SIOCGIWESSID   0x8B1B          /* get ESSID */
+#define SIOCSIWNICKN   0x8B1C          /* set node name/nickname */
+#define SIOCGIWNICKN   0x8B1D          /* get node name/nickname */
+/* As the ESSID and NICKN are strings up to 32 bytes long, it doesn't fit
+ * within the 'iwreq' structure, so we need to use the 'data' member to
+ * point to a string in user space, like it is done for RANGE... */
+
+/* Other parameters useful in 802.11 and some other devices */
+#define SIOCSIWRATE    0x8B20          /* set default bit rate (bps) */
+#define SIOCGIWRATE    0x8B21          /* get default bit rate (bps) */
+#define SIOCSIWRTS     0x8B22          /* set RTS/CTS threshold (bytes) */
+#define SIOCGIWRTS     0x8B23          /* get RTS/CTS threshold (bytes) */
+#define SIOCSIWFRAG    0x8B24          /* set fragmentation thr (bytes) */
+#define SIOCGIWFRAG    0x8B25          /* get fragmentation thr (bytes) */
+#define SIOCSIWTXPOW   0x8B26          /* set transmit power (dBm) */
+#define SIOCGIWTXPOW   0x8B27          /* get transmit power (dBm) */
+#define SIOCSIWRETRY   0x8B28          /* set retry limits and lifetime */
+#define SIOCGIWRETRY   0x8B29          /* get retry limits and lifetime */
+
+/* Encoding stuff (scrambling, hardware security, WEP...) */
+#define SIOCSIWENCODE  0x8B2A          /* set encoding token & mode */
+#define SIOCGIWENCODE  0x8B2B          /* get encoding token & mode */
+/* Power saving stuff (power management, unicast and multicast) */
+#define SIOCSIWPOWER   0x8B2C          /* set Power Management settings */
+#define SIOCGIWPOWER   0x8B2D          /* get Power Management settings */
+
+/* -------------------- DEV PRIVATE IOCTL LIST -------------------- */
+
+/* These 16 ioctl are wireless device private.
+ * Each driver is free to use them for whatever purpose it chooses,
+ * however the driver *must* export the description of those ioctls
+ * with SIOCGIWPRIV and *must* use arguments as defined below.
+ * If you don't follow those rules, DaveM is going to hate you (reason :
+ * it make mixed 32/64bit operation impossible).
+ */
+#define SIOCIWFIRSTPRIV        0x8BE0
+#define SIOCIWLASTPRIV 0x8BFF
+/* Previously, we were using SIOCDEVPRIVATE, but we now have our
+ * separate range because of collisions with other tools such as
+ * 'mii-tool'.
+ * We now have 32 commands, so a bit more space ;-).
+ * Also, all 'odd' commands are only usable by root and don't return the
+ * content of ifr/iwr to user (but you are not obliged to use the set/get
+ * convention, just use every other two command).
+ * And I repeat : you are not obliged to use them with iwspy, but you
+ * must be compliant with it.
+ */
+
+/* ------------------------- IOCTL STUFF ------------------------- */
+
+/* The first and the last (range) */
+#define SIOCIWFIRST    0x8B00
+#define SIOCIWLAST     SIOCIWLASTPRIV          /* 0x8BFF */
+
+/* Even : get (world access), odd : set (root access) */
+#define IW_IS_SET(cmd) (!((cmd) & 0x1))
+#define IW_IS_GET(cmd) ((cmd) & 0x1)
+
+/* ----------------------- WIRELESS EVENTS ----------------------- */
+/* Those are *NOT* ioctls, do not issue request on them !!! */
+/* Most events use the same identifier as ioctl requests */
+
+#define IWEVTXDROP     0x8C00          /* Packet dropped to excessive retry */
+#define IWEVQUAL       0x8C01          /* Quality part of statistics (scan) */
+#define IWEVCUSTOM     0x8C02          /* Driver specific ascii string */
+#define IWEVREGISTERED 0x8C03          /* Discovered a new node (AP mode) */
+#define IWEVEXPIRED    0x8C04          /* Expired a node (AP mode) */
+
+#define IWEVFIRST      0x8C00
+
+/* ------------------------- PRIVATE INFO ------------------------- */
+/*
+ * The following is used with SIOCGIWPRIV. It allow a driver to define
+ * the interface (name, type of data) for its private ioctl.
+ * Privates ioctl are SIOCIWFIRSTPRIV -> SIOCIWLASTPRIV
+ */
+
+#define IW_PRIV_TYPE_MASK      0x7000  /* Type of arguments */
+#define IW_PRIV_TYPE_NONE      0x0000
+#define IW_PRIV_TYPE_BYTE      0x1000  /* Char as number */
+#define IW_PRIV_TYPE_CHAR      0x2000  /* Char as character */
+#define IW_PRIV_TYPE_INT       0x4000  /* 32 bits int */
+#define IW_PRIV_TYPE_FLOAT     0x5000  /* struct iw_freq */
+#define IW_PRIV_TYPE_ADDR      0x6000  /* struct sockaddr */
+
+#define IW_PRIV_SIZE_FIXED     0x0800  /* Variable or fixed nuber of args */
+
+#define IW_PRIV_SIZE_MASK      0x07FF  /* Max number of those args */
+
+/*
+ * Note : if the number of args is fixed and the size < 16 octets,
+ * instead of passing a pointer we will put args in the iwreq struct...
+ */
+
+/* ----------------------- OTHER CONSTANTS ----------------------- */
+
+/* Maximum frequencies in the range struct */
+#define IW_MAX_FREQUENCIES     16
+/* Note : if you have something like 80 frequencies,
+ * don't increase this constant and don't fill the frequency list.
+ * The user will be able to set by channel anyway... */
+
+/* Maximum bit rates in the range struct */
+#define IW_MAX_BITRATES                8
+
+/* Maximum tx powers in the range struct */
+#define IW_MAX_TXPOWER         8
+/* Note : if you more than 8 TXPowers, just set the max and min or
+ * a few of them in the struct iw_range. */
+
+/* Maximum of address that you may set with SPY */
+#define IW_MAX_SPY             8       /* set */
+#define IW_MAX_GET_SPY         64      /* get */
+
+/* Maximum of address that you may get in the
+   list of access points in range */
+#define IW_MAX_AP              8
+
+/* Maximum size of the ESSID and NICKN strings */
+#define IW_ESSID_MAX_SIZE      32
+
+/* Modes of operation */
+#define IW_MODE_AUTO   0       /* Let the driver decides */
+#define IW_MODE_ADHOC  1       /* Single cell network */
+#define IW_MODE_INFRA  2       /* Multi cell network, roaming, ... */
+#define IW_MODE_MASTER 3       /* Synchronisation master or Access Point */
+#define IW_MODE_REPEAT 4       /* Wireless Repeater (forwarder) */
+#define IW_MODE_SECOND 5       /* Secondary master/repeater (backup) */
+#define IW_MODE_MONITOR        6       /* Passive monitor (listen only) */
+
+/* Maximum number of size of encoding token available
+ * they are listed in the range structure */
+#define IW_MAX_ENCODING_SIZES  8
+
+/* Maximum size of the encoding token in bytes */
+#define IW_ENCODING_TOKEN_MAX  32      /* 256 bits (for now) */
+
+/* Flags for encoding (along with the token) */
+#define IW_ENCODE_INDEX                0x00FF  /* Token index (if needed) */
+#define IW_ENCODE_FLAGS                0xFF00  /* Flags defined below */
+#define IW_ENCODE_MODE         0xF000  /* Modes defined below */
+#define IW_ENCODE_DISABLED     0x8000  /* Encoding disabled */
+#define IW_ENCODE_ENABLED      0x0000  /* Encoding enabled */
+#define IW_ENCODE_RESTRICTED   0x4000  /* Refuse non-encoded packets */
+#define IW_ENCODE_OPEN         0x2000  /* Accept non-encoded packets */
+#define IW_ENCODE_NOKEY         0x0800  /* Key is write only, so not present */
+
+/* Power management flags available (along with the value, if any) */
+#define IW_POWER_ON            0x0000  /* No details... */
+#define IW_POWER_TYPE          0xF000  /* Type of parameter */
+#define IW_POWER_PERIOD                0x1000  /* Value is a period/duration of  */
+#define IW_POWER_TIMEOUT       0x2000  /* Value is a timeout (to go asleep) */
+#define IW_POWER_MODE          0x0F00  /* Power Management mode */
+#define IW_POWER_UNICAST_R     0x0100  /* Receive only unicast messages */
+#define IW_POWER_MULTICAST_R   0x0200  /* Receive only multicast messages */
+#define IW_POWER_ALL_R         0x0300  /* Receive all messages though PM */
+#define IW_POWER_FORCE_S       0x0400  /* Force PM procedure for sending unicast */
+#define IW_POWER_REPEATER      0x0800  /* Repeat broadcast messages in PM period */
+#define IW_POWER_MODIFIER      0x000F  /* Modify a parameter */
+#define IW_POWER_MIN           0x0001  /* Value is a minimum  */
+#define IW_POWER_MAX           0x0002  /* Value is a maximum */
+#define IW_POWER_RELATIVE      0x0004  /* Value is not in seconds/ms/us */
+
+/* Transmit Power flags available */
+#define IW_TXPOW_TYPE          0x00FF  /* Type of value */
+#define IW_TXPOW_DBM           0x0000  /* Value is in dBm */
+#define IW_TXPOW_MWATT         0x0001  /* Value is in mW */
+#define IW_TXPOW_RANGE         0x1000  /* Range of value between min/max */
+
+/* Retry limits and lifetime flags available */
+#define IW_RETRY_ON            0x0000  /* No details... */
+#define IW_RETRY_TYPE          0xF000  /* Type of parameter */
+#define IW_RETRY_LIMIT         0x1000  /* Maximum number of retries*/
+#define IW_RETRY_LIFETIME      0x2000  /* Maximum duration of retries in us */
+#define IW_RETRY_MODIFIER      0x000F  /* Modify a parameter */
+#define IW_RETRY_MIN           0x0001  /* Value is a minimum  */
+#define IW_RETRY_MAX           0x0002  /* Value is a maximum */
+#define IW_RETRY_RELATIVE      0x0004  /* Value is not in seconds/ms/us */
+
+/* Scanning request flags */
+#define IW_SCAN_DEFAULT                0x0000  /* Default scan of the driver */
+#define IW_SCAN_ALL_ESSID      0x0001  /* Scan all ESSIDs */
+#define IW_SCAN_THIS_ESSID     0x0002  /* Scan only this ESSID */
+#define IW_SCAN_ALL_FREQ       0x0004  /* Scan all Frequencies */
+#define IW_SCAN_THIS_FREQ      0x0008  /* Scan only this Frequency */
+#define IW_SCAN_ALL_MODE       0x0010  /* Scan all Modes */
+#define IW_SCAN_THIS_MODE      0x0020  /* Scan only this Mode */
+#define IW_SCAN_ALL_RATE       0x0040  /* Scan all Bit-Rates */
+#define IW_SCAN_THIS_RATE      0x0080  /* Scan only this Bit-Rate */
+/* Maximum size of returned data */
+#define IW_SCAN_MAX_DATA       4096    /* In bytes */
+
+/* Max number of char in custom event - use multiple of them if needed */
+#define IW_CUSTOM_MAX          256     /* In bytes */
+
+/****************************** TYPES ******************************/
+
+/* --------------------------- SUBTYPES --------------------------- */
+/*
+ *     Generic format for most parameters that fit in an int
+ */
+struct iw_param
+{
+  __s32                value;          /* The value of the parameter itself */
+  __u8         fixed;          /* Hardware should not use auto select */
+  __u8         disabled;       /* Disable the feature */
+  __u16                flags;          /* Various specifc flags (if any) */
+};
+
+/*
+ *     For all data larger than 16 octets, we need to use a
+ *     pointer to memory allocated in user space.
+ */
+struct iw_point
+{
+  caddr_t      pointer;        /* Pointer to the data  (in user space) */
+  __u16                length;         /* number of fields or size in bytes */
+  __u16                flags;          /* Optional params */
+};
+
+/*
+ *     A frequency
+ *     For numbers lower than 10^9, we encode the number in 'm' and
+ *     set 'e' to 0
+ *     For number greater than 10^9, we divide it by the lowest power
+ *     of 10 to get 'm' lower than 10^9, with 'm'= f / (10^'e')...
+ *     The power of 10 is in 'e', the result of the division is in 'm'.
+ */
+struct iw_freq
+{
+       __s32           m;              /* Mantissa */
+       __s16           e;              /* Exponent */
+       __u8            i;              /* List index (when in range struct) */
+       __u8            pad;            /* Unused - just for alignement */
+};
+
+/*
+ *     Quality of the link
+ */
+struct iw_quality
+{
+       __u8            qual;           /* link quality (%retries, SNR,
+                                          %missed beacons or better...) */
+       __u8            level;          /* signal level (dBm) */
+       __u8            noise;          /* noise level (dBm) */
+       __u8            updated;        /* Flags to know if updated */
+};
+
+/*
+ *     Packet discarded in the wireless adapter due to
+ *     "wireless" specific problems...
+ *     Note : the list of counter and statistics in net_device_stats
+ *     is already pretty exhaustive, and you should use that first.
+ *     This is only additional stats...
+ */
+struct iw_discarded
+{
+       __u32           nwid;           /* Rx : Wrong nwid/essid */
+       __u32           code;           /* Rx : Unable to code/decode (WEP) */
+       __u32           fragment;       /* Rx : Can't perform MAC reassembly */
+       __u32           retries;        /* Tx : Max MAC retries num reached */
+       __u32           misc;           /* Others cases */
+};
+
+/*
+ *     Packet/Time period missed in the wireless adapter due to
+ *     "wireless" specific problems...
+ */
+struct iw_missed
+{
+       __u32           beacon;         /* Missed beacons/superframe */
+};
+
+/* ------------------------ WIRELESS STATS ------------------------ */
+/*
+ * Wireless statistics (used for /proc/net/wireless)
+ */
+struct iw_statistics
+{
+       __u16           status;         /* Status
+                                        * - device dependent for now */
+
+       struct iw_quality       qual;           /* Quality of the link
+                                                * (instant/mean/max) */
+       struct iw_discarded     discard;        /* Packet discarded counts */
+       struct iw_missed        miss;           /* Packet missed counts */
+};
+
+/* ------------------------ IOCTL REQUEST ------------------------ */
+/*
+ * This structure defines the payload of an ioctl, and is used 
+ * below.
+ *
+ * Note that this structure should fit on the memory footprint
+ * of iwreq (which is the same as ifreq), which mean a max size of
+ * 16 octets = 128 bits. Warning, pointers might be 64 bits wide...
+ * You should check this when increasing the structures defined
+ * above in this file...
+ */
+union  iwreq_data
+{
+       /* Config - generic */
+       char            name[IFNAMSIZ];
+       /* Name : used to verify the presence of  wireless extensions.
+        * Name of the protocol/provider... */
+
+       struct iw_point essid;          /* Extended network name */
+       struct iw_param nwid;           /* network id (or domain - the cell) */
+       struct iw_freq  freq;           /* frequency or channel :
+                                        * 0-1000 = channel
+                                        * > 1000 = frequency in Hz */
+
+       struct iw_param sens;           /* signal level threshold */
+       struct iw_param bitrate;        /* default bit rate */
+       struct iw_param txpower;        /* default transmit power */
+       struct iw_param rts;            /* RTS threshold threshold */
+       struct iw_param frag;           /* Fragmentation threshold */
+       __u32           mode;           /* Operation mode */
+       struct iw_param retry;          /* Retry limits & lifetime */
+
+       struct iw_point encoding;       /* Encoding stuff : tokens */
+       struct iw_param power;          /* PM duration/timeout */
+       struct iw_quality qual;         /* Quality part of statistics */
+
+       struct sockaddr ap_addr;        /* Access point address */
+       struct sockaddr addr;           /* Destination address (hw) */
+
+       struct iw_param param;          /* Other small parameters */
+       struct iw_point data;           /* Other large parameters */
+};
+
+/*
+ * The structure to exchange data for ioctl.
+ * This structure is the same as 'struct ifreq', but (re)defined for
+ * convenience...
+ * Do I need to remind you about structure size (32 octets) ?
+ */
+struct iwreq 
+{
+       union
+       {
+               char    ifrn_name[IFNAMSIZ];    /* if name, e.g. "eth0" */
+       } ifr_ifrn;
+
+       /* Data part (defined just above) */
+       union   iwreq_data      u;
+};
+
+/* -------------------------- IOCTL DATA -------------------------- */
+/*
+ *     For those ioctl which want to exchange mode data that what could
+ *     fit in the above structure...
+ */
+
+/*
+ *     Range of parameters
+ */
+
+struct iw_range
+{
+       /* Informative stuff (to choose between different interface) */
+       __u32           throughput;     /* To give an idea... */
+       /* In theory this value should be the maximum benchmarked
+        * TCP/IP throughput, because with most of these devices the
+        * bit rate is meaningless (overhead an co) to estimate how
+        * fast the connection will go and pick the fastest one.
+        * I suggest people to play with Netperf or any benchmark...
+        */
+
+       /* NWID (or domain id) */
+       __u32           min_nwid;       /* Minimal NWID we are able to set */
+       __u32           max_nwid;       /* Maximal NWID we are able to set */
+
+       /* Frequency */
+       __u16           num_channels;   /* Number of channels [0; num - 1] */
+       __u8            num_frequency;  /* Number of entry in the list */
+       struct iw_freq  freq[IW_MAX_FREQUENCIES];       /* list */
+       /* Note : this frequency list doesn't need to fit channel numbers */
+
+       /* signal level threshold range */
+       __s32   sensitivity;
+
+       /* Quality of link & SNR stuff */
+       struct iw_quality       max_qual;       /* Quality of the link */
+
+       /* Rates */
+       __u8            num_bitrates;   /* Number of entries in the list */
+       __s32           bitrate[IW_MAX_BITRATES];       /* list, in bps */
+
+       /* RTS threshold */
+       __s32           min_rts;        /* Minimal RTS threshold */
+       __s32           max_rts;        /* Maximal RTS threshold */
+
+       /* Frag threshold */
+       __s32           min_frag;       /* Minimal frag threshold */
+       __s32           max_frag;       /* Maximal frag threshold */
+
+       /* Power Management duration & timeout */
+       __s32           min_pmp;        /* Minimal PM period */
+       __s32           max_pmp;        /* Maximal PM period */
+       __s32           min_pmt;        /* Minimal PM timeout */
+       __s32           max_pmt;        /* Maximal PM timeout */
+       __u16           pmp_flags;      /* How to decode max/min PM period */
+       __u16           pmt_flags;      /* How to decode max/min PM timeout */
+       __u16           pm_capa;        /* What PM options are supported */
+
+       /* Encoder stuff */
+       __u16   encoding_size[IW_MAX_ENCODING_SIZES];   /* Different token sizes */
+       __u8    num_encoding_sizes;     /* Number of entry in the list */
+       __u8    max_encoding_tokens;    /* Max number of tokens */
+
+       /* Transmit power */
+       __u16           txpower_capa;   /* What options are supported */
+       __u8            num_txpower;    /* Number of entries in the list */
+       __s32           txpower[IW_MAX_TXPOWER];        /* list, in bps */
+
+       /* Wireless Extension version info */
+       __u8            we_version_compiled;    /* Must be WIRELESS_EXT */
+       __u8            we_version_source;      /* Last update of source */
+
+       /* Retry limits and lifetime */
+       __u16           retry_capa;     /* What retry options are supported */
+       __u16           retry_flags;    /* How to decode max/min retry limit */
+       __u16           r_time_flags;   /* How to decode max/min retry life */
+       __s32           min_retry;      /* Minimal number of retries */
+       __s32           max_retry;      /* Maximal number of retries */
+       __s32           min_r_time;     /* Minimal retry lifetime */
+       __s32           max_r_time;     /* Maximal retry lifetime */
+
+       /* Average quality of link & SNR */
+       struct iw_quality       avg_qual;       /* Quality of the link */
+       /* This should contain the average/typical values of the quality
+        * indicator. This should be the threshold between a "good" and
+        * a "bad" link (example : monitor going from green to orange).
+        * Currently, user space apps like quality monitors don't have any
+        * way to calibrate the measurement. With this, they can split
+        * the range between 0 and max_qual in different quality level
+        * (using a geometric subdivision centered on the average).
+        * I expect that people doing the user space apps will feedback
+        * us on which value we need to put in each driver...
+        */
+};
+
+/*
+ * Private ioctl interface information
+ */
+struct iw_priv_args
+{
+       __u32           cmd;            /* Number of the ioctl to issue */
+       __u16           set_args;       /* Type and number of args */
+       __u16           get_args;       /* Type and number of args */
+       char            name[IFNAMSIZ]; /* Name of the extension */
+};
+
+/* ----------------------- WIRELESS EVENTS ----------------------- */
+/*
+ * Wireless events are carried through the rtnetlink socket to user
+ * space. They are encapsulated in the IFLA_WIRELESS field of
+ * a RTM_NEWLINK message.
+ */
+
+/*
+ * A Wireless Event. Contains basically the same data as the ioctl...
+ */
+struct iw_event
+{
+       __u16           len;                    /* Real lenght of this stuff */
+       __u16           cmd;                    /* Wireless IOCTL */
+       union iwreq_data        u;              /* IOCTL fixed payload */
+};
+
+/* Size of the Event prefix (including padding and alignement junk) */
+#define IW_EV_LCP_LEN  (sizeof(struct iw_event) - sizeof(union iwreq_data))
+/* Size of the various events */
+#define IW_EV_CHAR_LEN (IW_EV_LCP_LEN + IFNAMSIZ)
+#define IW_EV_UINT_LEN (IW_EV_LCP_LEN + sizeof(__u32))
+#define IW_EV_FREQ_LEN (IW_EV_LCP_LEN + sizeof(struct iw_freq))
+#define IW_EV_POINT_LEN        (IW_EV_LCP_LEN + sizeof(struct iw_point))
+#define IW_EV_PARAM_LEN        (IW_EV_LCP_LEN + sizeof(struct iw_param))
+#define IW_EV_ADDR_LEN (IW_EV_LCP_LEN + sizeof(struct sockaddr))
+#define IW_EV_QUAL_LEN (IW_EV_LCP_LEN + sizeof(struct iw_quality))
+
+/* Note : in the case of iw_point, the extra data will come at the
+ * end of the event */
+
+#endif /* _LINUX_WIRELESS_H */
diff --git a/wireless_tools/wireless.7 b/wireless_tools/wireless.7
new file mode 100644 (file)
index 0000000..9ee50cb
--- /dev/null
@@ -0,0 +1,100 @@
+.\" Jean Tourrilhes - HPL - 2002
+.\" wireless.7
+.\"
+.TH WIRELESS 7 "12 July 2002" "net-tools" "Linux Programmer's Manual"
+.\"
+.\" NAME part
+.\"
+.SH NAME
+wireless \- Wireless Tools and Wireless Extensions
+.\"
+.\" SYNOPSIS part
+.\"
+.SH SYNOPSIS
+.B iwconfig
+.br
+.B iwpriv -a
+.br
+.\"
+.\" DESCRIPTION part
+.\"
+.SH DESCRIPTION
+The
+.B Wireless Extensions
+is an API allowing you manipulate Wireless LAN networking interfaces.
+It is composed of a variety of tools and configuration files. It is
+documented in more details in the Linux Wireless LAN Howto.
+.br
+The
+.B Wireless Tools
+are use to change configuration on the fly, to get statistics and
+diagnose those interfaces. They are described in their own man page
+(see below).
+.br
+.B Wireless configuration
+is specific to each Linux distribution. This man page will contain in
+the future the configuration procedure for a few common distributions
+(when I get the necessary info from them). For the time being, check
+the various files included with the Wireless Tools package.
+.\"
+.\" DEBIAN 3.0 part
+.\"
+.SH DEBIAN 3.0
+Debian 3.0 (and later) has integrated wireless configuration in their
+network scripts.
+.TP
+.B File :
+.I /etc/network/interfaces
+.TP
+.B Form :
+.RI wireless_ "<function> <value>"
+.br
+wireless_essid Home
+.br
+wireless_mode ad_hoc
+.TP
+.B See also :
+.I /etc/network/if-pre-up.d/wireless-tool
+.br
+.I /usr/share/doc/wireless.##/README.Debian
+.\"
+.\" PCMCIA part
+.\"
+.SH ORIGINAL PCMCIA SCRIPTS
+If you are using the original configuration scripts from the Pcmcia
+package, you can use this method.
+.TP
+.B File :
+.I /etc/pcmcia/wireless.opts
+.TP
+.B Form :
+*,*,*,*)
+.br
+    ESSID="MY_ESSID"
+.br
+    MODE="Managed"
+.br
+    ;;
+.TP
+.B See also :
+.I /etc/pcmcia/wireless
+.br
+File
+.I PCMCIA.txt
+part of Wireless Tools package
+.\"
+.\" AUTHOR part
+.\"
+.SH AUTHOR
+Jean Tourrilhes \- jt@hpl.hp.com
+.br
+.I http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/
+.\"
+.\" SEE ALSO part
+.\"
+.SH SEE ALSO
+.BR iwconfig (8),
+.BR iwlist (8),
+.BR iwspy (8),
+.BR iwpriv (8),
+.BR iwevent (8).