* 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 ----------------------------- */
--- /dev/null
+ 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
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.
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
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>
-#
-# 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
# 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)
$(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
+ 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...
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 :
-------------
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>
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
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
.BI " [enc " E "] [key " K "] [power " P "] [retry " R ]
.br
.BI " [commit]
+.br
+.BI "iwconfig --help"
+.br
+.BI "iwconfig --version"
.\"
.\" DESCRIPTION part
.\"
.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,
.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]
.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"
.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.
{
fprintf(stderr, "Usage: iwconfig interface [essid {NN|on|off}]\n");
fprintf(stderr, " [nwid {NN|on|off}]\n");
+ fprintf(stderr, " [mode {managed|ad-hoc|...}\n");
fprintf(stderr, " [freq N.NNNN[k|M|G]]\n");
fprintf(stderr, " [channel N]\n");
fprintf(stderr, " [sens N]\n");
fprintf(stderr, " [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");
}
return(-ENOTSUP);
}
else
- strcpy(info->name, wrq.u.name);
+ {
+ strncpy(info->name, wrq.u.name, IFNAMSIZ);
+ info->name[IFNAMSIZ] = '\0';
+ }
/* Get ranges */
if(iw_get_range_info(skfd, ifname, &(info->range)) >= 0)
/* Get 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)
{
/* 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)
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 */
}
else
{
- int gotone = 1;
+ int gotone = 0;
+ int oldone;
int keylen;
int temp;
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;
}
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);
.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
.\"
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:
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 }
};
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)
{
iw_usage(0);
break;
+ case 'v':
+ return(iw_print_version_info("iwevent"));
+ break;
+
default:
iw_usage(1);
break;
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);
.\" SYNOPSIS part
.\"
.SH SYNOPSIS
-.BI "iwgetid " [interface] " [--scheme] [--ap]"
+.BI "iwgetid " [interface] " [--scheme] [--ap] [--freq] [--mode]"
+.br
+.BI " [--protocol]
.br
.\"
.\" DESCRIPTION part
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
.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
.\"
#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...
*/
/*------------------------------------------------------------------*/
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 ************************/
/*------------------------------------------------------------------*/
/* 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);
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;
}
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);
{
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 }
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)
{
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;
* 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",
"Managed",
"Master",
"Repeater",
- "Secondary" };
+ "Secondary",
+ "Monitor" };
+
+/* Disable runtime version warning in iw_get_range_info() */
+int iw_ignore_version = 0;
/************************ SOCKET SUBROUTINES *************************/
/*------------------------------------------------------------------*/
/*
- * 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 */
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))
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)
{
* 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);
/* If no wireless name : no wireless extensions */
return(-1);
else
- strcpy(info->name, wrq.u.name);
+ {
+ strncpy(info->name, wrq.u.name, IFNAMSIZ);
+ info->name[IFNAMSIZ] = '\0';
+ }
/* Get network ID */
if(iw_get_ext(skfd, ifname, SIOCGIWNWID, &wrq) >= 0)
/* Get 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)
{
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
+ */
/*------------------------------------------------------------------*/
/*
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)
{
}
else
{
- out->m = in;
+ out->m = (long) in;
out->e = 0;
}
+#endif /* WE_NOLIBM */
}
/*------------------------------------------------------------------*/
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 */
}
/*------------------------------------------------------------------*/
*/
void
iw_print_freq(char * buffer,
- float freq)
+ double freq)
{
if(freq < KILO)
sprintf(buffer, "Channel:%g", freq);
}
}
+/*------------------------------------------------------------------*/
+/*
+ * 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 ***********************/
/*------------------------------------------------------------------*/
/*------------------------------------------------------------------*/
/*
+ * 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)
*/
/* 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);
}
return(1);
}
+ /* Always use the resolver (DNS name + IP addresses) */
if ((hp = gethostbyname(name)) == (struct hostent *)NULL) {
errno = h_errno;
return(-1);
/************************* 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 ************************/
#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 9 /* 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[] = {
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 */
};
/*------------------------------------------------------------------*/
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 */
iwe->cmd, iwe->len);
#endif
- /* Get the type and length of that event */
+ /* Check invalid events */
+ if(iwe->len <= IW_EV_LCP_LEN)
+ return(-1);
+
+ /* Get the type and length of that event */
if(iwe->cmd <= SIOCIWLAST)
{
cmd_index = iwe->cmd - SIOCIWFIRST;
if(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 */
/* 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 */
/* No data */
iwe->u.data.pointer = NULL;
- /* Go to next event */
+ /* Go to next event */
stream->current += iwe->len;
}
else
#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 ******************************/
/* Paths */
#define PROC_NET_WIRELESS "/proc/net/wireless"
+#define PROC_NET_DEV "/proc/net/dev"
/* Some usefull constants */
#define KILO 1e3
* 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;
* 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 */
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,
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,
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);
struct sockaddr * sap);
/* ----------------------- MISC SUBROUTINES ------------------------ */
int
- iw_byte_size(int args);
+ iw_get_priv_size(int args);
#if WIRELESS_EXT > 13
/* ---------------------- EVENT SUBROUTINES ---------------------- */
/**************************** VARIABLES ****************************/
extern const char * const iw_operation_mode[];
-#define IW_NUM_OPER_MODE 6
+#define IW_NUM_OPER_MODE 7
/************************* INLINE FUNTIONS *************************/
/*
.BI "iwlist " interface " txpower"
.br
.BI "iwlist " interface " retry"
+.br
+.BI "iwlist --help"
+.br
+.BI "iwlist --version"
.\"
.\" DESCRIPTION part
.\"
.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
.\"
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);
/* 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);
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 !
+ */
/*------------------------------------------------------------------*/
/*
char * args[], /* Command line args */
int count) /* Args count */
{
+ struct iwreq wrq;
struct iw_range range;
int k;
char buffer[128];
/* 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);
}
char * args[], /* Command line args */
int count) /* Args count */
{
+ struct iwreq wrq;
struct iw_range range;
int dbm;
int mwatt;
ifname);
else
{
- if((range.num_txpower > 0) && (range.num_txpower < IW_MAX_TXPOWER))
+ if((range.num_txpower <= 0) || (range.num_txpower > IW_MAX_TXPOWER))
+ printf("%-8.8s No transmit-powers ? Please update driver...\n\n", ifname);
+ else
{
printf("%-8.8s %d available transmit-powers :\n",
ifname, range.num_txpower);
}
printf("\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);
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);
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);
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];
.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
.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
.\"
.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 .
.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
.\"
#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 **************************/
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 **************************/
/*------------------------------------------------------------------*/
* 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) &&
{
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:
}
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);
(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 */
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);
}
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;
case IW_PRIV_TYPE_INT:
/* Display args */
for(j = 0; j < n; j++)
- printf("%d ", ((u_int *) buffer)[j]);
+ printf("%d ", ((__s32 *) buffer)[j]);
printf("\n");
break;
printf("%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);
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
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)
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)
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);
.SH SYNOPSIS
.BI "iwspy " interface
.br
-.BI "iwspy " interface " [+] " IPADDR " | " HWADDR " [...]"
+.BI "iwspy " interface " [+] " DNSNAME " | " IPADDR " | " HWADDR " [...]"
.br
.BI "iwspy " interface " off"
.\"
.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
#include "iwlib.h" /* Header */
+/* Backward compatibility */
+#ifndef IW_MAX_GET_SPY
+#define IW_MAX_GET_SPY 64
+#endif /* IW_MAX_GET_SPY */
+
/************************* DISPLAY ROUTINES **************************/
/*------------------------------------------------------------------*/
{
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;
/* 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)
{
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++)
{
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);
--- /dev/null
+/* 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 */
+
+++ /dev/null
-/* 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 */
--- /dev/null
+/* 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 */
+
+++ /dev/null
-/* 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 */
--- /dev/null
+/* 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+.\" 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).