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