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 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 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 ----------------------------- */
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...
 
-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.
@@ -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
-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
@@ -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.
-       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>
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
-DYNAMIC=libiw.so.24
+DYNAMIC=libiw.so.25
 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
 
-# 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
 
-# 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
 
+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
-XCFLAGS=$(CFLAGS) $(WARN) $(HEADERS) $(WE_HEADER)
+XCFLAGS=$(CFLAGS) $(WARN) $(HEADERS) $(WEXT_FLAG) $(WELIB_FLAG) $(KERNEL_INCLUDES)
 PICFLAG=-fPIC
 
-LIBS= -lm
-
 all:: $(STATIC) $(DYNAMIC) $(PROGS)
 
 %: %.o
@@ -87,13 +119,19 @@ $(STATIC): $(OBJS)
 # 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 -d $(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."
+       install -m 755 -d $(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) 
@@ -102,6 +140,20 @@ realclean::
        $(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
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...
@@ -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.
-
-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 :
 -------------
@@ -132,4 +143,18 @@ home,*,*,00:60:1D:*|home,*,*,00:02:2D:*)
 
        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>
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.
 
+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
@@ -70,17 +76,35 @@ iwevent.c
        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
 ----------
-       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...
 
+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
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]
+.br
+.BI "iwconfig --help"
+.br
+.BI "iwconfig --version"
 .\"
 .\" 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
-(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
-(the node forward packets on the air),
+(the node forward packets between other wireless nodes),
 .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"
+.br
+.I "   iwconfig eth0 mode Ad-Hoc"
 .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 .
-To set a key other than the current key, append
+To set a key other than the current key, prepend or append
 .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:
-prefix.
+prefix. Passphrase is currently not supported.
 .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
+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"
@@ -253,6 +267,10 @@ discard non-encrypted packets.
 .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.
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, "                          [mode {managed|ad-hoc|...}\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, "                          [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, "       Check man pages for more details.\n\n");
 }
 
 
@@ -69,7 +71,10 @@ get_info(int                 skfd,
        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)
@@ -109,7 +114,7 @@ get_info(int                        skfd,
 
   /* 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)
     {
@@ -126,7 +131,7 @@ get_info(int                        skfd,
 
   /* 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)
@@ -283,7 +288,7 @@ display_info(struct wireless_info * info,
        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 */
@@ -744,7 +749,8 @@ set_info(int                skfd,           /* The socket */
            }
          else
            {
-             int       gotone = 1;
+             int       gotone = 0;
+             int       oldone;
              int       keylen;
              int       temp;
 
@@ -752,47 +758,64 @@ set_info(int              skfd,           /* The socket */
              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;
-                     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;
 
+             /* Check if we have any invalid argument */
              if(!gotone)
                ABORT_ARG_TYPE("Set Encode", SIOCSIWENCODE, args[i]);
+             /* Get back to last processed argument */
              --i;
            }
 
@@ -1335,16 +1358,19 @@ main(int        argc,
     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
-      /* 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
-       /* 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);
index 2a73d6d..719e131 100644 (file)
@@ -67,13 +67,27 @@ available (see
 .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
-specific hardware/driver combination.
+specific hardware/driver combination. Please refer to driver
+documentation for details.
 .\"
 .\" 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",
-            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;
+#endif /* WIRELESS_EXT > 14 */
       /* ----- 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"
-       "     -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' },
+  { "version", no_argument, NULL, 'v' },
   { NULL, 0, NULL, 0 }
 };
 
@@ -503,7 +524,7 @@ main(int    argc,
   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)
        {
@@ -511,6 +532,10 @@ main(int   argc,
          iw_usage(0);
          break;
 
+       case 'v':
+         return(iw_print_version_info("iwevent"));
+         break;
+
        default:
          iw_usage(1);
          break;
@@ -529,6 +554,13 @@ main(int   argc,
       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);
 
index 323ce8c..30c8890 100644 (file)
@@ -12,7 +12,9 @@ iwgetid \- Report ESSID, NWID or AP/Cell Address of wireless network
 .\" SYNOPSIS part
 .\"
 .SH SYNOPSIS
-.BI "iwgetid " [interface] " [--scheme] [--ap]"
+.BI "iwgetid " [interface] " [--scheme] [--ap] [--freq] [--mode]"
+.br
+.BI "                   [--protocol]
 .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
-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
@@ -57,6 +60,30 @@ Display the MAC address of the Wireless
 .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
 .\"
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 WTYPE_FREQ     2       /* Display frequency/channel */
+#define WTYPE_MODE     3       /* Display mode */
+#define WTYPE_PROTO    4       /* Display protocol name */
 
 /*
  * 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...
+ *
+ * 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]);
 }
 
+/*------------------------------------------------------------------*/
+/*
+ * 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 ************************/
 
 /*------------------------------------------------------------------*/
@@ -142,7 +202,7 @@ print_essid(int                     skfd,
   /* 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);
@@ -227,7 +287,118 @@ print_ap(int              skfd,
       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;
     }
 
@@ -249,20 +420,36 @@ print_one_device(int              skfd,
   int ret;
 
   /* Check wtype */
-  if(wtype == WTYPE_AP)
+  switch(wtype)
     {
+    case WTYPE_AP:
       /* 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);
@@ -310,15 +497,21 @@ iw_usage(int status)
 {
   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' },
+  { "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 }
@@ -339,7 +532,7 @@ main(int    argc,
   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)
        {
@@ -348,6 +541,21 @@ main(int   argc,
          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;
index 9d0f575..64c2d78 100644 (file)
@@ -9,8 +9,44 @@
  *     Copyright (c) 1997-2002 Jean Tourrilhes <jt@hpl.hp.com>
  */
 
+/***************************** INCLUDES *****************************/
+
 #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",
@@ -18,7 +54,11 @@ const char * const iw_operation_mode[] = { "Auto",
                                        "Managed",
                                        "Master",
                                        "Repeater",
-                                       "Secondary" };
+                                       "Secondary",
+                                       "Monitor" };
+
+/* Disable runtime version warning in iw_get_range_info() */
+int    iw_ignore_version = 0;
 
 /************************ 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 */
@@ -75,10 +113,17 @@ iw_get_ifname(char *       name,   /* Where to store the name */
   while(isspace(*buf))
     buf++;
 
+#ifndef IW_RESTRIC_ENUM
+  /* Get name up to the last ':'. Aliases may contain ':' in them,
+   * but the last one should be the separator */
+  end = strrchr(buf, ':');
+#else
   /* Get name up to ": "
    * Note : we compare to ": " to make sure to process aliased interfaces
-   * properly. */
+   * properly. Doesn't work on /proc/net/dev, because it doesn't guarantee
+   * a ' ' after the ':'*/
   end = strstr(buf, ": ");
+#endif
 
   /* Not found ??? To big ??? */
   if((end == NULL) || (((end - buf) + 1) > nsize))
@@ -111,8 +156,13 @@ iw_enum_devices(int                skfd,
   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");
+#endif
 
   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... */
+  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
-      /* 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
     {
-      /* 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);
 }
 
 /*------------------------------------------------------------------*/
 /*
+ * 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,
-                iwprivargs *   priv)
+                iwprivargs *   priv,
+                int            maxpriv)
 {
   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);
@@ -266,7 +415,10 @@ iw_get_basic_config(int                    skfd,
     /* 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)
@@ -295,7 +447,7 @@ iw_get_basic_config(int                     skfd,
 
   /* 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)
     {
@@ -426,7 +578,64 @@ iw_set_basic_config(int                    skfd,
   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 ***********************/
+/*
+ * 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)
 {
+#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)
     {
@@ -447,9 +667,10 @@ iw_float2freq(double       in,
     }
   else
     {
-      out->m = in;
+      out->m = (long) in;
       out->e = 0;
     }
+#endif /* WE_NOLIBM */
 }
 
 /*------------------------------------------------------------------*/
@@ -459,7 +680,17 @@ iw_float2freq(double       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);
+#endif /* WE_NOLIBM */
 }
 
 /*------------------------------------------------------------------*/
@@ -468,7 +699,7 @@ iw_freq2float(iwfreq *      in)
  */
 void
 iw_print_freq(char *   buffer,
-             float     freq)
+             double    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 ***********************/
 
 /*------------------------------------------------------------------*/
@@ -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)
  */
@@ -715,38 +988,44 @@ iw_in_key(char *          input,
   /* 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
-    {
-      /* 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);
 }
@@ -1094,6 +1373,7 @@ iw_in_inet(char *name, struct sockaddr *sap)
        return(1);
   }
 
+  /* Always use the resolver (DNS name + IP addresses) */
   if ((hp = gethostbyname(name)) == (struct hostent *)NULL) {
        errno = h_errno;
        return(-1);
@@ -1186,23 +1466,29 @@ iw_in_addr(int          skfd,
 
 /************************* MISC SUBROUTINES **************************/
 
+/* Size (in bytes) of various events */
+static const int priv_type_size[] = {
+       0,                              /* IW_PRIV_TYPE_NONE */
+       1,                              /* IW_PRIV_TYPE_BYTE */
+       1,                              /* IW_PRIV_TYPE_CHAR */
+       0,                              /* Not defined */
+       sizeof(__u32),                  /* IW_PRIV_TYPE_INT */
+       sizeof(struct iw_freq),         /* IW_PRIV_TYPE_FLOAT */
+       sizeof(struct sockaddr),        /* IW_PRIV_TYPE_ADDR */
+       0,                              /* Not defined */
+};
+
 /*------------------------------------------------------------------*/
 /*
  * Max size in bytes of an private argument.
  */
 int
-iw_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 ************************/
@@ -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_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[] = {
@@ -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 */
+       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[] = {
-       IW_EV_LCP_LEN,
+       IW_EV_LCP_LEN,          /* IW_HEADER_TYPE_NULL */
        0,
-       IW_EV_CHAR_LEN,
+       IW_EV_CHAR_LEN,         /* IW_HEADER_TYPE_CHAR */
        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;
-  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 */
@@ -1349,7 +1639,11 @@ iw_extract_event_stream(struct stream_descr *    stream, /* Stream of events */
         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;
@@ -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];
     }
+  /* Unknown events -> event_type=0 => IW_EV_LCP_LEN */
   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 */
@@ -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)
-    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 */
@@ -1399,7 +1702,7 @@ iw_extract_event_stream(struct stream_descr *     stream, /* Stream of events */
        /* No data */
        iwe->u.data.pointer = NULL;
 
-       /* Go to next event */
+      /* Go to next event */
       stream->current += iwe->len;
     }
   else
index 475e67e..5818a08 100644 (file)
 #include <linux/in.h>          /* For struct sockaddr_in */
 #endif /* LIBC5_HEADERS */
 
-#ifdef PRIVATE_WE_HEADER
+#ifdef WEXT_HEADER
 /* 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>
-#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 ******************************/
 
@@ -147,6 +137,7 @@ or you may just ignore this message"
 
 /* Paths */
 #define PROC_NET_WIRELESS      "/proc/net/wireless"
+#define PROC_NET_DEV           "/proc/net/dev"
 
 /* Some usefull constants */
 #define KILO   1e3
@@ -186,11 +177,11 @@ typedef struct sockaddr           sockaddr;
  * 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;
-  float                freq;                   /* Frequency/channel */
+  double       freq;                   /* Frequency/channel */
   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
 {
-  char         name[IFNAMSIZ];         /* Wireless/protocol name */
+  char         name[IFNAMSIZ + 1];     /* Wireless/protocol name */
   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 */
@@ -280,9 +271,12 @@ int
                          char *        ifname,
                          iwrange *     range);
 int
+       iw_print_version_info(char *    toolname);
+int
        iw_get_priv_info(int            skfd,
                         char *         ifname,
-                        iwprivargs *   priv);
+                        iwprivargs *   priv,
+                        int            maxpriv);
 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);
+/* --------------------- PROTOCOL SUBROUTINES --------------------- */
+int
+       iw_protocol_compare(char *      protocol1,
+                           char *      protocol2);
 /* -------------------- FREQUENCY SUBROUTINES --------------------- */
 void
        iw_float2freq(double    in,
@@ -299,7 +297,10 @@ double
        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);
@@ -373,7 +374,7 @@ int
                   struct sockaddr *    sap);
 /* ----------------------- MISC SUBROUTINES ------------------------ */
 int
-       iw_byte_size(int                args);
+       iw_get_priv_size(int            args);
 
 #if WIRELESS_EXT > 13
 /* ---------------------- EVENT SUBROUTINES ---------------------- */
@@ -389,7 +390,7 @@ int
 /**************************** VARIABLES ****************************/
 
 extern const char * const      iw_operation_mode[];
-#define IW_NUM_OPER_MODE       6
+#define IW_NUM_OPER_MODE       7
 
 /************************* 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"
+.br
+.BI "iwlist --help"
+.br
+.BI "iwlist --version"
 .\"
 .\" 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 --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
 .\"
index 0703f3e..8b751c2 100644 (file)
@@ -26,13 +26,17 @@ print_freq_info(int         skfd,
                char *          args[],         /* Command line args */
                int             count)          /* Args count */
 {
-  float                        freq;
+  struct iwreq         wrq;
   struct iw_range      range;
+  double               freq;
   int                  k;
+  int                  channel;
+  char                 buffer[128];    /* Temporary buffer */
 
   /* 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);
@@ -45,7 +49,7 @@ print_freq_info(int           skfd,
          /* 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);
@@ -55,16 +59,31 @@ print_freq_info(int         skfd,
                else
                  printf("%g kHz\n", freq / KILO);
            }
-         printf("\n\n");
        }
       else
-       printf("%-8.8s  %d channels\n\n",
+       printf("%-8.8s  %d channels\n",
               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 ************************/
+/*
+ * 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 */
 {
+  struct iwreq         wrq;
   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);
            }
-         printf("\n\n");
        }
       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);
 }
@@ -454,6 +481,7 @@ print_txpower_info(int              skfd,
                   char *       args[],         /* Command line args */
                   int          count)          /* Args count */
 {
+  struct iwreq         wrq;
   struct iw_range      range;
   int                  dbm;
   int                  mwatt;
@@ -469,7 +497,9 @@ print_txpower_info(int              skfd,
                      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);
@@ -488,10 +518,35 @@ print_txpower_info(int            skfd,
                }
              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);
@@ -680,7 +735,7 @@ print_scanning_token(struct iw_event *      event,  /* Extracted token */
       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);
@@ -748,6 +803,17 @@ print_scanning_token(struct iw_event *     event,  /* Extracted token */
        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);
@@ -1021,6 +1087,10 @@ main(int argc,
   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];
index 2f51651..d662840 100644 (file)
@@ -14,7 +14,11 @@ network interface
 .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
@@ -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
-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
@@ -46,6 +48,34 @@ to use those interface specific commands and their effect.
 .\"
 .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 .
@@ -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."
-.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
 .\"
index 333f98f..986ffd8 100644 (file)
 
 #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[] = {
-  "    ", "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 **************************/
 
@@ -32,52 +197,6 @@ iw_usage(void)
   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 **************************/
 
 /*------------------------------------------------------------------*/
@@ -85,44 +204,71 @@ print_priv_info(int                skfd,
  * 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          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;
-  while((++k < number) && strcmp(priv[k].name, args[i]));
+  while((++k < priv_num) && strcmp(priv[k].name, cmdname));
 
   /* 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);
     }
          
-  /* 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) &&
@@ -132,26 +278,28 @@ set_private(int           skfd,           /* Socket */
        {
        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 */
-         for(; i < wrq.u.data.length + 1; i++) {
+         for(; i < wrq.u.data.length; i++) {
            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 */
-         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 */
-         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:
@@ -174,6 +322,45 @@ set_private(int            skfd,           /* Socket */
            }
          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);
@@ -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",
-                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 */
@@ -194,20 +381,39 @@ set_private(int           skfd,           /* Socket */
 
   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) &&
-     (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
     {
-      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");
-      fprintf(stderr, "%X: %s\n", priv[k].cmd, strerror(errno));
+      fprintf(stderr, "%s (%X): %s\n", cmdname, priv[k].cmd, strerror(errno));
       return(-1);
     }
 
@@ -218,10 +424,11 @@ set_private(int           skfd,           /* Socket */
       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) &&
-        (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;
@@ -241,7 +448,7 @@ set_private(int             skfd,           /* Socket */
        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;
 
@@ -251,6 +458,41 @@ set_private(int            skfd,           /* Socket */
          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);
@@ -260,6 +502,133 @@ set_private(int           skfd,           /* Socket */
   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
@@ -280,14 +649,14 @@ set_roaming(int           skfd,           /* Socket */
   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 */
-  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)
@@ -373,13 +742,13 @@ port_type(int             skfd,           /* Socket */
   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 */
-  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)
@@ -485,27 +854,40 @@ main(int  argc,
     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
-      /* 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
-       /* 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
-         /* 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
-           /* 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);
index d550281..9eec627 100644 (file)
@@ -13,7 +13,7 @@ iwspy \- Get wireless statistics from specific nodes
 .SH SYNOPSIS
 .BI "iwspy " interface
 .br
-.BI "iwspy " interface " [+] " IPADDR " | " HWADDR " [...]"
+.BI "iwspy " interface " [+] " DNSNAME " | " IPADDR " | " HWADDR " [...]"
 .br
 .BI "iwspy " interface " off"
 .\"
@@ -38,21 +38,21 @@ wireless cells.
 .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
-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)
-this address and retry.
+this name/address and retry.
 .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
index 6b02c1b..21726e6 100644 (file)
 
 #include "iwlib.h"             /* Header */
 
+/* Backward compatibility */
+#ifndef IW_MAX_GET_SPY
+#define IW_MAX_GET_SPY 64
+#endif /* IW_MAX_GET_SPY */
+
 /************************* DISPLAY ROUTINES **************************/
 
 /*------------------------------------------------------------------*/
@@ -26,10 +31,10 @@ print_spy_info(int  skfd,
 {
   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];
-  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;
@@ -40,7 +45,7 @@ print_spy_info(int    skfd,
 
   /* 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)
     {
@@ -69,9 +74,8 @@ print_spy_info(int    skfd,
     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++)
     {
@@ -211,17 +215,20 @@ main(int  argc,
   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
-      /* 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
-       /* 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);
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).