Android-x86
Fork

  • R/O
  • HTTP
  • SSH
  • HTTPS

external-wireless-tools: コミット

external/wireless-tools


コミットメタ情報

リビジョンc7b2e81e6d53daac413a19d5446ab68b8395c849 (tree)
日時2016-10-12 06:17:19
作者chris-kirby <chris.kirby@hpe....>
コミッターchris-kirby

ログメッセージ

v29

変更サマリ

差分

--- /dev/null
+++ b/wireless_tools/19-udev-ifrename.rules
@@ -0,0 +1,13 @@
1+# udev rules to properly integrate ifrename.
2+# Renaming is done using /etc/iftab, with full ifrename functionality.
3+# Require udev version 107 or later.
4+# Please double check the path to ifrename, and make sure its available
5+# when udev runs (i.e. on boot partition).
6+
7+# Enable this rule to test with udevtest.
8+#ENV{UDEV_LOG}=="6", SUBSYSTEM=="net", ACTION=="add", IMPORT="/sbin/ifrename -D -V -u -i %k", NAME:="%k"
9+
10+# Main ifrename rule.
11+# If interface is found in /etc/iftab, subsequent rename rules are bypassed.
12+# If interface is not found in /etc/iftab, subsequent rename rules applies.
13+SUBSYSTEM=="net", ACTION=="add", IMPORT="/sbin/ifrename -u -i %k", NAME:="%k"
--- a/wireless_tools/CHANGELOG.h
+++ b/wireless_tools/CHANGELOG.h
@@ -1,7 +1,7 @@
11 /*
22 * Wireless Tools
33 *
4- * Jean II - HPLB 97->99 - HPL 99->04
4+ * Jean II - HPLB 97->99 - HPL 99->07
55 *
66 * The changelog...
77 *
@@ -625,6 +625,121 @@
625625 * o Add WE-20 headers, compile with that as default
626626 * ---
627627 * o Fix 'inline' for gcc-4 as well. Grrr... [iwlib]
628+ *
629+ * wireless 29 :
630+ * -----------
631+ * o Add new power value : 'power saving' [iwconfig/iwlist/iwlib]
632+ * o Optimise getting iwrange when setting TxPower [iwconfig]
633+ * o Optimise displaying current power values (better loop) [iwlist]
634+ * ---
635+ * o Add modulation bitmasks ioctls [iwconfig/iwlist]
636+ * o Add short and long retries [iwconfig/iwlist/iwlib]
637+ * o Fix 'relative' power saving to not be *1000 [iwconfig/iwlib]
638+ * o iw_print_pm_value() require we_version [iwlib]
639+ * o Optimise displaying range power values (subroutine) [iwlist]
640+ * ---
641+ * o Fix 'relative' retry to not be *1000 [iwconfig/iwlib]
642+ * o iw_print_retry_value() require we_version [iwlib]
643+ * o Optimise getting iwrange when setting PowerSaving [iwconfig]
644+ * o Optimise displaying current retry values (better loop) [iwlist]
645+ * o Optimise displaying range retry values (subroutine) [iwlist]
646+ * ---
647+ * o Fix stupid bug in displaying range retry values [iwlist]
648+ * ---
649+ * o Add support for unicast and broadcast bitrates [iwconfig/iwlist]
650+ * ---
651+ * o Replace spaghetti code with real dispatcher in set_info() [iwconfig]
652+ * Code is more readable, maintainable, and save 700 bytes...
653+ * o Drop 'domain' alias for 'nwid'. Obsolete. [iwconfig]
654+ * o Make iw_usage() use dispatcher data instead of hardcoded [iwconfig]
655+ * o Factor out modifier parsing for retry/power [iwconfig]
656+ * o Fix iwmulticall to compile with new dispatcher above [iwmulticall]
657+ * o Add WE_ESSENTIAL compile option to drop 10kB [Makefile]
658+ * ---
659+ * o Update manpages with new features above [man]
660+ * ---
661+ * o Add temp variable to sscanf() to fix 64 bits issues [iwconfig]
662+ * o De-inline get_pm_value/get_retry_value to reduce footprint [iwlist]
663+ * o Optimise iw_print_ie_cipher/iw_print_ie_auth [iwlist]
664+ * o Add "Memory footprint reduction" section in doc [README]
665+ * o Add 'last' scan option for left-over scan [iwlist]
666+ * (From Stavros Markou <smarkou@patras.atmel.com>)
667+ * o Add 'essid' scan option for directed scan [iwlist]
668+ * ---
669+ * (Bug reported by Henrik Brix Andersen <brix@gentoo.org>)
670+ * o Fix segfault on setting bitrate (parse wrong arg) [iwconfig]
671+ * ---
672+ * o Revert 'CC=gcc' to normal [Makefile]
673+ * o Integrate properly patch below [iwlist]
674+ * (From Brian Eaton <eaton.lists@gmail.com>)
675+ * o More WPA support : iwlist auth/wpakeys/genie [iwlist]
676+ * ---
677+ * o Tweak man pages : interface is often optional [iwlist.8/iwspy.8]
678+ * o Drop obsolete port/roam code from [iwpriv]
679+ * (From Pavel Roskin <proski@gnu.org>)
680+ * o Fix bug where all auth masks use iw_auth_capa_name [iwlist]
681+ * (From Dima Ryazanov <someone@berkeley.edu>)
682+ * o Fix iw_scan()/iw_process_scan() for non-root -> EPERM [iwlib]
683+ * (Bug reported by Arkadiusz Miskiewicz <arekm@pld-linux.org>)
684+ * o Fix "iwconfig nickname" (was abreviated) [iwconfig]
685+ * (Bug reported by Charles Plessy)
686+ * o Invalid mode from driver segfault iwlist scan [iwlist]
687+ * (From Aurelien Jacobs <aurel@gnuage.org>)
688+ * o Replace index() with strchr() [iwlib/iwconfig/iwpriv]
689+ * (From Jens Thoms Toerring)
690+ * o Parser/printf/sscanf fixes and optimisation [iwconfig]
691+ * ---
692+ * (From Pavel Roskin <proski@gnu.org>)
693+ * o Fix bug extracting mountpoint of sysfs (wrong field) [ifrename]
694+ * (Suggested by Pavel Roskin <proski@gnu.org>)
695+ * o Read sysfs symlinks transparently [ifrename]
696+ * ---
697+ * o Fix README header to talk about ifrename [README]
698+ * o Add 'prevname' selector for udev compatibility [ifrename]
699+ * o Read parent directory names in SYSFS selector [ifrename]
700+ * o Make dry-run output compatible with udev [ifrename]
701+ * o Update man page with useful SYSFS selectors [iftab.5]
702+ * ---
703+ * o Factorise wildcard rewrite '*'->'%d' to hide it from -D -V [ifrename]
704+ * o Reorganise sysfs description, better wording [iftab.5]
705+ * (Suggested by Pavel Roskin <proski@gnu.org>)
706+ * o Enhance explanation of arp and iwproto [iftab.5]
707+ * ---
708+ * (Bug reported by Johannes Berg <johannes@sipsolutions.net>)
709+ * o Band-aid for the 64->32bit iwevent/iwscan issues [iwlib]
710+ * ---
711+ * o Better band-aid for the 64->32bit iwevent/iwscan issues [iwlib]
712+ * (Suggested by Kay Sievers <kay.sievers@vrfy.org>)
713+ * o Add udev compatible output, print new DEVPATH [ifrename]
714+ * ---
715+ * o Fix DEVPATH output to use the real devpath from udev [ifrename]
716+ * o Add udev rules for ifrename integration [19-udev-ifrename.rules]
717+ * ---
718+ * o Add largest bitrate in easy scan API [iwlib]
719+ * ---
720+ * o Debug version : output IW_EV_LCP_LEN [iwlist]
721+ * ---
722+ * (Bug reported by Santiago Gala/Roy Marples)
723+ * o Fix 64->32bit band-aid on 64 bits, target is local aligned [iwlib]
724+ * ---
725+ * (Bug reported by Santiago Gala/Roy Marples)
726+ * o More fix to the 64->32bit band-aid on 64 bits [iwlib]
727+ * ---
728+ * (Bug reported by Dimitris Kogias)
729+ * o Fix GENIE parsing os chipher/key_mngt [iwlist]
730+ * (Bug reported by Guus Sliepen <guus@debian.org>)
731+ * o Compiler warning on DEBUG code [iwlist]
732+ * ---
733+ * o --version output WE_MAX_VERSION instead of WE_VERSION [iwlib]
734+ * o Change iwstats dBm range to [-192;63] in iw_print_stats() [iwlib.c]
735+ * o Implement iwstats IW_QUAL_RCPI in iw_print_stats() [iwlib.c]
736+ * (Bug reported by Guus Sliepen <guus@sliepen.eu.org>)
737+ * o LINUX_VERSION_CODE removed, only use GENERIC_HEADERS [iwlib.h]
738+ * (Bug reported by Johan Danielsson <joda11147@gmail.com>)
739+ * o Fix OUI type check for WPA 1 IE [iwlist.c]
740+ * ---
741+ * (Bug reported by Florent Daignière)
742+ * o Don't look for "fixed" out of array in set_txpower_info() [iwconfig]
628743 */
629744
630745 /* ----------------------------- TODO ----------------------------- */
@@ -635,10 +750,7 @@
635750 * --------
636751 * Make disable a per encryption key modifier if some hardware
637752 * requires it.
638- *
639- * iwpriv :
640- * ------
641- * Remove 'port' and 'roam' cruft now that we have mode in iwconfig
753+ * IW_QUAL_RCPI
642754 *
643755 * iwspy :
644756 * -----
--- a/wireless_tools/IFRENAME-VS-XXX.txt
+++ b/wireless_tools/IFRENAME-VS-XXX.txt
@@ -79,21 +79,21 @@ interfaces, with rules such as :
7979 http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev.html
8080
8181 Advantages over 'ifrename' :
82- + integrated into 'udev'
8382 + simpler to setup if 'udev' is already properly setup
83+ + automatically generates persistent rules
8484 Drawbacks compared to 'ifrename' :
8585 - Less selectors that 'ifrename'
8686 - Require kernel 2.6.X or later with sysfs support
8787 - Do no support non-hotplug interfaces
8888 - Require 'udev', not everybody uses it (static /dev, devfs)
89- - Does not support module on-demand loading
9089 Comments :
9190 o 'udev' support many selectors, basically all those
92-present in 'sysfs', even if the documentation only show instructions
93-to use the MAC address (which is problematic with virtual devices some
94-drivers - see above). 'ifrename' can also use all selectors present in
95-'sysfs' (like 'udev'), plus some other selectors not present in sysfs
96-that were found to be useful.
91+present in 'sysfs' (excluding symlinks), even if the documentation
92+only show instructions to use the MAC address (which is problematic
93+with virtual devices some drivers - see above). 'ifrename' can also
94+use all selectors present in 'sysfs' (like 'udev'), can use sysfs
95+symlinks and parent directories, plus some other selectors not present
96+in sysfs that were found to be useful.
9797 o Not all interfaces are managed by hotplug. All
9898 virtual devices, such as tunnels and loopbacks, are not associated
9999 with a hardware bus, and therefore are not managed by hotplug. All
@@ -102,7 +102,9 @@ hotplug. 'udev' can't deal with those devices.
102102 o It is common practice on embedded system to use a
103103 static /dev and not 'udev' to save space and boot time. And to not use
104104 hotplug for the same reasons.
105- o 'ifrename' could be better integrated in 'udev', I don't foresee any technical issues.
105+ o 'ifrename' has now a udev compatiblity mode that
106+enables to trivially integrate it into 'udev' as an IMPORT rule. This
107+requires udev version 107 or better and ifrename 29-pre17 or better.
106108
107109 SELECTOR AWARE NETWORK SCRIPTS
108110 ------------------------------
--- a/wireless_tools/INSTALL
+++ b/wireless_tools/INSTALL
@@ -36,17 +36,87 @@ Create a local copy of the tools :
3636 --------------------------------
3737 By default, the package is built with iwlib as a dynamic
3838 library, and the tool will expect to use the default version of libiw
39-on the system.
39+on the system. This means you can't use the tools until they are
40+properly installed.
4041 If you just want to experiment with a "local" version of the
4142 tools, you may want to pass the BUILD_STATIC flag to Makefile. It will
4243 create a self contained version of the tools.
43--------------
44-make clean
45-make BUILD_STATIC='y'
46--------------
44+ -------------
45+ make clean
46+ make BUILD_STATIC='y'
47+ -------------
4748 The resulting binary can be used in the compilation directory
4849 or installed in any place you like.
4950
51+Other useful Makefile options :
52+-----------------------------
53+ PREFIX : where the tools will be installed (default : /usr/local)
54+ CC : Compiler to use (defaul : gcc)
55+ BUILD_STATIC : build tools with a static version of the wireless lib
56+ BUILD_NOLIBM : build tools without mathematical lib (slower)
57+ BUILD_STRIPPING : strip symbols from tools/lib.
58+ BUILD_WE_ESSENTIAL : remove less used and obsolete features.
59+
60+ You can pass those options on the command line of make, or
61+modify the top of the Makefile. You can also set them as environment
62+variable, but this is not recommended.
63+ If you pass those options on the command line, you should pass
64+the same command line options for all invocations of make ("make" and
65+"make install").
66+
67+Memory footprint reduction :
68+--------------------------
69+ The Wireless Tools are used in various embedded systems where
70+memory footprint is a great concern. The Wireless Tools package offer
71+multiple options to customise the compilation depending on the level
72+of features you want.
73+ The list below details the must useful combinations of these
74+options, from the largest footprint to the smallest. Footprint depend
75+on lot's of factor and is purely indicative (version 29-pre7+, i386,
76+glibc, gcc 3.3.5).
77+
78+ 1) Static build
79+ Command line : make BUILD_STATIC='y'
80+ - : Largest footprint
81+ - : libiw not included (other third party tools may depend on it)
82+ Size : ~280 kB
83+
84+ 2) Default build
85+ Command line : make
86+ + : Fully featured version of the tools
87+ - : Largest footprint (except for static version of tools)
88+ Size : ~190 kB (libiw : ~29 kB ; ifrename : ~29 kB)
89+
90+ 3) Stripping (remove function symbols)
91+ Command line : make BUILD_STRIPPING='y'
92+ + : Fully featured version of the tools
93+ - : Still quite large
94+ Size : ~110 kB (libiw : ~23 kB ; ifrename : ~17 kB)
95+
96+ 4) Multicall version (include stripping)
97+ Command line : make iwmulticall ; make install-iwmulticall
98+ + : Fully featured version of the tools
99+ + : Small
100+ - : libiw not included (other third party tools may depend on it)
101+ - : ifrename is not included
102+ Size : ~55 kB
103+
104+ 5) Multicall + Essential
105+ Command line : make BUILD_WE_ESSENTIAL='y' iwmulticall
106+ + : Smaller
107+ - : Some less used features are left out
108+ - : libiw not included (other third party tools may depend on it)
109+ - : ifrename is not included
110+ Size : ~44 kB
111+
112+ 6) iwconfig only + essential + static
113+ Command line : make BUILD_WE_ESSENTIAL='y' BUILD_STATIC='y' BUILD_STRIPPING='y' iwconfig
114+ + : Very small
115+ - : Very limited functionality : no scanning, no event, no iwpriv
116+ - : libiw not included (other third party tools may depend on it)
117+ - : ifrename is not included
118+ Size : ~28 kB
119+
50120 Wireless headers (past history) :
51121 -------------------------------
52122 Previous version of the Wireless Tools had to be compiled with
@@ -63,18 +133,6 @@ you that.
63133 Note that the previous option to make versioned installed of
64134 the tools no longer make sense and therefore is gone.
65135
66-Other useful Makefile options :
67------------------------------
68- PREFIX : where the tools will be installed (default : /usr/local)
69- BUILD_STATIC : build tools with a static version of the wireless lib
70- BUILD_NOLIBM : build tools without mathematical lib (slower)
71- Note that you should pass the same command line options for
72-all invocations of make ("make" and "make install").
73-
74- If you want the absolute minimal footprint, you may want to
75-look into the multicall version of the tools. You can build it with
76-"make iwmulticall" and install it with "make install-iwmulticall".
77-
78136 Old kernel with older Wireless Extensions :
79137 -----------------------------------------
80138 Kernel prior to 2.2.14 : Those kernels include Wireless
--- a/wireless_tools/Makefile
+++ b/wireless_tools/Makefile
@@ -2,31 +2,36 @@
22 ## Please check the configurion parameters below
33 ##
44
5-## Installation directory. By default, go in /usr/local
5+## Installation directory. By default, go in /usr/local.
66 ## Distributions should probably use /, but they probably know better...
77 ifndef PREFIX
88 PREFIX = /usr/local
99 endif
1010
11-## Compiler to use (modify this for cross compile)
11+## Compiler to use (modify this for cross compile).
1212 CC = gcc
13-## Other tools you need to modify for cross compile (static lib only)
13+## Other tools you need to modify for cross compile (static lib only).
1414 AR = ar
1515 RANLIB = ranlib
1616
17-## Uncomment this to build tools using static version of the library
17+## Uncomment this to build tools using static version of the library.
1818 ## Mostly useful for embedded platforms without ldd, or to create
1919 ## a local version (non-root).
2020 # BUILD_STATIC = y
2121
22-## Uncomment this to build without using libm (less efficient)
22+## Uncomment this to build without using libm (less efficient).
2323 ## This is mostly useful for embedded platforms without maths.
2424 # BUILD_NOLIBM = y
2525
26-## Uncomment this to strip binary from symbols. This reduce binary size
26+## Uncomment this to strip binary from symbols. This reduce binary size.
2727 ## by a few percent but make debug worse...
2828 # BUILD_STRIPPING = y
2929
30+## Uncomment this to build with only essential functionality.
31+## This leaves out the less used features and cut in half the tools.
32+## This is mostly useful for embedded platforms without limited feature needs.
33+# BUILD_WE_ESSENTIAL = y
34+
3035 # ***************************************************************************
3136 # ***** Most users should not need to change anything beyond this point *****
3237 # ***************************************************************************
@@ -91,12 +96,17 @@ else
9196 STRIPFLAGS=
9297 endif
9398
99+# Do we want to build with only essential functionality ?
100+ifdef BUILD_WE_ESSENTIAL
101+ WEDEF_FLAG= -DWE_ESSENTIAL=y
102+endif
103+
94104 # Other flags
95105 CFLAGS=-Os -W -Wall -Wstrict-prototypes -Wmissing-prototypes -Wshadow \
96106 -Wpointer-arith -Wcast-qual -Winline -I.
97107 #CFLAGS=-O2 -W -Wall -Wstrict-prototypes -I.
98108 DEPFLAGS=-MMD
99-XCFLAGS=$(CFLAGS) $(DEPFLAGS) $(WARN) $(HEADERS) $(WELIB_FLAG)
109+XCFLAGS=$(CFLAGS) $(DEPFLAGS) $(WARN) $(HEADERS) $(WELIB_FLAG) $(WEDEF_FLAG)
100110 PICFLAG=-fPIC
101111
102112 # Standard compilation targets
--- a/wireless_tools/README
+++ b/wireless_tools/README
@@ -1,10 +1,12 @@
1- Wireless Tools
2- --------------
1+ Wireless Tools & IfRename
2+ -------------------------
33
44 This package contains the Wireless tools, used to manipulate
55 the Wireless Extensions. The Wireless Extensions is an interface
66 allowing you to set Wireless LAN specific parameters and get the
77 specific stats.
8+ It also contains the IfRename package, used for advance
9+renaming of network interfaces.
810
911 web page :
1012 --------
@@ -112,6 +114,10 @@ iwlib.c
112114 The Wireless Tools helper library. May be useful if you want
113115 to create your own applications using Wireless Extensions.
114116
117+iwmulticall.c
118+-------------
119+ Multicall version of the tools for embedded systems.
120+
115121 Changelog, contributions :
116122 ------------------------
117123 See CHANGELOG.h
@@ -136,6 +142,10 @@ more tricky features of Wireless Extensions in your driver.
136142 alone works, but it should point you in the proper direction.
137143 Also, have a look at existing drivers in the Linux kernel.
138144
145+19-udev-ifrename.rules :
146+----------------------
147+ udev rules to integrate properly ifrename (udev >= 107).
148+
139149 Other tools :
140150 -----------
141151 My web page lists many other tools using Wireless
--- a/wireless_tools/ifrename.8
+++ b/wireless_tools/ifrename.8
@@ -1,7 +1,7 @@
1-.\" Jean II - HPL - 2004
1+.\" Jean II - HPL - 2004-2007
22 .\" ifrename.8
33 .\"
4-.TH IFRENAME 8 "01 March 2004" "wireless-tools" "Linux Programmer's Manual"
4+.TH IFRENAME 8 "26 February 2007" "wireless-tools" "Linux Programmer's Manual"
55 .\"
66 .\" NAME part
77 .\"
@@ -11,7 +11,7 @@ ifrename \- rename network interfaces based on various static criteria
1111 .\" SYNOPSIS part
1212 .\"
1313 .SH SYNOPSIS
14-.B "ifrename [-c configfile] [-p] [-d] [-v] [-V] [-D]"
14+.B "ifrename [-c configfile] [-p] [-d] [-u] [-v] [-V] [-D]"
1515 .br
1616 .B "ifrename [-c configfile] [-i interface] [-n newname]"
1717 .\"
@@ -124,12 +124,38 @@ In any case, name swapping and the use of this feature is discouraged,
124124 and you are invited to choose unique and unambiguous names for your
125125 interfaces...
126126 .TP
127+.B -u
128+Enable
129+.I udev
130+output mode. This enables proper integration of
131+.B ifrename
132+in the
133+.I udev
134+framework,
135+.BR udevd (8)
136+will use
137+.B ifrename
138+to assign interface names present in
139+.IR /etc/iftab .
140+In this mode the output of ifrename can be parsed
141+directly by
142+.BR udevd (8)
143+as an IMPORT action. This requires
144+.I udev
145+version 107 or later.
146+.TP
127147 .B -D
128148 Dry-run mode. Ifrename won't change any interface, it will only print
129149 new interface name, if applicable, and return.
130150 .br
131151 In dry-run mode, interface name wildcards are not resolved. New
132152 interface name is printed, even if it is the same as the old name.
153+.br
154+Be also aware that some selectors can only be read by root, for
155+example those based on
156+.BR ethtool ),
157+and will fail silently if run by a normal user. In other words,
158+dry-run mode under a standard user may not give the expected result.
133159 .TP
134160 .B -V
135161 Verbose mode. Ifrename will display internal results of parsing its
--- a/wireless_tools/ifrename.c
+++ b/wireless_tools/ifrename.c
@@ -1,14 +1,14 @@
11 /*
22 * Wireless Tools
33 *
4- * Jean II - HPL 04
4+ * Jean II - HPL 04 -> 07
55 *
66 * Main code for "ifrename". This is tool allows to rename network
77 * interfaces based on various criteria (not only wireless).
88 * You need to link this code against "iwlib.c" and "-lm".
99 *
1010 * This file is released under the GPL license.
11- * Copyright (c) 2004 Jean Tourrilhes <jt@hpl.hp.com>
11+ * Copyright (c) 2007 Jean Tourrilhes <jt@hpl.hp.com>
1212 */
1313
1414 /*
@@ -30,7 +30,7 @@
3030 * Difference with standard 'nameif' :
3131 * o 'nameif' has only a single selector, the interface MAC address.
3232 * o Modular selector architecture, easily add new selectors.
33- * o Wide range of selector, including sysfs...
33+ * o Wide range of selector, including sysfs and sysfs symlinks...
3434 * o hotplug invocation support.
3535 * o module loading support.
3636 * o MAC address wildcard.
@@ -82,7 +82,8 @@ const int SELECT_INTERRUPT = 9; /* Select by HW Irq line */
8282 const int SELECT_IWPROTO = 10; /* Select by Wireless Protocol */
8383 const int SELECT_PCMCIASLOT = 11; /* Select by Pcmcia Slot */
8484 const int SELECT_SYSFS = 12; /* Select by sysfs file */
85-#define SELECT_NUM 13
85+const int SELECT_PREVNAME = 13; /* Select by previous interface name */
86+#define SELECT_NUM 14
8687
8788 #define HAS_MAC_EXACT 1
8889 #define HAS_MAC_FILTER 2
@@ -99,6 +100,7 @@ const struct option long_opt[] =
99100 {"interface", 1, NULL, 'i' },
100101 {"newname", 1, NULL, 'n' },
101102 {"takeover", 0, NULL, 't' },
103+ {"udev", 0, NULL, 'u' },
102104 {"version", 0, NULL, 'v' },
103105 {"verbose", 0, NULL, 'V' },
104106 {NULL, 0, NULL, '\0' },
@@ -108,8 +110,8 @@ const struct option long_opt[] =
108110 #define PCMCIA_STAB1 "/var/lib/pcmcia/stab"
109111 #define PCMCIA_STAB2 "/var/run/stab"
110112
111-/* Max number of sysfs file we support */
112-#define SYSFS_MAX_FILE 5
113+/* Max number of sysfs file types we support */
114+#define SYSFS_MAX_FILE 8
113115
114116 /* Userspace headers lag, fix that... */
115117 #ifndef ARPHRD_IEEE1394
@@ -160,6 +162,8 @@ typedef struct if_mapping
160162
161163 /* Name of this interface */
162164 char ifname[IFNAMSIZ+1];
165+ char * sysfs_devpath;
166+ int sysfs_devplen;
163167
164168 /* Selectors for this interface */
165169 int active[SELECT_NUM]; /* Selectors active */
@@ -177,6 +181,7 @@ typedef struct if_mapping
177181 char iwproto[IFNAMSIZ + 1]; /* Wireless/protocol name */
178182 int pcmcia_slot; /* Pcmcia slot */
179183 char * sysfs[SYSFS_MAX_FILE]; /* sysfs selectors */
184+ char prevname[IFNAMSIZ+1]; /* previous interface name */
180185 } if_mapping;
181186
182187 /* Extra parsing information when adding a mapping */
@@ -358,6 +363,21 @@ static int
358363 const char * ifname,
359364 struct if_mapping * target,
360365 int flag);
366+static int
367+ mapping_addprevname(struct if_mapping * ifnode,
368+ int * active,
369+ char * pos,
370+ size_t len,
371+ struct add_extra * extra,
372+ int linenum);
373+static int
374+ mapping_cmpprevname(struct if_mapping * ifnode,
375+ struct if_mapping * target);
376+static int
377+ mapping_getprevname(int skfd,
378+ const char * ifname,
379+ struct if_mapping * target,
380+ int flag);
361381
362382 /**************************** VARIABLES ****************************/
363383
@@ -390,6 +410,8 @@ const struct mapping_selector selector_list[] =
390410 { "pcmciaslot", &mapping_addpcmciaslot, &mapping_cmppcmciaslot, &mapping_getpcmciaslot },
391411 /* sysfs file (udev emulation) */
392412 { "sysfs", &mapping_addsysfs, &mapping_cmpsysfs, &mapping_getsysfs },
413+ /* previous interface name */
414+ { "prevname", &mapping_addprevname, &mapping_cmpprevname, &mapping_getprevname },
393415 /* The Terminator */
394416 { NULL, NULL, NULL, NULL },
395417 };
@@ -419,6 +441,9 @@ int dry_run = 0; /* Just print new name, don't rename */
419441 /* Verbose support (i.e. debugging) */
420442 int verbose = 0;
421443
444+/* udev output support (print new DEVPATH) */
445+int udev_output = 0;
446+
422447 /* sysfs global data */
423448 struct sysfs_metadata sysfs_global =
424449 {
@@ -449,8 +474,8 @@ if_match_ifname(const char * pattern,
449474 int n;
450475 int ret;
451476
452- /* Check for a wildcard (converted from '*' to '%d' in mapping_create()) */
453- p = strstr(pattern, "%d");
477+ /* Check for a wildcard */
478+ p = strchr(pattern, '*');
454479
455480 /* No wildcard, simple comparison */
456481 if(p == NULL)
@@ -473,7 +498,7 @@ if_match_ifname(const char * pattern,
473498 while(isdigit(*v));
474499
475500 /* Pattern suffix */
476- p += 2;
501+ p += 1;
477502
478503 /* Compare suffixes */
479504 return(strcmp(p, v));
@@ -539,6 +564,7 @@ if_set_name(int skfd,
539564 char * retname)
540565 {
541566 struct ifreq ifr;
567+ char * star;
542568 int ret;
543569
544570 /* The kernel doesn't check is the interface already has the correct
@@ -562,6 +588,22 @@ if_set_name(int skfd,
562588 strncpy(ifr.ifr_name, oldname, IFNAMSIZ);
563589 strncpy(ifr.ifr_newname, newname, IFNAMSIZ);
564590
591+ /* Check for wildcard interface name, such as 'eth*' or 'wlan*'...
592+ * This require specific kernel support (2.6.2-rc1 and later).
593+ * We externally use '*', but the kernel doesn't know about that,
594+ * so convert it to something it knows about... */
595+ star = strchr(newname, '*');
596+ if(star != NULL)
597+ {
598+ int slen = star - newname;
599+ /* Replace '*' with '%d' in the new buffer */
600+ star = ifr.ifr_newname + slen;
601+ /* Size was checked in process_rename() and mapping_create() */
602+ memmove(star + 2, star + 1, IFNAMSIZ - slen - 2);
603+ star[0] = '%';
604+ star[1] = 'd';
605+ }
606+
565607 /* Do it */
566608 ret = ioctl(skfd, SIOCSIFNAME, &ifr);
567609
@@ -613,7 +655,7 @@ mapping_addmac(struct if_mapping * ifnode,
613655 /* Verify validity of string */
614656 if(len >= sizeof(ifnode->mac_filter))
615657 {
616- fprintf(stderr, "MAC address too long at line %d\n", linenum);
658+ fprintf(stderr, "Error : MAC address too long at line %d\n", linenum);
617659 return(-1);
618660 }
619661 n = strspn(string, "0123456789ABCDEFabcdef:*");
@@ -1544,6 +1586,8 @@ mapping_getsysfs(int skfd,
15441586 int flag)
15451587 {
15461588 FILE * stream;
1589+ char * fname;
1590+ int fnsize;
15471591 char * linebuf = NULL;
15481592 size_t linelen = 0;
15491593 char * sdup;
@@ -1553,83 +1597,116 @@ mapping_getsysfs(int skfd,
15531597 skfd = skfd;
15541598 flag = flag;
15551599
1556- /* Check if we know the root of the sysfs filesystem */
1557- if(sysfs_global.root == NULL)
1600+ /* Check if we know the devpath of this device */
1601+ if(target->sysfs_devpath == NULL)
15581602 {
1559- /* Open the mount file for reading */
1560- stream = fopen("/proc/mounts", "r");
1561- if(!stream)
1562- {
1563- fprintf(stderr, "Error: Can't open /proc/mounts file: %s\n",
1564- strerror(errno));
1565- return(-1);
1566- }
1567-
1568- /* Read each line of file
1569- * getline is a GNU extension :-( The buffer is recycled and increased
1570- * as needed by getline. */
1571- while(getline(&linebuf, &linelen, stream) > 0)
1603+ /* Check if we know the root of the sysfs filesystem */
1604+ if(sysfs_global.root == NULL)
15721605 {
1573- char * p;
1574- size_t n;
1606+ /* Open the mount file for reading */
1607+ stream = fopen("/proc/mounts", "r");
1608+ if(!stream)
1609+ {
1610+ fprintf(stderr, "Error: Can't open /proc/mounts file: %s\n",
1611+ strerror(errno));
1612+ return(-1);
1613+ }
15751614
1576- /* Get the line starting with sysfs */
1577- p = linebuf;
1578- while(isspace(*p))
1579- ++p;
1580- if(!strncasecmp(p, "sysfs ", 6))
1615+ /* Read each line of file
1616+ * getline is a GNU extension :-( The buffer is recycled and
1617+ * increased as needed by getline. */
1618+ while(getline(&linebuf, &linelen, stream) > 0)
15811619 {
1582- /* Find the mount point */
1583- p += 6;
1584- while(isspace(*p))
1585- ++p;
1586- n = strcspn(p, " \t\n");
1587- sdup = strndup(p, n);
1588- if((n == 0) || (sdup == NULL))
1620+ int i;
1621+ char * p;
1622+ size_t n;
1623+ char * token[3];
1624+ size_t toklen[3];
1625+
1626+ /* The format of /proc/mounts is similar to /etc/fstab (5).
1627+ * The first argument is the device. For sysfs, there is no
1628+ * associated device, so this argument is ignored.
1629+ * The second argument is the mount point.
1630+ * The third argument is the filesystem type.
1631+ */
1632+
1633+ /* Extract the first 3 tokens */
1634+ p = linebuf;
1635+ for(i = 0; i < 3; i++)
15891636 {
1590- fprintf(stderr, "Error: Can't parse /proc/mounts file: %s\n",
1591- strerror(errno));
1592- return(-1);
1637+ while(isspace(*p))
1638+ ++p;
1639+ token[i] = p;
1640+ n = strcspn(p, " \t\n");
1641+ toklen[i] = n;
1642+ p += n;
15931643 }
1594- /* Store it */
1595- sysfs_global.root = sdup;
1596- sysfs_global.rlen = n;
1597- break;
1644+ /* Get the filesystem which type is "sysfs" */
1645+ if((n == 5) && (!strncasecmp(token[2], "sysfs", 5)))
1646+ {
1647+ /* Get its mount point */
1648+ n = toklen[1];
1649+ sdup = strndup(token[1], n);
1650+ if((n == 0) || (sdup == NULL))
1651+ {
1652+ fprintf(stderr,
1653+ "Error: Can't parse /proc/mounts file: %s\n",
1654+ strerror(errno));
1655+ return(-1);
1656+ }
1657+ /* Store it */
1658+ sysfs_global.root = sdup;
1659+ sysfs_global.rlen = n;
1660+ break;
1661+ }
1662+ /* Finished -> next line */
15981663 }
1599- /* Finished -> next line */
1600- }
16011664
1602- /* Cleanup */
1603- fclose(stream);
1665+ /* Cleanup */
1666+ fclose(stream);
16041667
1605- /* Check if we found it */
1606- if(sysfs_global.root == NULL)
1668+ /* Check if we found it */
1669+ if(sysfs_global.root == NULL)
1670+ {
1671+ fprintf(stderr,
1672+ "Error: Can't find sysfs in /proc/mounts file\n");
1673+ free(linebuf);
1674+ return(-1);
1675+ }
1676+ }
1677+
1678+ /* Construct devpath for this interface.
1679+ * Reserve enough space to replace name without realloc. */
1680+ fnsize = (sysfs_global.rlen + 11 + IFNAMSIZ + 1);
1681+ fname = malloc(fnsize);
1682+ if(fname == NULL)
16071683 {
1608- fprintf(stderr, "Error: Can't find sysfs in /proc/mounts file\n");
1609- free(linebuf);
1684+ fprintf(stderr, "Error: Can't allocate SYSFS devpath\n");
16101685 return(-1);
16111686 }
1687+ /* Not true devpath for 2.6.20+, but this syslink should work */
1688+ target->sysfs_devplen = sprintf(fname, "%s/class/net/%s",
1689+ sysfs_global.root, ifname);
1690+ target->sysfs_devpath = fname;
16121691 }
16131692
16141693 /* Loop on all sysfs selector */
16151694 for(findex = 0; findex < sysfs_global.filenum; findex++)
16161695 {
1617- char * fname;
1618- int flen;
16191696 char * p;
16201697 ssize_t n;
16211698
16221699 /* Construct complete filename for the sysfs selector */
1623- flen = (sysfs_global.rlen + 11 + strlen(ifname) + 1 +
1624- strlen(sysfs_global.filename[findex]) + 1);
1625- fname = malloc(flen);
1700+ fnsize = (target->sysfs_devplen + 1 +
1701+ strlen(sysfs_global.filename[findex]) + 1);
1702+ fname = malloc(fnsize);
16261703 if(fname == NULL)
16271704 {
16281705 fprintf(stderr, "Error: Can't allocate SYSFS filename\n");
16291706 free(linebuf);
16301707 return(-1);
16311708 }
1632- sprintf(fname, "%s/class/net/%s/%s", sysfs_global.root, ifname,
1709+ sprintf(fname, "%s/%s", target->sysfs_devpath,
16331710 sysfs_global.filename[findex]);
16341711
16351712 /* Open the sysfs file for reading */
@@ -1649,18 +1726,103 @@ mapping_getsysfs(int skfd,
16491726 fclose(stream);
16501727 if(n <= 0)
16511728 {
1652- /* Some sysfs attribute are void for some interface */
1653- if(verbose)
1654- fprintf(stderr, "Error: Can't read file `%s'\n", fname);
1655- /* Next sysfs selector */
1656- continue;
1657- }
1729+ /* Some attributes are just symlinks to another directory.
1730+ * We can read the attributes in that other directory
1731+ * just fine, but sometimes the symlink itself gives a lot
1732+ * of information.
1733+ * Examples : SYSFS{device} and SYSFS{device/driver}
1734+ * In such cases, get the name of the directory pointed to...
1735+ */
1736+ /*
1737+ * I must note that the API for readlink() is very bad,
1738+ * which force us to have this ugly code. Yuck !
1739+ */
1740+ int allocsize = 128; /* 256 = Good start */
1741+ int retry = 16;
1742+ char * linkpath = NULL;
1743+ int pathlen;
16581744
1659- /* Get content, remove trailing '/n', save it */
1660- p = linebuf;
1661- if(p[n - 1] == '\n')
1662- n--;
1663- sdup = strndup(p, n);
1745+ /* Try reading the link with increased buffer size */
1746+ do
1747+ {
1748+ allocsize *= 2;
1749+ linkpath = realloc(linkpath, allocsize);
1750+ pathlen = readlink(fname, linkpath, allocsize);
1751+ /* If we did not hit the buffer limit, success */
1752+ if(pathlen < allocsize)
1753+ break;
1754+ }
1755+ while(retry-- > 0);
1756+
1757+ /* Check for error, most likely ENOENT */
1758+ if(pathlen > 0)
1759+ /* We have a symlink ;-) Terminate the string. */
1760+ linkpath[pathlen] = '\0';
1761+ else
1762+ {
1763+ /* Error ! */
1764+ free(linkpath);
1765+
1766+ /* A lot of information in the sysfs is implicit, given
1767+ * by the position of a file in the tree. It is therefore
1768+ * important to be able to read the various components
1769+ * of a path. For this reason, we resolve '..' to the
1770+ * real name of the parent directory... */
1771+ /* We have at least 11 char, see above */
1772+ if(!strcmp(fname + fnsize - 4, "/.."))
1773+ //if(!strcmp(fname + strlen(fname) - 3, "/.."))
1774+ {
1775+ /* This procedure to get the realpath is not very
1776+ * nice, but it's the "best practice". Hmm... */
1777+ int cwd_fd = open(".", O_RDONLY);
1778+ linkpath = NULL;
1779+ if(cwd_fd > 0)
1780+ {
1781+ int ret = chdir(fname);
1782+ if(ret == 0)
1783+ /* Using getcwd with NULL is a GNU extension. Nice. */
1784+ linkpath = getcwd(NULL, 0);
1785+ /* This may fail, but it's not fatal */
1786+ fchdir(cwd_fd);
1787+ }
1788+ /* Check if we suceeded */
1789+ if(!linkpath)
1790+ {
1791+ free(linkpath);
1792+ if(verbose)
1793+ fprintf(stderr, "Error: Can't read parent directory `%s'\n", fname);
1794+ /* Next sysfs selector */
1795+ continue;
1796+ }
1797+ }
1798+ else
1799+ {
1800+ /* Some sysfs attribute are void for some interface,
1801+ * we may have a real directory, or we may have permission
1802+ * issues... */
1803+ if(verbose)
1804+ fprintf(stderr, "Error: Can't read file `%s'\n", fname);
1805+ /* Next sysfs selector */
1806+ continue;
1807+ }
1808+ }
1809+
1810+ /* Here, we have a link name or a parent directory name */
1811+
1812+ /* Keep only the last component of path name, save it */
1813+ p = basename(linkpath);
1814+ sdup = strdup(p);
1815+ free(linkpath);
1816+ }
1817+ else
1818+ {
1819+ /* This is a regular file (well, pseudo file) */
1820+ /* Get content, remove trailing '/n', save it */
1821+ p = linebuf;
1822+ if(p[n - 1] == '\n')
1823+ n--;
1824+ sdup = strndup(p, n);
1825+ }
16641826 if(sdup == NULL)
16651827 {
16661828 fprintf(stderr, "Error: Can't allocate SYSFS value\n");
@@ -1686,6 +1848,77 @@ mapping_getsysfs(int skfd,
16861848 return(target->active[SELECT_SYSFS] ? 0 : -1);
16871849 }
16881850
1851+/*------------------------------------------------------------------*/
1852+/*
1853+ * Add a Previous Interface Name selector to a mapping
1854+ */
1855+static int
1856+mapping_addprevname(struct if_mapping * ifnode,
1857+ int * active,
1858+ char * string,
1859+ size_t len,
1860+ struct add_extra * extra,
1861+ int linenum)
1862+{
1863+ /* Avoid "Unused parameter" warning */
1864+ extra = extra;
1865+
1866+ /* Verify validity of string */
1867+ if(len >= sizeof(ifnode->prevname))
1868+ {
1869+ fprintf(stderr, "Old Interface Name too long at line %d\n", linenum);
1870+ return(-1);
1871+ }
1872+
1873+ /* Copy */
1874+ memcpy(ifnode->prevname, string, len + 1);
1875+
1876+ /* Activate */
1877+ ifnode->active[SELECT_PREVNAME] = 1;
1878+ active[SELECT_PREVNAME] = 1;
1879+
1880+ if(verbose)
1881+ fprintf(stderr,
1882+ "Parsing : Added Old Interface Name `%s' from line %d.\n",
1883+ ifnode->prevname, linenum);
1884+
1885+ return(0);
1886+}
1887+
1888+/*------------------------------------------------------------------*/
1889+/*
1890+ * Compare the Previous Interface Name of two mappings
1891+ * Note : this one is special.
1892+ */
1893+static int
1894+mapping_cmpprevname(struct if_mapping * ifnode,
1895+ struct if_mapping * target)
1896+{
1897+ /* Do wildcard matching, case insensitive */
1898+ return(fnmatch(ifnode->prevname, target->ifname, FNM_CASEFOLD));
1899+}
1900+
1901+/*------------------------------------------------------------------*/
1902+/*
1903+ * Extract the Previous Interface Name from a live interface
1904+ */
1905+static int
1906+mapping_getprevname(int skfd,
1907+ const char * ifname,
1908+ struct if_mapping * target,
1909+ int flag)
1910+{
1911+ /* Avoid "Unused parameter" warning */
1912+ skfd = skfd; ifname = ifname; flag = flag;
1913+
1914+ /* Don't do anything, it's already in target->ifname ;-) */
1915+
1916+ /* Activate */
1917+ target->active[SELECT_PREVNAME] = 1;
1918+
1919+ return(0);
1920+}
1921+
16891922
16901923 /*********************** MAPPING MANAGEMENTS ***********************/
16911924 /*
@@ -1706,8 +1939,10 @@ mapping_create(char * pos,
17061939 struct if_mapping * ifnode;
17071940 char * star;
17081941
1709- /* Check overflow. */
1710- if(len > IFNAMSIZ)
1942+ star = memchr(pos, '*', len);
1943+
1944+ /* Check overflow, need one extra char for wildcard */
1945+ if((len + (star != NULL)) > IFNAMSIZ)
17111946 {
17121947 fprintf(stderr, "Error: Interface name `%.*s' too long at line %d\n",
17131948 (int) len, pos, linenum);
@@ -1738,29 +1973,6 @@ mapping_create(char * pos,
17381973 fprintf(stderr, "Warning: Alias device `%s' at line %d probably can't be mapped.\n",
17391974 ifnode->ifname, linenum);
17401975
1741- /* Check for wildcard interface name, such as 'eth*' or 'wlan*'...
1742- * This require specific kernel support (2.6.2-rc1 and later).
1743- * We externally use '*', but the kernel doesn't know about that,
1744- * so convert it to something it knows about... */
1745- star = strchr(ifnode->ifname, '*');
1746- if(star != NULL)
1747- {
1748- /* We need an extra char */
1749- if(len >= IFNAMSIZ)
1750- {
1751- fprintf(stderr,
1752- "Error: Interface wildcard `%s' too long at line %d\n",
1753- ifnode->ifname, linenum);
1754- free(ifnode);
1755- return(NULL);
1756- }
1757-
1758- /* Replace '*' with '%d' */
1759- memmove(star + 2, star + 1, len + 1 - (star - ifnode->ifname));
1760- star[0] = '%';
1761- star[1] = 'd';
1762- }
1763-
17641976 if(verbose)
17651977 fprintf(stderr, "Parsing : Added Mapping `%s' from line %d.\n",
17661978 ifnode->ifname, linenum);
@@ -2215,37 +2427,23 @@ probe_debian(int skfd)
22152427 static int
22162428 process_rename(int skfd,
22172429 char * ifname,
2218- char * pattern)
2430+ char * newname)
22192431 {
2220- char newname[IFNAMSIZ+1];
22212432 char retname[IFNAMSIZ+1];
22222433 int len;
22232434 char * star;
22242435
2225- len = strlen(pattern);
2226- star = strchr(pattern, '*');
2436+ len = strlen(newname);
2437+ star = strchr(newname, '*');
22272438
22282439 /* Check newname length, need one extra char for wildcard */
22292440 if((len + (star != NULL)) > IFNAMSIZ)
22302441 {
22312442 fprintf(stderr, "Error: Interface name `%s' too long.\n",
2232- pattern);
2443+ newname);
22332444 return(-1);
22342445 }
22352446
2236- /* Copy to local buffer */
2237- memcpy(newname, pattern, len + 1);
2238-
2239- /* Convert wildcard to the proper format */
2240- if(star != NULL)
2241- {
2242- /* Replace '*' with '%d' in the new buffer */
2243- star += newname - pattern;
2244- memmove(star + 2, star + 1, len + 1 - (star - newname));
2245- star[0] = '%';
2246- star[1] = 'd';
2247- }
2248-
22492447 /* Change the name of the interface */
22502448 if(if_set_name(skfd, ifname, newname, retname) < 0)
22512449 {
@@ -2285,6 +2483,24 @@ process_ifname(int skfd,
22852483 if(target == NULL)
22862484 return(-1);
22872485
2486+ /* If udev is calling us, get the real devpath. */
2487+ if(udev_output)
2488+ {
2489+ const char *env;
2490+ /* It's passed to us as an environment variable */
2491+ env = getenv("DEVPATH");
2492+ if(env)
2493+ {
2494+ int env_len = strlen(env);
2495+ target->sysfs_devplen = env_len;
2496+ /* Make enough space for new interface name */
2497+ target->sysfs_devpath = malloc(env_len + IFNAMSIZ + 1);
2498+ if(target->sysfs_devpath != NULL)
2499+ memcpy(target->sysfs_devpath, env, env_len + 1);
2500+ }
2501+ /* We will get a second chance is the user has some sysfs selectors */
2502+ }
2503+
22882504 /* Find matching mapping */
22892505 mapping = mapping_find(target);
22902506 if(mapping == NULL)
@@ -2300,26 +2516,47 @@ process_ifname(int skfd,
23002516 * That would be tricky to do... */
23012517 if(dry_run)
23022518 {
2303- printf("Dry-run : Would rename %s to %s.\n",
2304- target->ifname, mapping->ifname);
2305- return(0);
2519+ strcpy(retname, mapping->ifname);
2520+ fprintf(stderr, "Dry-run : Would rename %s to %s.\n",
2521+ target->ifname, mapping->ifname);
23062522 }
2307-
2308- /* Change the name of the interface */
2309- if(if_set_name(skfd, target->ifname, mapping->ifname, retname) < 0)
2523+ else
23102524 {
2311- fprintf(stderr, "Error: cannot change name of %s to %s: %s\n",
2312- target->ifname, mapping->ifname, strerror(errno));
2313- return(-1);
2525+ /* Change the name of the interface */
2526+ if(if_set_name(skfd, target->ifname, mapping->ifname, retname) < 0)
2527+ {
2528+ fprintf(stderr, "Error: cannot change name of %s to %s: %s\n",
2529+ target->ifname, mapping->ifname, strerror(errno));
2530+ return(-1);
2531+ }
23142532 }
23152533
23162534 /* Check if called with an explicit interface name */
23172535 if(print_newname)
23182536 {
2319- /* Always print out the *new* interface name so that
2320- * the calling script can pick it up and know where its interface
2321- * has gone. */
2322- printf("%s\n", retname);
2537+ if(!udev_output)
2538+ /* Always print out the *new* interface name so that
2539+ * the calling script can pick it up and know where its interface
2540+ * has gone. */
2541+ printf("%s\n", retname);
2542+ else
2543+ /* udev likes to call us as an IMPORT action. This means that
2544+ * we need to return udev the environment variables changed.
2545+ * Obviously, we don't want to return anything is nothing changed. */
2546+ if(strcmp(target->ifname, retname))
2547+ {
2548+ char * pos;
2549+ /* Hack */
2550+ if(!target->sysfs_devpath)
2551+ mapping_getsysfs(skfd, ifname, target, 0);
2552+ /* Update devpath. Size is large enough. */
2553+ pos = strrchr(target->sysfs_devpath, '/');
2554+ if((pos != NULL) && (!strcmp(target->ifname, pos + 1)))
2555+ strcpy(pos + 1, retname);
2556+ /* Return new environment variables */
2557+ printf("DEVPATH=%s\nINTERFACE=%s\nINTERFACE_OLD=%s\n",
2558+ target->sysfs_devpath, retname, target->ifname);
2559+ }
23232560 }
23242561
23252562 /* Done */
@@ -2387,7 +2624,7 @@ main(int argc,
23872624 /* Loop over all command line options */
23882625 while(1)
23892626 {
2390- int c = getopt_long(argc, argv, "c:dDi:n:ptvV", long_opt, NULL);
2627+ int c = getopt_long(argc, argv, "c:dDi:n:ptuvV", long_opt, NULL);
23912628 if(c == -1)
23922629 break;
23932630
@@ -2417,6 +2654,9 @@ main(int argc,
24172654 case 't':
24182655 force_takeover = 1;
24192656 break;
2657+ case 'u':
2658+ udev_output = 1;
2659+ break;
24202660 case 'v':
24212661 printf("%-8.16s Wireless-Tools version %d\n", "ifrename", WT_VERSION);
24222662 return(0);
@@ -2449,7 +2689,8 @@ main(int argc,
24492689 else
24502690 {
24512691 /* Rename only this interface based on mappings
2452- * Mostly used for HotPlug processing (from /etc/hotplug/net.agent).
2692+ * Mostly used for HotPlug processing (from /etc/hotplug/net.agent)
2693+ * or udev processing (from a udev IMPORT rule).
24532694 * Process the network interface specified on the command line,
24542695 * and return the new name on stdout.
24552696 */
--- a/wireless_tools/iftab.5
+++ b/wireless_tools/iftab.5
@@ -1,7 +1,7 @@
1-.\" Jean II - HPL - 2004
1+.\" Jean II - HPL - 2004-2007
22 .\" iftab.5
33 .\"
4-.TH IFTAB 5 "01 March 2004" "wireless-tools" "Linux Programmer's Manual"
4+.TH IFTAB 5 "26 February 2007" "wireless-tools" "Linux Programmer's Manual"
55 .\"
66 .\" NAME part
77 .\"
@@ -98,7 +98,9 @@ the goal is to uniquely identify each piece of hardware.
9898 .PP
9999 Most users will only use the
100100 .B mac
101-selector, other selectors are for more specialised setup.
101+selector despite its potential problems, other selectors are for more
102+specialised setup. Most selectors accept a '*' in the selector value
103+for wilcard matching, and most selectors are case insensitive.
102104 .TP
103105 .BI mac " mac address"
104106 Matches the MAC Address of the interface with the specified MAC
@@ -106,19 +108,27 @@ address. The MAC address of the interface can be shown using
106108 .IR ifconfig (8)
107109 or
108110 .IR ip (8).
109-The specified MAC address may contain a '*' for wilcard matching.
110111 .br
111112 This is the most common selector, as most interfaces have a unique MAC
112113 address allowing to identify network interfaces without ambiguity.
113114 However, some interfaces don't have a valid MAC address until they are
114-brought up, in such case using this selector is tricky.
115+brought up, in such case using this selector is tricky or impossible.
115116 .TP
116117 .BI arp " arp type"
117118 Matches the ARP Type (also called Link Type) of the interface with the
118-specified ARP type. The ARP Type of the interface can be shown using
119+specified ARP type as a number. The ARP Type of the interface can be
120+shown using
119121 .IR ifconfig (8)
120122 or
121-.IR ip (8).
123+.IR ip (8),
124+the
125+.B link/ether
126+type correspond to
127+.B 1
128+and the
129+.B link/ieee802.11
130+type correspond to
131+.BR 801 .
122132 .br
123133 This selector is useful when a driver create multiple network
124134 interfaces for a single network card.
@@ -159,7 +169,9 @@ not sufficient to uniquely identify an interface.
159169 Matches the Wireless Protocol of the interface with the specified
160170 wireless protocol. The Wireless Protocol of the interface can be shown
161171 using
162-.IR iwconfig (8).
172+.IR iwconfig (8)
173+or
174+.IR iwgetid (8).
163175 .br
164176 This selector is only supported on wireless interfaces and is not
165177 sufficient to uniquely identify an interface.
@@ -174,21 +186,97 @@ This selector is usually only supported on 16 bits cards, for 32 bits
174186 cards it is advised to use the selector
175187 .BR businfo .
176188 .TP
189+.BI prevname " previous interface name"
190+Matches the name of the interface prior to renaming with the specified
191+oldname.
192+.br
193+This selector should be avoided as the previous interface name may
194+vary depending on various condition. A system/kernel/driver update may
195+change the original name. Then, ifrename or another tool may rename it
196+prior to the execution of this selector.
197+.TP
177198 .BI SYSFS{ filename } " value"
178-Matches the sysfs attribute given by filename to the specified value. sysfs attributes of the interface can be read in one of the directory in the directory
179-.IR /sys/class/net/ .
180-For example, the filename
181-.I address
182-is the MAC address of the device and should be identical to the selector
183-.BR mac .
199+Matches the content the sysfs attribute given by filename to the
200+specified value. For symlinks and parents directories, match the
201+actual directory name of the sysfs attribute given by filename to the
202+specified value.
184203 .br
204+A list of the most useful sysfs attributes is given in the next
205+section.
206+.\"
207+.\" SYSFS DESCRIPTORS part
208+.\"
209+.SH SYSFS DESCRIPTORS
210+Sysfs attributes for a specific interface are located on most systems
211+in the directory named after that interface at
212+.IR /sys/class/net/ .
213+Most sysfs attribute are files, and their values can be read using
214+.IR cat "(1) or " more (1).
215+It is also possible to match attributes in subdirectories.
216+.PP
217+Some sysfs attributes are symlinks, pointing to another directory in
218+sysfs. If the attribute filename is a symlink the sysfs attribute
219+resolves to the name of the directory pointed by the symlink using
220+.IR readlink (1).
221+The location is a directory in the sysfs tree is also important. If
222+the attribute filename ends with
223+.IR /.. ,
224+the sysfs attribute resolves to the real name of the parent directory
225+using
226+.IR pwd (1).
227+.PP
185228 The sysfs filesystem is only supported with 2.6.X kernel and need to
186-be mounted. sysfs selectors are not as efficient as other selectors,
187-therefore they should be avoided for maximum performance.
229+be mounted (usually in
230+.IR /sys ).
231+sysfs selectors are not as efficient as other selectors, therefore
232+they should be avoided for maximum performance.
233+.PP
234+These are common sysfs attributes and their corresponding ifrename
235+descriptors.
236+.TP
237+.BI SYSFS{address} " value"
238+Same as the
239+.B mac
240+descriptor.
241+.TP
242+.BI SYSFS{type} " value"
243+Same as the
244+.B arp
245+descriptor.
246+.TP
247+.BI SYSFS{device} " value"
248+Valid only up to kernel 2.6.20. Same as the
249+.B businfo
250+descriptor.
251+.TP
252+.BI SYSFS{..} " value"
253+Valid only from kernel 2.6.21. Same as the
254+.B businfo
255+descriptor.
256+.TP
257+.BI SYSFS{device/driver} " value"
258+Valid only up to kernel 2.6.20. Same as the
259+.B driver
260+descriptor.
261+.TP
262+.BI SYSFS{../driver} " value"
263+Valid only from kernel 2.6.21. Same as the
264+.B driver
265+descriptor.
266+.TP
267+.BI SYSFS{device/irq} " value"
268+Valid only up to kernel 2.6.20. Same as the
269+.B irq
270+descriptor.
271+.TP
272+.BI SYSFS{../irq} " value"
273+Valid only from kernel 2.6.21. Same as the
274+.B irq
275+descriptor.
188276 .\"
189-.\" EXAMPLE part
277+.\" EXAMPLES part
190278 .\"
191-.SH EXAMPLE
279+.SH EXAMPLES
192280 # This is a comment
193281 .br
194282 eth2 mac 08:00:09:DE:82:0E
@@ -199,7 +287,11 @@ eth4 driver pcnet32 businfo 0000:02:05.0
199287 .br
200288 air* mac 00:07:0E:* arp 1
201289 .br
202-myvpn SYSFS{address} 00:10:83:*
290+myvpn SYSFS{address} 00:10:83:* SYSFS{type} 1
291+.br
292+bcm* SYSFS{device} 0000:03:00.0 SYSFS{device/driver} bcm43xx
293+.br
294+bcm* SYSFS{..} 0000:03:00.0 SYSFS{../driver} bcm43xx
203295 .\"
204296 .\" AUTHOR part
205297 .\"
--- a/wireless_tools/iwconfig.8
+++ b/wireless_tools/iwconfig.8
@@ -1,7 +1,7 @@
11 .\" Jean II - HPLB - 1996 => HPL - 2004
22 .\" iwconfig.8
33 .\"
4-.TH IWCONFIG 8 "09 March 2006" "wireless-tools" "Linux Programmer's Manual"
4+.TH IWCONFIG 8 "30 March 2006" "wireless-tools" "Linux Programmer's Manual"
55 .\"
66 .\" NAME part
77 .\"
@@ -21,7 +21,7 @@ iwconfig \- configure a wireless network interface
2121 .br
2222 .BI " [enc " E "] [key " K "] [power " P "] [retry " R ]
2323 .br
24-.BI " [commit]
24+.BI " [modu " M "] [commit]
2525 .br
2626 .BI "iwconfig --help"
2727 .br
@@ -78,11 +78,10 @@ to escape it.
7878 .br
7979 .I " iwconfig eth0 essid -- ""ANY""
8080 .TP
81-.BR nwid / domain
82-Set the Network ID (in some products it may also be called Domain
83-ID). As all adjacent wireless networks share the same medium, this
84-parameter is used to differenciate them (create logical colocated
85-networks) and identify nodes belonging to the same cell.
81+.BR nwid
82+Set the Network ID. As all adjacent wireless networks share the same
83+medium, this parameter is used to differentiate them (create logical
84+colocated networks) and identify nodes belonging to the same cell.
8685 .br
8786 This parameter is only used for pre-802.11 hardware, the 802.11
8887 protocol uses the ESSID and AP Address for this function.
@@ -285,14 +284,15 @@ behaviour of the retry mechanism.
285284 .br
286285 To set the maximum number of retries, enter
287286 .IR "limit `value'" .
288-This is an absolute value (without unit).
287+This is an absolute value (without unit), and the default (when
288+nothing is specified).
289289 To set the maximum length of time the MAC should retry, enter
290290 .IR "lifetime `value'" .
291291 By defaults, this value in in seconds, append the suffix m or u to
292292 specify values in milliseconds or microseconds.
293293 .br
294294 You can also add the
295-.IR min " and " max
295+.IR short ", " long ", " min " and " max
296296 modifiers. If the card supports automatic mode, they define the bounds
297297 of the limit or lifetime. Some other cards define different values
298298 depending on packet size, for example in 802.11
@@ -305,6 +305,8 @@ is the short retry limit (non RTS/CTS packets).
305305 .br
306306 .I " iwconfig eth0 retry lifetime 300m"
307307 .br
308+.I " iwconfig eth0 retry short 12"
309+.br
308310 .I " iwconfig eth0 retry min limit 8"
309311 .TP
310312 .BR rts [_threshold]
@@ -406,12 +408,14 @@ To set the period between wake ups, enter
406408 .IR "period `value'" .
407409 To set the timeout before going back to sleep, enter
408410 .IR "timeout `value'" .
411+To set the generic level of power saving, enter
412+.IR "saving `value'" .
409413 You can also add the
410414 .IR min " and " max
411415 modifiers. By default, those values are in seconds, append the suffix
412416 m or u to specify values in milliseconds or microseconds. Sometimes,
413-those values are without units (number of beacon periods, dwell or
414-similar).
417+those values are without units (number of beacon periods, dwell,
418+percentage or similar).
415419 .br
416420 .IR off " and " on
417421 disable and reenable power management. Finally, you may set the power
@@ -431,15 +435,43 @@ management mode to
431435 .br
432436 .I " iwconfig eth0 power timeout 300u all"
433437 .br
438+.I " iwconfig eth0 power saving 3"
439+.br
434440 .I " iwconfig eth0 power off"
435441 .br
436442 .I " iwconfig eth0 power min period 2 power max period 4"
437443 .TP
444+.BR modu [lation]
445+Force the card to use a specific set of modulations. Modern cards
446+support various modulations, some which are standard, such as 802.11b
447+or 802.11g, and some proprietary. This command force the card to only
448+use the specific set of modulations listed on the command line. This
449+can be used to fix interoperability issues.
450+.br
451+The list of available modulations depend on the card/driver and can be
452+displayed using
453+.IR "iwlist modulation" .
454+Note that some card/driver may not be able to select each modulation
455+listed independantly, some may come as a group. You may also set this
456+parameter to
457+.IR auto
458+let the card/driver do its best.
459+.br
460+.B Examples :
461+.br
462+.I " iwconfig eth0 modu 11g"
463+.br
464+.I " iwconfig eth0 modu CCK OFDMa"
465+.br
466+.I " iwconfig eth0 modu auto"
467+.TP
438468 .BR commit
439469 Some cards may not apply changes done through Wireless Extensions
440470 immediately (they may wait to aggregate the changes or apply it only
441-when the card is brought up via ifconfig). This command (when
442-available) forces the card to apply all pending changes.
471+when the card is brought up via
472+.IR ifconfig ).
473+This command (when available) forces the card to apply all pending
474+changes.
443475 .br
444476 This is normally not needed, because the card will eventually apply
445477 the changes, but can be useful for debugging.
--- a/wireless_tools/iwconfig.c
+++ b/wireless_tools/iwconfig.c
@@ -1,48 +1,37 @@
11 /*
22 * Wireless Tools
33 *
4- * Jean II - HPLB 97->99 - HPL 99->04
4+ * Jean II - HPLB 97->99 - HPL 99->07
55 *
66 * Main code for "iwconfig". This is the generic tool for most
77 * manipulations...
88 * You need to link this code against "iwlib.c" and "-lm".
99 *
1010 * This file is released under the GPL license.
11- * Copyright (c) 1997-2004 Jean Tourrilhes <jt@hpl.hp.com>
11+ * Copyright (c) 1997-2007 Jean Tourrilhes <jt@hpl.hp.com>
1212 */
1313
1414 #include "iwlib.h" /* Header */
1515
16-/************************* MISC SUBROUTINES **************************/
16+/**************************** CONSTANTS ****************************/
1717
18-/*------------------------------------------------------------------*/
1918 /*
20- * Print usage string
19+ * Error codes defined for setting args
2120 */
22-static void
23-iw_usage(void)
24-{
25- fprintf(stderr,
26- "Usage: iwconfig interface [essid {NN|on|off}]\n"
27- " [nwid {NN|on|off}]\n"
28- " [mode {managed|ad-hoc|...}\n"
29- " [freq N.NNNN[k|M|G]]\n"
30- " [channel N]\n"
31- " [ap {N|off|auto}]\n"
32- " [sens N]\n"
33- " [nick N]\n"
34- " [rate {N|auto|fixed}]\n"
35- " [rts {N|auto|fixed|off}]\n"
36- " [frag {N|auto|fixed|off}]\n"
37- " [enc {NNNN-NNNN|off}]\n"
38- " [power {period N|timeout N}]\n"
39- " [retry {limit N|lifetime N}]\n"
40- " [txpower N {mW|dBm}]\n"
41- " [commit]\n"
42- " Check man pages for more details.\n\n"
43- );
44-}
21+#define IWERR_ARG_NUM -2
22+#define IWERR_ARG_TYPE -3
23+#define IWERR_ARG_SIZE -4
24+#define IWERR_ARG_CONFLICT -5
25+#define IWERR_SET_EXT -6
26+#define IWERR_GET_EXT -7
27+
28+/**************************** VARIABLES ****************************/
4529
30+/*
31+ * Ugly, but deal with errors in set_info() efficiently...
32+ */
33+static int errarg;
34+static int errmax;
4635
4736 /************************* DISPLAY ROUTINES **************************/
4837
@@ -79,13 +68,6 @@ get_info(int skfd,
7968 if(iw_get_range_info(skfd, ifname, &(info->range)) >= 0)
8069 info->has_range = 1;
8170
82- /* Get sensitivity */
83- if(iw_get_ext(skfd, ifname, SIOCGIWSENS, &wrq) >= 0)
84- {
85- info->has_sens = 1;
86- memcpy(&(info->sens), &(wrq.u.sens), sizeof(iwparam));
87- }
88-
8971 /* Get AP address */
9072 if(iw_get_ext(skfd, ifname, SIOCGIWAP, &wrq) >= 0)
9173 {
@@ -93,14 +75,6 @@ get_info(int skfd,
9375 memcpy(&(info->ap_addr), &(wrq.u.ap_addr), sizeof (sockaddr));
9476 }
9577
96- /* Get NickName */
97- wrq.u.essid.pointer = (caddr_t) info->nickname;
98- wrq.u.essid.length = IW_ESSID_MAX_SIZE + 1;
99- wrq.u.essid.flags = 0;
100- if(iw_get_ext(skfd, ifname, SIOCGIWNICKN, &wrq) >= 0)
101- if(wrq.u.data.length > 1)
102- info->has_nickname = 1;
103-
10478 /* Get bit rate */
10579 if(iw_get_ext(skfd, ifname, SIOCGIWRATE, &wrq) >= 0)
10680 {
@@ -108,20 +82,6 @@ get_info(int skfd,
10882 memcpy(&(info->bitrate), &(wrq.u.bitrate), sizeof(iwparam));
10983 }
11084
111- /* Get RTS threshold */
112- if(iw_get_ext(skfd, ifname, SIOCGIWRTS, &wrq) >= 0)
113- {
114- info->has_rts = 1;
115- memcpy(&(info->rts), &(wrq.u.rts), sizeof(iwparam));
116- }
117-
118- /* Get fragmentation threshold */
119- if(iw_get_ext(skfd, ifname, SIOCGIWFRAG, &wrq) >= 0)
120- {
121- info->has_frag = 1;
122- memcpy(&(info->frag), &(wrq.u.frag), sizeof(iwparam));
123- }
124-
12585 /* Get Power Management settings */
12686 wrq.u.power.flags = 0;
12787 if(iw_get_ext(skfd, ifname, SIOCGIWPOWER, &wrq) >= 0)
@@ -130,6 +90,22 @@ get_info(int skfd,
13090 memcpy(&(info->power), &(wrq.u.power), sizeof(iwparam));
13191 }
13292
93+ /* Get stats */
94+ if(iw_get_stats(skfd, ifname, &(info->stats),
95+ &info->range, info->has_range) >= 0)
96+ {
97+ info->has_stats = 1;
98+ }
99+
100+#ifndef WE_ESSENTIAL
101+ /* Get NickName */
102+ wrq.u.essid.pointer = (caddr_t) info->nickname;
103+ wrq.u.essid.length = IW_ESSID_MAX_SIZE + 1;
104+ wrq.u.essid.flags = 0;
105+ if(iw_get_ext(skfd, ifname, SIOCGIWNICKN, &wrq) >= 0)
106+ if(wrq.u.data.length > 1)
107+ info->has_nickname = 1;
108+
133109 if((info->has_range) && (info->range.we_version_compiled > 9))
134110 {
135111 /* Get Transmit Power */
@@ -140,6 +116,13 @@ get_info(int skfd,
140116 }
141117 }
142118
119+ /* Get sensitivity */
120+ if(iw_get_ext(skfd, ifname, SIOCGIWSENS, &wrq) >= 0)
121+ {
122+ info->has_sens = 1;
123+ memcpy(&(info->sens), &(wrq.u.sens), sizeof(iwparam));
124+ }
125+
143126 if((info->has_range) && (info->range.we_version_compiled > 10))
144127 {
145128 /* Get retry limit/lifetime */
@@ -150,44 +133,20 @@ get_info(int skfd,
150133 }
151134 }
152135
153- /* Get stats */
154- if(iw_get_stats(skfd, ifname, &(info->stats),
155- &info->range, info->has_range) >= 0)
136+ /* Get RTS threshold */
137+ if(iw_get_ext(skfd, ifname, SIOCGIWRTS, &wrq) >= 0)
156138 {
157- info->has_stats = 1;
139+ info->has_rts = 1;
140+ memcpy(&(info->rts), &(wrq.u.rts), sizeof(iwparam));
158141 }
159142
160-#ifdef DISPLAY_WPA
161- /* Note : currently disabled to not bloat iwconfig output. Also,
162- * if does not make total sense to display parameters that we
163- * don't allow (yet) to configure.
164- * For now, use iwlist instead... Jean II */
165-
166- /* Get WPA/802.1x/802.11i security parameters */
167- if((info->has_range) && (info->range.we_version_compiled > 17))
143+ /* Get fragmentation threshold */
144+ if(iw_get_ext(skfd, ifname, SIOCGIWFRAG, &wrq) >= 0)
168145 {
169- wrq.u.param.flags = IW_AUTH_KEY_MGMT;
170- if(iw_get_ext(skfd, ifname, SIOCGIWAUTH, &wrq) >= 0)
171- {
172- info->has_auth_key_mgmt = 1;
173- info->auth_key_mgmt = wrq.u.param.value;
174- }
175-
176- wrq.u.param.flags = IW_AUTH_CIPHER_PAIRWISE;
177- if(iw_get_ext(skfd, ifname, SIOCGIWAUTH, &wrq) >= 0)
178- {
179- info->has_auth_cipher_pairwise = 1;
180- info->auth_cipher_pairwise = wrq.u.param.value;
181- }
182-
183- wrq.u.param.flags = IW_AUTH_CIPHER_GROUP;
184- if(iw_get_ext(skfd, ifname, SIOCGIWAUTH, &wrq) >= 0)
185- {
186- info->has_auth_cipher_group = 1;
187- info->auth_cipher_group = wrq.u.param.value;
188- }
146+ info->has_frag = 1;
147+ memcpy(&(info->frag), &(wrq.u.frag), sizeof(iwparam));
189148 }
190-#endif
149+#endif /* WE_ESSENTIAL */
191150
192151 return(0);
193152 }
@@ -225,9 +184,11 @@ display_info(struct wireless_info * info,
225184 printf("ESSID:off/any ");
226185 }
227186
187+#ifndef WE_ESSENTIAL
228188 /* Display NickName (station name), if any */
229189 if(info->has_nickname)
230190 printf("Nickname:\"%s\"", info->nickname);
191+#endif /* WE_ESSENTIAL */
231192
232193 /* Formatting */
233194 if(info->b.has_essid || info->has_nickname)
@@ -236,6 +197,7 @@ display_info(struct wireless_info * info,
236197 tokens = 0;
237198 }
238199
200+#ifndef WE_ESSENTIAL
239201 /* Display Network ID */
240202 if(info->b.has_nwid)
241203 {
@@ -247,6 +209,7 @@ display_info(struct wireless_info * info,
247209 printf("NWID:%X ", info->b.nwid.value);
248210 tokens +=2;
249211 }
212+#endif /* WE_ESSENTIAL */
250213
251214 /* Display the current mode of operation */
252215 if(info->b.has_mode)
@@ -306,6 +269,7 @@ display_info(struct wireless_info * info,
306269 printf("Bit Rate%c%s ", (info->bitrate.fixed ? '=' : ':'), buffer);
307270 }
308271
272+#ifndef WE_ESSENTIAL
309273 /* Display the Transmit Power */
310274 if(info->has_txpower)
311275 {
@@ -334,10 +298,7 @@ display_info(struct wireless_info * info,
334298 tokens +=4;
335299
336300 /* Fixed ? */
337- if(info->sens.fixed)
338- printf("Sensitivity=");
339- else
340- printf("Sensitivity:");
301+ printf("Sensitivity%c", info->sens.fixed ? '=' : ':');
341302
342303 if(info->has_range)
343304 /* Display in dBm ? */
@@ -348,10 +309,12 @@ display_info(struct wireless_info * info,
348309 else
349310 printf("%d ", info->sens.value);
350311 }
312+#endif /* WE_ESSENTIAL */
351313
352314 printf("\n ");
353315 tokens = 0;
354316
317+#ifndef WE_ESSENTIAL
355318 /* Display retry limit/lifetime information */
356319 if(info->has_retry)
357320 {
@@ -365,7 +328,8 @@ display_info(struct wireless_info * info,
365328 if(info->retry.flags & IW_RETRY_TYPE)
366329 {
367330 iw_print_retry_value(buffer, sizeof(buffer),
368- info->retry.value, info->retry.flags);
331+ info->retry.value, info->retry.flags,
332+ info->range.we_version_compiled);
369333 printf("%s", buffer);
370334 }
371335
@@ -386,12 +350,9 @@ display_info(struct wireless_info * info,
386350 else
387351 {
388352 /* Fixed ? */
389- if(info->rts.fixed)
390- printf("RTS thr=");
391- else
392- printf("RTS thr:");
393-
394- printf("%d B ", info->rts.value);
353+ printf("RTS thr%c%d B ",
354+ info->rts.fixed ? '=' : ':',
355+ info->rts.value);
395356 }
396357 tokens += 3;
397358 }
@@ -413,18 +374,16 @@ display_info(struct wireless_info * info,
413374 else
414375 {
415376 /* Fixed ? */
416- if(info->frag.fixed)
417- printf("Fragment thr=");
418- else
419- printf("Fragment thr:");
420-
421- printf("%d B ", info->frag.value);
377+ printf("Fragment thr%c%d B ",
378+ info->frag.fixed ? '=' : ':',
379+ info->frag.value);
422380 }
423381 }
424382
425383 /* Formating */
426384 if(tokens > 0)
427385 printf("\n ");
386+#endif /* WE_ESSENTIAL */
428387
429388 /* Display encryption information */
430389 /* Note : we display only the "current" key, use iwlist to list all keys */
@@ -451,22 +410,6 @@ display_info(struct wireless_info * info,
451410 printf("\n ");
452411 }
453412
454-#ifdef DISPLAY_WPA
455- /* Display WPA/802.1x/802.11i security parameters */
456- if(info->has_auth_key_mgmt || info->has_auth_cipher_pairwise ||
457- info->has_auth_cipher_group)
458- {
459- printf("Auth params:");
460- if(info->has_auth_key_mgmt)
461- printf(" key_mgmt:0x%X ", info->auth_key_mgmt);
462- if(info->has_auth_cipher_pairwise)
463- printf(" cipher_pairwise:0x%X ", info->auth_cipher_pairwise);
464- if(info->has_auth_cipher_group)
465- printf(" cipher_group:0x%X ", info->auth_cipher_group);
466- printf("\n ");
467- }
468-#endif
469-
470413 /* Display Power Management information */
471414 /* Note : we display only one parameter, period or timeout. If a device
472415 * (such as HiperLan) has both, the user need to use iwlist... */
@@ -482,7 +425,8 @@ display_info(struct wireless_info * info,
482425 if(info->power.flags & IW_POWER_TYPE)
483426 {
484427 iw_print_pm_value(buffer, sizeof(buffer),
485- info->power.value, info->power.flags);
428+ info->power.value, info->power.flags,
429+ info->range.we_version_compiled);
486430 printf("%s ", buffer);
487431 }
488432
@@ -558,864 +502,1403 @@ print_info(int skfd,
558502 return(rc);
559503 }
560504
561-/************************* SETTING ROUTINES **************************/
505+/****************** COMMAND LINE MODIFIERS PARSING ******************/
506+/*
507+ * Factor out the parsing of command line modifiers.
508+ */
562509
563510 /*------------------------------------------------------------------*/
564511 /*
565- * Macro to handle errors when setting WE
566- * Print a nice error message and exit...
567- * We define them as macro so that "return" do the right thing.
568- * The "do {...} while(0)" is a standard trick
512+ * Map command line modifiers to the proper flags...
569513 */
570-#define ERR_SET_EXT(rname, request) \
571- fprintf(stderr, "Error for wireless request \"%s\" (%X) :\n", \
572- rname, request)
573-
574-#define ABORT_ARG_NUM(rname, request) \
575- do { \
576- ERR_SET_EXT(rname, request); \
577- fprintf(stderr, " too few arguments.\n"); \
578- return(-1); \
579- } while(0)
580-
581-#define ABORT_ARG_TYPE(rname, request, arg) \
582- do { \
583- ERR_SET_EXT(rname, request); \
584- fprintf(stderr, " invalid argument \"%s\".\n", arg); \
585- return(-2); \
586- } while(0)
587-
588-#define ABORT_ARG_SIZE(rname, request, max) \
589- do { \
590- ERR_SET_EXT(rname, request); \
591- fprintf(stderr, " argument too big (max %d)\n", max); \
592- return(-3); \
593- } while(0)
514+typedef struct iwconfig_modifier {
515+ const char * cmd; /* Command line shorthand */
516+ __u16 flag; /* Flags to add */
517+ __u16 exclude; /* Modifiers to exclude */
518+} iwconfig_modifier;
594519
595520 /*------------------------------------------------------------------*/
596521 /*
597- * Wrapper to push some Wireless Parameter in the driver
598- * Use standard wrapper and add pretty error message if fail...
522+ * Modifiers for Power
599523 */
600-#define IW_SET_EXT_ERR(skfd, ifname, request, wrq, rname) \
601- do { \
602- if(iw_set_ext(skfd, ifname, request, wrq) < 0) { \
603- ERR_SET_EXT(rname, request); \
604- fprintf(stderr, " SET failed on device %-1.16s ; %s.\n", \
605- ifname, strerror(errno)); \
606- return(-5); \
607- } } while(0)
524+static const struct iwconfig_modifier iwmod_power[] = {
525+ { "min", IW_POWER_MIN, IW_POWER_MAX },
526+ { "max", IW_POWER_MAX, IW_POWER_MIN },
527+ { "period", IW_POWER_PERIOD, IW_POWER_TIMEOUT | IW_POWER_SAVING },
528+ { "timeout", IW_POWER_TIMEOUT, IW_POWER_PERIOD | IW_POWER_SAVING },
529+ { "saving", IW_POWER_SAVING, IW_POWER_TIMEOUT | IW_POWER_PERIOD },
530+};
531+#define IWMOD_POWER_NUM (sizeof(iwmod_power)/sizeof(iwmod_power[0]))
608532
609533 /*------------------------------------------------------------------*/
610534 /*
611- * Wrapper to extract some Wireless Parameter out of the driver
612- * Use standard wrapper and add pretty error message if fail...
535+ * Modifiers for Retry
613536 */
614-#define IW_GET_EXT_ERR(skfd, ifname, request, wrq, rname) \
615- do { \
616- if(iw_get_ext(skfd, ifname, request, wrq) < 0) { \
617- ERR_SET_EXT(rname, request); \
618- fprintf(stderr, " GET failed on device %-1.16s ; %s.\n", \
619- ifname, strerror(errno)); \
620- return(-6); \
621- } } while(0)
537+#ifndef WE_ESSENTIAL
538+static const struct iwconfig_modifier iwmod_retry[] = {
539+ { "min", IW_RETRY_MIN, IW_RETRY_MAX },
540+ { "max", IW_RETRY_MAX, IW_RETRY_MIN },
541+ { "short", IW_RETRY_SHORT, IW_RETRY_LONG },
542+ { "long", IW_RETRY_LONG, IW_RETRY_SHORT },
543+ { "limit", IW_RETRY_LIMIT, IW_RETRY_LIFETIME },
544+ { "lifetime", IW_RETRY_LIFETIME, IW_RETRY_LIMIT },
545+};
546+#define IWMOD_RETRY_NUM (sizeof(iwmod_retry)/sizeof(iwmod_retry[0]))
547+#endif /* WE_ESSENTIAL */
622548
623549 /*------------------------------------------------------------------*/
624550 /*
625- * Set the wireless options requested on command line
626- * This function is too long and probably should be split,
627- * because it look like the perfect definition of spaghetti code,
628- * but I'm way to lazy
551+ * Parse command line modifiers.
552+ * Return error or number arg parsed.
553+ * Modifiers must be at the beggining of command line.
629554 */
630555 static int
631-set_info(int skfd, /* The socket */
632- char * args[], /* Command line args */
633- int count, /* Args count */
634- char * ifname) /* Dev name */
556+parse_modifiers(char * args[], /* Command line args */
557+ int count, /* Args count */
558+ __u16 * pout, /* Flags to write */
559+ const struct iwconfig_modifier modifier[],
560+ int modnum)
635561 {
636- struct iwreq wrq;
637- int i;
562+ int i = 0;
563+ int k = 0;
564+ __u16 result = 0; /* Default : no flag set */
638565
639- /* if nothing after the device name - will never happen */
640- if(count < 1)
566+ /* Get all modifiers and value types on the command line */
567+ do
641568 {
642- fprintf(stderr, "Error : too few arguments.\n");
643- return(-1);
569+ for(k = 0; k < modnum; k++)
570+ {
571+ /* Check if matches */
572+ if(!strcasecmp(args[i], modifier[k].cmd))
573+ {
574+ /* Check for conflicting flags */
575+ if(result & modifier[k].exclude)
576+ {
577+ errarg = i;
578+ return(IWERR_ARG_CONFLICT);
579+ }
580+ /* Just add it */
581+ result |= modifier[k].flag;
582+ ++i;
583+ break;
584+ }
585+ }
644586 }
587+ /* For as long as current arg matched and not out of args */
588+ while((i < count) && (k < modnum));
589+
590+ /* Check there remains one arg for value */
591+ if(i >= count)
592+ return(IWERR_ARG_NUM);
593+
594+ /* Return result */
595+ *pout = result;
596+ return(i);
597+}
598+
599+
600+/*********************** SETTING SUB-ROUTINES ***********************/
601+/*
602+ * The following functions are use to set some wireless parameters and
603+ * are called by the set dispatcher set_info().
604+ * They take as arguments the remaining of the command line, with
605+ * arguments processed already removed.
606+ * An error is indicated by a negative return value.
607+ * 0 and positive return values indicate the number of args consumed.
608+ */
645609
646- /* The other args on the line specify options to be set... */
647- for(i = 0; i < count; i++)
610+/*------------------------------------------------------------------*/
611+/*
612+ * Set ESSID
613+ */
614+static int
615+set_essid_info(int skfd,
616+ char * ifname,
617+ char * args[], /* Command line args */
618+ int count) /* Args count */
619+{
620+ struct iwreq wrq;
621+ int i = 1;
622+ char essid[IW_ESSID_MAX_SIZE + 1];
623+ int we_kernel_version;
624+
625+ if((!strcasecmp(args[0], "off")) ||
626+ (!strcasecmp(args[0], "any")))
648627 {
649- /* ---------- Commit changes to driver ---------- */
650- if(!strncmp(args[i], "commit", 6))
651- {
652- /* No args */
653- IW_SET_EXT_ERR(skfd, ifname, SIOCSIWCOMMIT, &wrq,
654- "Commit changes");
655- continue;
656- }
628+ wrq.u.essid.flags = 0;
629+ essid[0] = '\0';
630+ }
631+ else
632+ if(!strcasecmp(args[0], "on"))
633+ {
634+ /* Get old essid */
635+ memset(essid, '\0', sizeof(essid));
636+ wrq.u.essid.pointer = (caddr_t) essid;
637+ wrq.u.essid.length = IW_ESSID_MAX_SIZE + 1;
638+ wrq.u.essid.flags = 0;
639+ if(iw_get_ext(skfd, ifname, SIOCGIWESSID, &wrq) < 0)
640+ return(IWERR_GET_EXT);
641+ wrq.u.essid.flags = 1;
642+ }
643+ else
644+ {
645+ i = 0;
646+
647+ /* '-' or '--' allow to escape the ESSID string, allowing
648+ * to set it to the string "any" or "off".
649+ * This is a big ugly, but it will do for now */
650+ if((!strcmp(args[0], "-")) || (!strcmp(args[0], "--")))
651+ {
652+ if(++i >= count)
653+ return(IWERR_ARG_NUM);
654+ }
655+
656+ /* Check the size of what the user passed us to avoid
657+ * buffer overflows */
658+ if(strlen(args[i]) > IW_ESSID_MAX_SIZE)
659+ {
660+ errmax = IW_ESSID_MAX_SIZE;
661+ return(IWERR_ARG_SIZE);
662+ }
663+ else
664+ {
665+ int temp;
657666
658- /* ---------- Set network ID ---------- */
659- if((!strcasecmp(args[i], "nwid")) ||
660- (!strcasecmp(args[i], "domain")))
661- {
662- i++;
663- if(i >= count)
664- ABORT_ARG_NUM("Set NWID", SIOCSIWNWID);
665- if((!strcasecmp(args[i], "off")) ||
666- (!strcasecmp(args[i], "any")))
667- wrq.u.nwid.disabled = 1;
668- else
669- if(!strcasecmp(args[i], "on"))
667+ wrq.u.essid.flags = 1;
668+ strcpy(essid, args[i]); /* Size checked, all clear */
669+ i++;
670+
671+ /* Check for ESSID index */
672+ if((i < count) &&
673+ (sscanf(args[i], "[%i]", &temp) == 1) &&
674+ (temp > 0) && (temp < IW_ENCODE_INDEX))
670675 {
671- /* Get old nwid */
672- IW_GET_EXT_ERR(skfd, ifname, SIOCGIWNWID, &wrq,
673- "Set NWID");
674- wrq.u.nwid.disabled = 0;
676+ wrq.u.essid.flags = temp;
677+ ++i;
675678 }
676- else
677- if(sscanf(args[i], "%lX", (unsigned long *) &(wrq.u.nwid.value))
678- != 1)
679- ABORT_ARG_TYPE("Set NWID", SIOCSIWNWID, args[i]);
680- else
681- wrq.u.nwid.disabled = 0;
682- wrq.u.nwid.fixed = 1;
683-
684- /* Set new nwid */
685- IW_SET_EXT_ERR(skfd, ifname, SIOCSIWNWID, &wrq,
686- "Set NWID");
687- continue;
688- }
679+ }
680+ }
689681
690- /* ---------- Set frequency / channel ---------- */
691- if((!strncmp(args[i], "freq", 4)) ||
692- (!strcmp(args[i], "channel")))
693- {
694- double freq;
682+ /* Get version from kernel, device may not have range... */
683+ we_kernel_version = iw_get_kernel_we_version();
695684
696- if(++i >= count)
697- ABORT_ARG_NUM("Set Frequency", SIOCSIWFREQ);
698- if(!strcasecmp(args[i], "auto"))
699- {
700- wrq.u.freq.m = -1;
701- wrq.u.freq.e = 0;
702- wrq.u.freq.flags = 0;
703- }
704- else
705- {
706- if(!strcasecmp(args[i], "fixed"))
707- {
708- /* Get old bitrate */
709- IW_GET_EXT_ERR(skfd, ifname, SIOCGIWFREQ, &wrq,
710- "Set Bit Rate");
711- wrq.u.freq.flags = IW_FREQ_FIXED;
712- }
713- else /* Should be a numeric value */
714- {
715- if(sscanf(args[i], "%lg", &(freq)) != 1)
716- ABORT_ARG_TYPE("Set Frequency", SIOCSIWFREQ, args[i]);
717- if(index(args[i], 'G')) freq *= GIGA;
718- if(index(args[i], 'M')) freq *= MEGA;
719- if(index(args[i], 'k')) freq *= KILO;
685+ /* Finally set the ESSID value */
686+ wrq.u.essid.pointer = (caddr_t) essid;
687+ wrq.u.essid.length = strlen(essid);
688+ if(we_kernel_version < 21)
689+ wrq.u.essid.length++;
720690
721- iw_float2freq(freq, &(wrq.u.freq));
691+ if(iw_set_ext(skfd, ifname, SIOCSIWESSID, &wrq) < 0)
692+ return(IWERR_SET_EXT);
722693
723- wrq.u.freq.flags = IW_FREQ_FIXED;
694+ /* Var args */
695+ return(i);
696+}
724697
725- /* Check for an additional argument */
726- if(((i+1) < count) &&
727- (!strcasecmp(args[i+1], "auto")))
728- {
729- wrq.u.freq.flags = 0;
730- ++i;
731- }
732- if(((i+1) < count) &&
733- (!strcasecmp(args[i+1], "fixed")))
734- {
735- wrq.u.freq.flags = IW_FREQ_FIXED;
736- ++i;
737- }
738- }
739- }
698+/*------------------------------------------------------------------*/
699+/*
700+ * Set Mode
701+ */
702+static int
703+set_mode_info(int skfd,
704+ char * ifname,
705+ char * args[], /* Command line args */
706+ int count) /* Args count */
707+{
708+ struct iwreq wrq;
709+ unsigned int k; /* Must be unsigned */
740710
741- IW_SET_EXT_ERR(skfd, ifname, SIOCSIWFREQ, &wrq,
742- "Set Frequency");
743- continue;
744- }
711+ /* Avoid "Unused parameter" warning */
712+ count = count;
713+
714+ /* Check if it is a uint, otherwise get is as a string */
715+ if(sscanf(args[0], "%i", &k) != 1)
716+ {
717+ k = 0;
718+ while((k < IW_NUM_OPER_MODE) &&
719+ strncasecmp(args[0], iw_operation_mode[k], 3))
720+ k++;
721+ }
722+ if(k >= IW_NUM_OPER_MODE)
723+ {
724+ errarg = 0;
725+ return(IWERR_ARG_TYPE);
726+ }
727+
728+ wrq.u.mode = k;
729+ if(iw_set_ext(skfd, ifname, SIOCSIWMODE, &wrq) < 0)
730+ return(IWERR_SET_EXT);
731+
732+ /* 1 arg */
733+ return(1);
734+}
735+
736+/*------------------------------------------------------------------*/
737+/*
738+ * Set frequency/channel
739+ */
740+static int
741+set_freq_info(int skfd,
742+ char * ifname,
743+ char * args[], /* Command line args */
744+ int count) /* Args count */
745+{
746+ struct iwreq wrq;
747+ int i = 1;
745748
746- /* ---------- Set sensitivity ---------- */
747- if(!strncmp(args[i], "sens", 4))
749+ if(!strcasecmp(args[0], "auto"))
750+ {
751+ wrq.u.freq.m = -1;
752+ wrq.u.freq.e = 0;
753+ wrq.u.freq.flags = 0;
754+ }
755+ else
756+ {
757+ if(!strcasecmp(args[0], "fixed"))
748758 {
749- if(++i >= count)
750- ABORT_ARG_NUM("Set Sensitivity", SIOCSIWSENS);
751- if(sscanf(args[i], "%i", &(wrq.u.sens.value)) != 1)
752- ABORT_ARG_TYPE("Set Sensitivity", SIOCSIWSENS, args[i]);
753-
754- IW_SET_EXT_ERR(skfd, ifname, SIOCSIWSENS, &wrq,
755- "Set Sensitivity");
756- continue;
759+ /* Get old frequency */
760+ if(iw_get_ext(skfd, ifname, SIOCGIWFREQ, &wrq) < 0)
761+ return(IWERR_GET_EXT);
762+ wrq.u.freq.flags = IW_FREQ_FIXED;
757763 }
758-
759- /* ---------- Set encryption stuff ---------- */
760- if((!strncmp(args[i], "enc", 3)) ||
761- (!strcmp(args[i], "key")))
764+ else /* Should be a numeric value */
762765 {
763- unsigned char key[IW_ENCODING_TOKEN_MAX];
764-
765- if(++i >= count)
766- ABORT_ARG_NUM("Set Encode", SIOCSIWENCODE);
766+ double freq;
767+ char * unit;
767768
768- if(!strcasecmp(args[i], "on"))
769+ freq = strtod(args[0], &unit);
770+ if(unit == args[0])
769771 {
770- /* Get old encryption information */
771- wrq.u.data.pointer = (caddr_t) key;
772- wrq.u.data.length = IW_ENCODING_TOKEN_MAX;
773- wrq.u.data.flags = 0;
774- IW_GET_EXT_ERR(skfd, ifname, SIOCGIWENCODE, &wrq,
775- "Set Encode");
776- wrq.u.data.flags &= ~IW_ENCODE_DISABLED; /* Enable */
772+ errarg = 0;
773+ return(IWERR_ARG_TYPE);
777774 }
778- else
775+ if(unit != NULL)
779776 {
780- int gotone = 0;
781- int oldone;
782- int keylen;
783- int temp;
784-
785- wrq.u.data.pointer = (caddr_t) NULL;
786- wrq.u.data.flags = 0;
787- wrq.u.data.length = 0;
788-
789- /* Allow arguments in any order (it's safe) */
790- do
791- {
792- oldone = gotone;
793-
794- /* -- Check for the key -- */
795- if(i < count)
796- {
797- keylen = iw_in_key_full(skfd, ifname,
798- args[i], key, &wrq.u.data.flags);
799- if(keylen > 0)
800- {
801- wrq.u.data.length = keylen;
802- wrq.u.data.pointer = (caddr_t) key;
803- ++i;
804- gotone++;
805- }
806- }
807-
808- /* -- Check for token index -- */
809- if((i < count) &&
810- (sscanf(args[i], "[%i]", &temp) == 1) &&
811- (temp > 0) && (temp < IW_ENCODE_INDEX))
812- {
813- wrq.u.encoding.flags |= temp;
814- ++i;
815- gotone++;
816- }
777+ if(unit[0] == 'G') freq *= GIGA;
778+ if(unit[0] == 'M') freq *= MEGA;
779+ if(unit[0] == 'k') freq *= KILO;
780+ }
817781
818- /* -- Check the various flags -- */
819- if((i < count) && (!strcasecmp(args[i], "off")))
820- {
821- wrq.u.data.flags |= IW_ENCODE_DISABLED;
822- ++i;
823- gotone++;
824- }
825- if((i < count) && (!strcasecmp(args[i], "open")))
826- {
827- wrq.u.data.flags |= IW_ENCODE_OPEN;
828- ++i;
829- gotone++;
830- }
831- if((i < count) && (!strncasecmp(args[i], "restricted", 5)))
832- {
833- wrq.u.data.flags |= IW_ENCODE_RESTRICTED;
834- ++i;
835- gotone++;
836- }
837- if((i < count) && (!strncasecmp(args[i], "temporary", 4)))
838- {
839- wrq.u.data.flags |= IW_ENCODE_TEMP;
840- ++i;
841- gotone++;
842- }
843- }
844- while(gotone != oldone);
782+ iw_float2freq(freq, &(wrq.u.freq));
845783
846- /* Pointer is absent in new API */
847- if(wrq.u.data.pointer == NULL)
848- wrq.u.data.flags |= IW_ENCODE_NOKEY;
784+ wrq.u.freq.flags = IW_FREQ_FIXED;
849785
850- /* Check if we have any invalid argument */
851- if(!gotone)
852- ABORT_ARG_TYPE("Set Encode", SIOCSIWENCODE, args[i]);
853- /* Get back to last processed argument */
854- --i;
786+ /* Check for an additional argument */
787+ if((i < count) && (!strcasecmp(args[i], "auto")))
788+ {
789+ wrq.u.freq.flags = 0;
790+ ++i;
855791 }
856-
857- IW_SET_EXT_ERR(skfd, ifname, SIOCSIWENCODE, &wrq,
858- "Set Encode");
859- continue;
860- }
861-
862- /* ---------- Set ESSID ---------- */
863- if(!strcasecmp(args[i], "essid"))
864- {
865- char essid[IW_ESSID_MAX_SIZE + 1];
866- int we_kernel_version;
867-
868- i++;
869- if(i >= count)
870- ABORT_ARG_NUM("Set ESSID", SIOCSIWESSID);
871- if((!strcasecmp(args[i], "off")) ||
872- (!strcasecmp(args[i], "any")))
792+ if((i < count) && (!strcasecmp(args[i], "fixed")))
873793 {
874- wrq.u.essid.flags = 0;
875- essid[0] = '\0';
794+ wrq.u.freq.flags = IW_FREQ_FIXED;
795+ ++i;
876796 }
877- else
878- if(!strcasecmp(args[i], "on"))
879- {
880- /* Get old essid */
881- memset(essid, '\0', sizeof(essid));
882- wrq.u.essid.pointer = (caddr_t) essid;
883- wrq.u.essid.length = IW_ESSID_MAX_SIZE + 1;
884- wrq.u.essid.flags = 0;
885- IW_GET_EXT_ERR(skfd, ifname, SIOCGIWESSID, &wrq,
886- "Set ESSID");
887- wrq.u.essid.flags = 1;
888- }
889- else
890- {
891- /* '-' or '--' allow to escape the ESSID string, allowing
892- * to set it to the string "any" or "off".
893- * This is a big ugly, but it will do for now */
894- if((!strcmp(args[i], "-")) || (!strcmp(args[i], "--")))
895- {
896- i++;
897- if(i >= count)
898- ABORT_ARG_NUM("Set ESSID", SIOCSIWESSID);
899- }
797+ }
798+ }
900799
901- /* Check the size of what the user passed us to avoid
902- * buffer overflows */
903- if(strlen(args[i]) > IW_ESSID_MAX_SIZE)
904- ABORT_ARG_SIZE("Set ESSID", SIOCSIWESSID, IW_ESSID_MAX_SIZE);
905- else
906- {
907- int temp;
800+ if(iw_set_ext(skfd, ifname, SIOCSIWFREQ, &wrq) < 0)
801+ return(IWERR_SET_EXT);
908802
909- wrq.u.essid.flags = 1;
910- strcpy(essid, args[i]); /* Size checked, all clear */
803+ /* Var args */
804+ return(i);
805+}
911806
912- /* Check for ESSID index */
913- if(((i+1) < count) &&
914- (sscanf(args[i+1], "[%i]", &temp) == 1) &&
915- (temp > 0) && (temp < IW_ENCODE_INDEX))
916- {
917- wrq.u.essid.flags = temp;
918- ++i;
919- }
920- }
921- }
807+/*------------------------------------------------------------------*/
808+/*
809+ * Set Bit Rate
810+ */
811+static int
812+set_bitrate_info(int skfd,
813+ char * ifname,
814+ char * args[], /* Command line args */
815+ int count) /* Args count */
816+{
817+ struct iwreq wrq;
818+ int i = 1;
922819
923- /* Get version from kernel, device may not have range... */
924- we_kernel_version = iw_get_kernel_we_version();
925-
926- /* Finally set the ESSID value */
927- wrq.u.essid.pointer = (caddr_t) essid;
928- wrq.u.essid.length = strlen(essid) + 1;
929- if(we_kernel_version > 20)
930- wrq.u.essid.length--;
931- IW_SET_EXT_ERR(skfd, ifname, SIOCSIWESSID, &wrq,
932- "Set ESSID");
933- continue;
820+ wrq.u.bitrate.flags = 0;
821+ if(!strcasecmp(args[0], "auto"))
822+ {
823+ wrq.u.bitrate.value = -1;
824+ wrq.u.bitrate.fixed = 0;
825+ }
826+ else
827+ {
828+ if(!strcasecmp(args[0], "fixed"))
829+ {
830+ /* Get old bitrate */
831+ if(iw_get_ext(skfd, ifname, SIOCGIWRATE, &wrq) < 0)
832+ return(IWERR_GET_EXT);
833+ wrq.u.bitrate.fixed = 1;
934834 }
935-
936- /* ---------- Set AP address ---------- */
937- if(!strcasecmp(args[i], "ap"))
835+ else /* Should be a numeric value */
938836 {
939- if(++i >= count)
940- ABORT_ARG_NUM("Set AP Address", SIOCSIWAP);
837+ double brate;
838+ char * unit;
941839
942- if((!strcasecmp(args[i], "auto")) ||
943- (!strcasecmp(args[i], "any")))
840+ brate = strtod(args[0], &unit);
841+ if(unit == args[0])
944842 {
945- /* Send a broadcast address */
946- iw_broad_ether(&(wrq.u.ap_addr));
843+ errarg = 0;
844+ return(IWERR_ARG_TYPE);
947845 }
948- else
846+ if(unit != NULL)
949847 {
950- if(!strcasecmp(args[i], "off"))
951- {
952- /* Send a NULL address */
953- iw_null_ether(&(wrq.u.ap_addr));
954- }
955- else
956- {
957- /* Get the address and check if the interface supports it */
958- if(iw_in_addr(skfd, ifname, args[i++], &(wrq.u.ap_addr)) < 0)
959- ABORT_ARG_TYPE("Set AP Address", SIOCSIWAP, args[i-1]);
960- }
848+ if(unit[0] == 'G') brate *= GIGA;
849+ if(unit[0] == 'M') brate *= MEGA;
850+ if(unit[0] == 'k') brate *= KILO;
961851 }
852+ wrq.u.bitrate.value = (long) brate;
853+ wrq.u.bitrate.fixed = 1;
962854
963- IW_SET_EXT_ERR(skfd, ifname, SIOCSIWAP, &wrq,
964- "Set AP Address");
965- continue;
966- }
967-
968- /* ---------- Set NickName ---------- */
969- if(!strncmp(args[i], "nick", 4))
970- {
971- int we_kernel_version;
972-
973- i++;
974- if(i >= count)
975- ABORT_ARG_NUM("Set Nickname", SIOCSIWNICKN);
976- if(strlen(args[i]) > IW_ESSID_MAX_SIZE)
977- ABORT_ARG_SIZE("Set Nickname", SIOCSIWNICKN, IW_ESSID_MAX_SIZE);
978-
979- we_kernel_version = iw_get_kernel_we_version();
980-
981- wrq.u.essid.pointer = (caddr_t) args[i];
982- wrq.u.essid.length = strlen(args[i]) + 1;
983- if(we_kernel_version > 20)
984- wrq.u.essid.length--;
985- IW_SET_EXT_ERR(skfd, ifname, SIOCSIWNICKN, &wrq,
986- "Set Nickname");
987- continue;
988- }
989-
990- /* ---------- Set Bit-Rate ---------- */
991- if((!strncmp(args[i], "bit", 3)) ||
992- (!strcmp(args[i], "rate")))
993- {
994- if(++i >= count)
995- ABORT_ARG_NUM("Set Bit Rate", SIOCSIWRATE);
996- if(!strcasecmp(args[i], "auto"))
855+ /* Check for an additional argument */
856+ if((i < count) && (!strcasecmp(args[i], "auto")))
997857 {
998- wrq.u.bitrate.value = -1;
999858 wrq.u.bitrate.fixed = 0;
859+ ++i;
1000860 }
1001- else
861+ if((i < count) && (!strcasecmp(args[i], "fixed")))
1002862 {
1003- if(!strcasecmp(args[i], "fixed"))
1004- {
1005- /* Get old bitrate */
1006- IW_GET_EXT_ERR(skfd, ifname, SIOCGIWRATE, &wrq,
1007- "Set Bit Rate");
1008- wrq.u.bitrate.fixed = 1;
1009- }
1010- else /* Should be a numeric value */
1011- {
1012- double brate;
1013-
1014- if(sscanf(args[i], "%lg", &(brate)) != 1)
1015- ABORT_ARG_TYPE("Set Bit Rate", SIOCSIWRATE, args[i]);
1016- if(index(args[i], 'G')) brate *= GIGA;
1017- if(index(args[i], 'M')) brate *= MEGA;
1018- if(index(args[i], 'k')) brate *= KILO;
1019- wrq.u.bitrate.value = (long) brate;
1020- wrq.u.bitrate.fixed = 1;
1021-
1022- /* Check for an additional argument */
1023- if(((i+1) < count) &&
1024- (!strcasecmp(args[i+1], "auto")))
1025- {
1026- wrq.u.bitrate.fixed = 0;
1027- ++i;
1028- }
1029- if(((i+1) < count) &&
1030- (!strcasecmp(args[i+1], "fixed")))
1031- {
1032- wrq.u.bitrate.fixed = 1;
1033- ++i;
1034- }
1035- }
863+ wrq.u.bitrate.fixed = 1;
864+ ++i;
865+ }
866+ if((i < count) && (!strcasecmp(args[i], "unicast")))
867+ {
868+ wrq.u.bitrate.flags |= IW_BITRATE_UNICAST;
869+ ++i;
870+ }
871+ if((i < count) && (!strcasecmp(args[i], "broadcast")))
872+ {
873+ wrq.u.bitrate.flags |= IW_BITRATE_BROADCAST;
874+ ++i;
1036875 }
1037-
1038- IW_SET_EXT_ERR(skfd, ifname, SIOCSIWRATE, &wrq,
1039- "Set Bit Rate");
1040- continue;
1041876 }
877+ }
878+
879+ if(iw_set_ext(skfd, ifname, SIOCSIWRATE, &wrq) < 0)
880+ return(IWERR_SET_EXT);
881+
882+ /* Var args */
883+ return(i);
884+}
885+
886+/*------------------------------------------------------------------*/
887+/*
888+ * Set encryption
889+ */
890+static int
891+set_enc_info(int skfd,
892+ char * ifname,
893+ char * args[], /* Command line args */
894+ int count) /* Args count */
895+{
896+ struct iwreq wrq;
897+ int i = 1;
898+ unsigned char key[IW_ENCODING_TOKEN_MAX];
1042899
1043- /* ---------- Set RTS threshold ---------- */
1044- if(!strncasecmp(args[i], "rts", 3))
900+ if(!strcasecmp(args[0], "on"))
901+ {
902+ /* Get old encryption information */
903+ wrq.u.data.pointer = (caddr_t) key;
904+ wrq.u.data.length = IW_ENCODING_TOKEN_MAX;
905+ wrq.u.data.flags = 0;
906+ if(iw_get_ext(skfd, ifname, SIOCGIWENCODE, &wrq) < 0)
907+ return(IWERR_GET_EXT);
908+ wrq.u.data.flags &= ~IW_ENCODE_DISABLED; /* Enable */
909+ }
910+ else
911+ {
912+ int gotone = 0;
913+ int oldone;
914+ int keylen;
915+ int temp;
916+
917+ wrq.u.data.pointer = (caddr_t) NULL;
918+ wrq.u.data.flags = 0;
919+ wrq.u.data.length = 0;
920+ i = 0;
921+
922+ /* Allow arguments in any order (it's safe) */
923+ do
1045924 {
1046- i++;
1047- if(i >= count)
1048- ABORT_ARG_NUM("Set RTS Threshold", SIOCSIWRTS);
1049- wrq.u.rts.value = -1;
1050- wrq.u.rts.fixed = 1;
1051- wrq.u.rts.disabled = 0;
1052- if(!strcasecmp(args[i], "off"))
1053- wrq.u.rts.disabled = 1; /* i.e. max size */
1054- else
1055- if(!strcasecmp(args[i], "auto"))
1056- wrq.u.rts.fixed = 0;
1057- else
1058- {
1059- if(!strcasecmp(args[i], "fixed"))
1060- {
1061- /* Get old RTS threshold */
1062- IW_GET_EXT_ERR(skfd, ifname, SIOCGIWRTS, &wrq,
1063- "Set RTS Threshold");
1064- wrq.u.rts.fixed = 1;
1065- }
1066- else /* Should be a numeric value */
1067- if(sscanf(args[i], "%li", (unsigned long *) &(wrq.u.rts.value))
1068- != 1)
1069- ABORT_ARG_TYPE("Set RTS Threshold", SIOCSIWRTS, args[i]);
925+ oldone = gotone;
926+
927+ /* -- Check for the key -- */
928+ if(i < count)
929+ {
930+ keylen = iw_in_key_full(skfd, ifname,
931+ args[i], key, &wrq.u.data.flags);
932+ if(keylen > 0)
933+ {
934+ wrq.u.data.length = keylen;
935+ wrq.u.data.pointer = (caddr_t) key;
936+ ++i;
937+ gotone++;
938+ }
1070939 }
1071940
1072- IW_SET_EXT_ERR(skfd, ifname, SIOCSIWRTS, &wrq,
1073- "Set RTS Threshold");
1074- continue;
941+ /* -- Check for token index -- */
942+ if((i < count) &&
943+ (sscanf(args[i], "[%i]", &temp) == 1) &&
944+ (temp > 0) && (temp < IW_ENCODE_INDEX))
945+ {
946+ wrq.u.encoding.flags |= temp;
947+ ++i;
948+ gotone++;
949+ }
950+
951+ /* -- Check the various flags -- */
952+ if((i < count) && (!strcasecmp(args[i], "off")))
953+ {
954+ wrq.u.data.flags |= IW_ENCODE_DISABLED;
955+ ++i;
956+ gotone++;
957+ }
958+ if((i < count) && (!strcasecmp(args[i], "open")))
959+ {
960+ wrq.u.data.flags |= IW_ENCODE_OPEN;
961+ ++i;
962+ gotone++;
963+ }
964+ if((i < count) && (!strncasecmp(args[i], "restricted", 5)))
965+ {
966+ wrq.u.data.flags |= IW_ENCODE_RESTRICTED;
967+ ++i;
968+ gotone++;
969+ }
970+ if((i < count) && (!strncasecmp(args[i], "temporary", 4)))
971+ {
972+ wrq.u.data.flags |= IW_ENCODE_TEMP;
973+ ++i;
974+ gotone++;
975+ }
1075976 }
977+ while(gotone != oldone);
978+
979+ /* Pointer is absent in new API */
980+ if(wrq.u.data.pointer == NULL)
981+ wrq.u.data.flags |= IW_ENCODE_NOKEY;
1076982
1077- /* ---------- Set fragmentation threshold ---------- */
1078- if(!strncmp(args[i], "frag", 4))
983+ /* Check if we have any invalid argument */
984+ if(!gotone)
1079985 {
1080- i++;
1081- if(i >= count)
1082- ABORT_ARG_NUM("Set Fragmentation Threshold", SIOCSIWFRAG);
1083- wrq.u.frag.value = -1;
1084- wrq.u.frag.fixed = 1;
1085- wrq.u.frag.disabled = 0;
1086- if(!strcasecmp(args[i], "off"))
1087- wrq.u.frag.disabled = 1; /* i.e. max size */
1088- else
1089- if(!strcasecmp(args[i], "auto"))
1090- wrq.u.frag.fixed = 0;
986+ errarg = 0;
987+ return(IWERR_ARG_TYPE);
988+ }
989+ }
990+
991+ if(iw_set_ext(skfd, ifname, SIOCSIWENCODE, &wrq) < 0)
992+ return(IWERR_SET_EXT);
993+
994+ /* Var arg */
995+ return(i);
996+}
997+
998+/*------------------------------------------------------------------*/
999+/*
1000+ * Set Power Management
1001+ */
1002+static int
1003+set_power_info(int skfd,
1004+ char * ifname,
1005+ char * args[], /* Command line args */
1006+ int count) /* Args count */
1007+{
1008+ struct iwreq wrq;
1009+ int i = 1;
1010+
1011+ if(!strcasecmp(args[0], "off"))
1012+ wrq.u.power.disabled = 1; /* i.e. max size */
1013+ else
1014+ if(!strcasecmp(args[0], "on"))
1015+ {
1016+ /* Get old Power info */
1017+ wrq.u.power.flags = 0;
1018+ if(iw_get_ext(skfd, ifname, SIOCGIWPOWER, &wrq) < 0)
1019+ return(IWERR_GET_EXT);
1020+ wrq.u.power.disabled = 0;
1021+ }
1022+ else
1023+ {
1024+ double value;
1025+ char * unit;
1026+ int gotone = 0;
1027+
1028+ /* Parse modifiers */
1029+ i = parse_modifiers(args, count, &wrq.u.power.flags,
1030+ iwmod_power, IWMOD_POWER_NUM);
1031+ if(i < 0)
1032+ return(i);
1033+
1034+ wrq.u.power.disabled = 0;
1035+
1036+ /* Is there any value to grab ? */
1037+ value = strtod(args[0], &unit);
1038+ if(unit != args[0])
1039+ {
1040+ struct iw_range range;
1041+ int flags;
1042+ /* Extract range info to handle properly 'relative' */
1043+ if(iw_get_range_info(skfd, ifname, &range) < 0)
1044+ memset(&range, 0, sizeof(range));
1045+
1046+ /* Get the flags to be able to do the proper conversion */
1047+ switch(wrq.u.power.flags & IW_POWER_TYPE)
1048+ {
1049+ case IW_POWER_SAVING:
1050+ flags = range.pms_flags;
1051+ break;
1052+ case IW_POWER_TIMEOUT:
1053+ flags = range.pmt_flags;
1054+ break;
1055+ default:
1056+ flags = range.pmp_flags;
1057+ break;
1058+ }
1059+ /* Check if time or relative */
1060+ if(flags & IW_POWER_RELATIVE)
1061+ {
1062+ if(range.we_version_compiled < 21)
1063+ value *= MEGA;
1064+ else
1065+ wrq.u.power.flags |= IW_POWER_RELATIVE;
1066+ }
10911067 else
10921068 {
1093- if(!strcasecmp(args[i], "fixed"))
1094- {
1095- /* Get old fragmentation threshold */
1096- IW_GET_EXT_ERR(skfd, ifname, SIOCGIWFRAG, &wrq,
1097- "Set Fragmentation Threshold");
1098- wrq.u.frag.fixed = 1;
1099- }
1100- else /* Should be a numeric value */
1101- if(sscanf(args[i], "%li",
1102- (unsigned long *) &(wrq.u.frag.value))
1103- != 1)
1104- ABORT_ARG_TYPE("Set Fragmentation Threshold", SIOCSIWFRAG,
1105- args[i]);
1106- }
1069+ value *= MEGA; /* default = s */
1070+ if(unit[0] == 'u') value /= MEGA;
1071+ if(unit[0] == 'm') value /= KILO;
1072+ }
1073+ wrq.u.power.value = (long) value;
1074+ /* Set some default type if none */
1075+ if((wrq.u.power.flags & IW_POWER_TYPE) == 0)
1076+ wrq.u.power.flags |= IW_POWER_PERIOD;
1077+ ++i;
1078+ gotone = 1;
1079+ }
1080+
1081+ /* Now, check the mode */
1082+ if(i < count)
1083+ {
1084+ if(!strcasecmp(args[i], "all"))
1085+ wrq.u.power.flags |= IW_POWER_ALL_R;
1086+ if(!strncasecmp(args[i], "unicast", 4))
1087+ wrq.u.power.flags |= IW_POWER_UNICAST_R;
1088+ if(!strncasecmp(args[i], "multicast", 5))
1089+ wrq.u.power.flags |= IW_POWER_MULTICAST_R;
1090+ if(!strncasecmp(args[i], "force", 5))
1091+ wrq.u.power.flags |= IW_POWER_FORCE_S;
1092+ if(!strcasecmp(args[i], "repeat"))
1093+ wrq.u.power.flags |= IW_POWER_REPEATER;
1094+ if(wrq.u.power.flags & IW_POWER_MODE)
1095+ {
1096+ ++i;
1097+ gotone = 1;
1098+ }
1099+ }
1100+ if(!gotone)
1101+ {
1102+ errarg = i;
1103+ return(IWERR_ARG_TYPE);
1104+ }
1105+ }
1106+
1107+ if(iw_set_ext(skfd, ifname, SIOCSIWPOWER, &wrq) < 0)
1108+ return(IWERR_SET_EXT);
1109+
1110+ /* Var args */
1111+ return(i);
1112+}
11071113
1108- IW_SET_EXT_ERR(skfd, ifname, SIOCSIWFRAG, &wrq,
1109- "Set Fragmentation Threshold");
1110- continue;
1111- }
1114+#ifndef WE_ESSENTIAL
1115+/*------------------------------------------------------------------*/
1116+/*
1117+ * Set Nickname
1118+ */
1119+static int
1120+set_nick_info(int skfd,
1121+ char * ifname,
1122+ char * args[], /* Command line args */
1123+ int count) /* Args count */
1124+{
1125+ struct iwreq wrq;
1126+ int we_kernel_version;
1127+
1128+ /* Avoid "Unused parameter" warning */
1129+ count = count;
11121130
1113- /* ---------- Set operation mode ---------- */
1114- if(!strcmp(args[i], "mode"))
1131+ if(strlen(args[0]) > IW_ESSID_MAX_SIZE)
1132+ {
1133+ errmax = IW_ESSID_MAX_SIZE;
1134+ return(IWERR_ARG_SIZE);
1135+ }
1136+
1137+ we_kernel_version = iw_get_kernel_we_version();
1138+
1139+ wrq.u.essid.pointer = (caddr_t) args[0];
1140+ wrq.u.essid.length = strlen(args[0]);
1141+ if(we_kernel_version < 21)
1142+ wrq.u.essid.length++;
1143+
1144+ if(iw_set_ext(skfd, ifname, SIOCSIWNICKN, &wrq) < 0)
1145+ return(IWERR_SET_EXT);
1146+
1147+ /* 1 args */
1148+ return(1);
1149+}
1150+
1151+/*------------------------------------------------------------------*/
1152+/*
1153+ * Set commit
1154+ */
1155+static int
1156+set_nwid_info(int skfd,
1157+ char * ifname,
1158+ char * args[], /* Command line args */
1159+ int count) /* Args count */
1160+{
1161+ struct iwreq wrq;
1162+ unsigned long temp;
1163+
1164+ /* Avoid "Unused parameter" warning */
1165+ count = count;
1166+
1167+ if((!strcasecmp(args[0], "off")) ||
1168+ (!strcasecmp(args[0], "any")))
1169+ wrq.u.nwid.disabled = 1;
1170+ else
1171+ if(!strcasecmp(args[0], "on"))
1172+ {
1173+ /* Get old nwid */
1174+ if(iw_get_ext(skfd, ifname, SIOCGIWNWID, &wrq) < 0)
1175+ return(IWERR_GET_EXT);
1176+ wrq.u.nwid.disabled = 0;
1177+ }
1178+ else
1179+ if(sscanf(args[0], "%lX", &(temp)) != 1)
11151180 {
1116- int k;
1181+ errarg = 0;
1182+ return(IWERR_ARG_TYPE);
1183+ }
1184+ else
1185+ {
1186+ wrq.u.nwid.value = temp;
1187+ wrq.u.nwid.disabled = 0;
1188+ }
11171189
1118- i++;
1119- if(i >= count)
1120- ABORT_ARG_NUM("Set Mode", SIOCSIWMODE);
1190+ wrq.u.nwid.fixed = 1;
11211191
1122- if(sscanf(args[i], "%i", &k) != 1)
1192+ /* Set new nwid */
1193+ if(iw_set_ext(skfd, ifname, SIOCSIWNWID, &wrq) < 0)
1194+ return(IWERR_SET_EXT);
1195+
1196+ /* 1 arg */
1197+ return(1);
1198+}
1199+
1200+/*------------------------------------------------------------------*/
1201+/*
1202+ * Set AP Address
1203+ */
1204+static int
1205+set_apaddr_info(int skfd,
1206+ char * ifname,
1207+ char * args[], /* Command line args */
1208+ int count) /* Args count */
1209+{
1210+ struct iwreq wrq;
1211+
1212+ /* Avoid "Unused parameter" warning */
1213+ count = count;
1214+
1215+ if((!strcasecmp(args[0], "auto")) ||
1216+ (!strcasecmp(args[0], "any")))
1217+ {
1218+ /* Send a broadcast address */
1219+ iw_broad_ether(&(wrq.u.ap_addr));
1220+ }
1221+ else
1222+ {
1223+ if(!strcasecmp(args[0], "off"))
1224+ {
1225+ /* Send a NULL address */
1226+ iw_null_ether(&(wrq.u.ap_addr));
1227+ }
1228+ else
1229+ {
1230+ /* Get the address and check if the interface supports it */
1231+ if(iw_in_addr(skfd, ifname, args[0], &(wrq.u.ap_addr)) < 0)
11231232 {
1124- k = 0;
1125- while((k < IW_NUM_OPER_MODE) &&
1126- strncasecmp(args[i], iw_operation_mode[k], 3))
1127- k++;
1233+ errarg = 0;
1234+ return(IWERR_ARG_TYPE);
11281235 }
1129- if((k >= IW_NUM_OPER_MODE) || (k < 0))
1130- ABORT_ARG_TYPE("Set Mode", SIOCSIWMODE, args[i]);
1131-
1132- wrq.u.mode = k;
1133- IW_SET_EXT_ERR(skfd, ifname, SIOCSIWMODE, &wrq,
1134- "Set Mode");
1135- continue;
11361236 }
1237+ }
11371238
1138- /* ---------- Set Power Management ---------- */
1139- if(!strncmp(args[i], "power", 3))
1140- {
1141- if(++i >= count)
1142- ABORT_ARG_NUM("Set Power Management", SIOCSIWPOWER);
1239+ if(iw_set_ext(skfd, ifname, SIOCSIWAP, &wrq) < 0)
1240+ return(IWERR_SET_EXT);
11431241
1144- if(!strcasecmp(args[i], "off"))
1145- wrq.u.power.disabled = 1; /* i.e. max size */
1146- else
1147- if(!strcasecmp(args[i], "on"))
1242+ /* 1 args */
1243+ return(1);
1244+}
1245+
1246+/*------------------------------------------------------------------*/
1247+/*
1248+ * Set Tx Power
1249+ */
1250+static int
1251+set_txpower_info(int skfd,
1252+ char * ifname,
1253+ char * args[], /* Command line args */
1254+ int count) /* Args count */
1255+{
1256+ struct iwreq wrq;
1257+ int i = 1;
1258+
1259+ /* Avoid "Unused parameter" warning */
1260+ args = args; count = count;
1261+
1262+ /* Prepare the request */
1263+ wrq.u.txpower.value = -1;
1264+ wrq.u.txpower.fixed = 1;
1265+ wrq.u.txpower.disabled = 0;
1266+ wrq.u.txpower.flags = IW_TXPOW_DBM;
1267+
1268+ if(!strcasecmp(args[0], "off"))
1269+ wrq.u.txpower.disabled = 1; /* i.e. turn radio off */
1270+ else
1271+ if(!strcasecmp(args[0], "auto"))
1272+ wrq.u.txpower.fixed = 0; /* i.e. use power control */
1273+ else
1274+ {
1275+ if(!strcasecmp(args[0], "on"))
1276+ {
1277+ /* Get old tx-power */
1278+ if(iw_get_ext(skfd, ifname, SIOCGIWTXPOW, &wrq) < 0)
1279+ return(IWERR_GET_EXT);
1280+ wrq.u.txpower.disabled = 0;
1281+ }
1282+ else
1283+ {
1284+ if(!strcasecmp(args[0], "fixed"))
11481285 {
1149- /* Get old Power info */
1150- wrq.u.power.flags = 0;
1151- IW_GET_EXT_ERR(skfd, ifname, SIOCGIWPOWER, &wrq,
1152- "Set Power Management");
1153- wrq.u.power.disabled = 0;
1286+ /* Get old tx-power */
1287+ if(iw_get_ext(skfd, ifname, SIOCGIWTXPOW, &wrq) < 0)
1288+ return(IWERR_GET_EXT);
1289+ wrq.u.txpower.fixed = 1;
1290+ wrq.u.txpower.disabled = 0;
11541291 }
1155- else
1292+ else /* Should be a numeric value */
11561293 {
1157- double temp;
1158- int gotone = 0;
1159- /* Default - nope */
1160- wrq.u.power.flags = IW_POWER_ON;
1161- wrq.u.power.disabled = 0;
1162-
1163- /* Check value modifier */
1164- if(!strcasecmp(args[i], "min"))
1294+ int power;
1295+ int ismwatt = 0;
1296+ struct iw_range range;
1297+
1298+ /* Extract range info to do proper conversion */
1299+ if(iw_get_range_info(skfd, ifname, &range) < 0)
1300+ memset(&range, 0, sizeof(range));
1301+
1302+ /* Get the value */
1303+ if(sscanf(args[0], "%i", &(power)) != 1)
11651304 {
1166- wrq.u.power.flags |= IW_POWER_MIN;
1167- if(++i >= count)
1168- ABORT_ARG_NUM("Set Power Management", SIOCSIWPOWER);
1305+ errarg = 0;
1306+ return(IWERR_ARG_TYPE);
11691307 }
1170- else
1171- if(!strcasecmp(args[i], "max"))
1172- {
1173- wrq.u.power.flags |= IW_POWER_MAX;
1174- if(++i >= count)
1175- ABORT_ARG_NUM("Set Power Management", SIOCSIWPOWER);
1176- }
11771308
1178- /* Check value type */
1179- if(!strcasecmp(args[i], "period"))
1309+ /* Check if milliWatt
1310+ * We authorise a single 'm' as a shorthand for 'mW',
1311+ * on the other hand a 'd' probably means 'dBm'... */
1312+ ismwatt = ((strchr(args[0], 'm') != NULL)
1313+ && (strchr(args[0], 'd') == NULL));
1314+
1315+ /* We could check 'W' alone... Another time... */
1316+
1317+ /* Convert */
1318+ if(range.txpower_capa & IW_TXPOW_RELATIVE)
11801319 {
1181- wrq.u.power.flags |= IW_POWER_PERIOD;
1182- if(++i >= count)
1183- ABORT_ARG_NUM("Set Power Management", SIOCSIWPOWER);
1320+ /* Can't convert */
1321+ if(ismwatt)
1322+ {
1323+ errarg = 0;
1324+ return(IWERR_ARG_TYPE);
1325+ }
1326+ wrq.u.txpower.flags = IW_TXPOW_RELATIVE;
11841327 }
11851328 else
1186- if(!strcasecmp(args[i], "timeout"))
1329+ if(range.txpower_capa & IW_TXPOW_MWATT)
1330+ {
1331+ if(!ismwatt)
1332+ power = iw_dbm2mwatt(power);
1333+ wrq.u.txpower.flags = IW_TXPOW_MWATT;
1334+ }
1335+ else
11871336 {
1188- wrq.u.power.flags |= IW_POWER_TIMEOUT;
1189- if(++i >= count)
1190- ABORT_ARG_NUM("Set Power Management", SIOCSIWPOWER);
1337+ if(ismwatt)
1338+ power = iw_mwatt2dbm(power);
1339+ wrq.u.txpower.flags = IW_TXPOW_DBM;
11911340 }
1341+ wrq.u.txpower.value = power;
11921342
1193- /* Is there any value to grab ? */
1194- if(sscanf(args[i], "%lg", &(temp)) == 1)
1343+ /* Check for an additional argument */
1344+ if((i < count) && (!strcasecmp(args[i], "auto")))
11951345 {
1196- temp *= MEGA; /* default = s */
1197- if(index(args[i], 'u')) temp /= MEGA;
1198- if(index(args[i], 'm')) temp /= KILO;
1199- wrq.u.power.value = (long) temp;
1200- if((wrq.u.power.flags & IW_POWER_TYPE) == 0)
1201- wrq.u.power.flags |= IW_POWER_PERIOD;
1346+ wrq.u.txpower.fixed = 0;
12021347 ++i;
1203- gotone = 1;
12041348 }
1205-
1206- /* Now, check the mode */
1207- if(i < count)
1349+ if((i < count) && (!strcasecmp(args[i], "fixed")))
12081350 {
1209- if(!strcasecmp(args[i], "all"))
1210- wrq.u.power.flags |= IW_POWER_ALL_R;
1211- if(!strncasecmp(args[i], "unicast", 4))
1212- wrq.u.power.flags |= IW_POWER_UNICAST_R;
1213- if(!strncasecmp(args[i], "multicast", 5))
1214- wrq.u.power.flags |= IW_POWER_MULTICAST_R;
1215- if(!strncasecmp(args[i], "force", 5))
1216- wrq.u.power.flags |= IW_POWER_FORCE_S;
1217- if(!strcasecmp(args[i], "repeat"))
1218- wrq.u.power.flags |= IW_POWER_REPEATER;
1219- if(wrq.u.power.flags & IW_POWER_MODE)
1220- {
1221- ++i;
1222- gotone = 1;
1223- }
1351+ wrq.u.txpower.fixed = 1;
1352+ ++i;
12241353 }
1225- if(!gotone)
1226- ABORT_ARG_TYPE("Set Power Management", SIOCSIWPOWER,
1227- args[i]);
1228- --i;
12291354 }
1355+ }
1356+ }
1357+
1358+ if(iw_set_ext(skfd, ifname, SIOCSIWTXPOW, &wrq) < 0)
1359+ return(IWERR_SET_EXT);
12301360
1231- IW_SET_EXT_ERR(skfd, ifname, SIOCSIWPOWER, &wrq,
1232- "Set Power Management");
1233- continue;
1234- }
1361+ /* Var args */
1362+ return(i);
1363+}
12351364
1236- /* ---------- Set Transmit-Power ---------- */
1237- if(!strncmp(args[i], "txpower", 3))
1365+/*------------------------------------------------------------------*/
1366+/*
1367+ * Set Sensitivity
1368+ */
1369+static int
1370+set_sens_info(int skfd,
1371+ char * ifname,
1372+ char * args[], /* Command line args */
1373+ int count) /* Args count */
1374+{
1375+ struct iwreq wrq;
1376+ int temp;
1377+
1378+ /* Avoid "Unused parameter" warning */
1379+ count = count;
1380+
1381+ if(sscanf(args[0], "%i", &(temp)) != 1)
1382+ {
1383+ errarg = 0;
1384+ return(IWERR_ARG_TYPE);
1385+ }
1386+ wrq.u.sens.value = temp;
1387+
1388+ if(iw_set_ext(skfd, ifname, SIOCSIWSENS, &wrq) < 0)
1389+ return(IWERR_SET_EXT);
1390+
1391+ /* 1 arg */
1392+ return(1);
1393+}
1394+
1395+/*------------------------------------------------------------------*/
1396+/*
1397+ * Set Retry Limit
1398+ */
1399+static int
1400+set_retry_info(int skfd,
1401+ char * ifname,
1402+ char * args[], /* Command line args */
1403+ int count) /* Args count */
1404+{
1405+ struct iwreq wrq;
1406+ int i = 0;
1407+ double value;
1408+ char * unit;
1409+
1410+ /* Parse modifiers */
1411+ i = parse_modifiers(args, count, &wrq.u.retry.flags,
1412+ iwmod_retry, IWMOD_RETRY_NUM);
1413+ if(i < 0)
1414+ return(i);
1415+
1416+ /* Add default type if none */
1417+ if((wrq.u.retry.flags & IW_RETRY_TYPE) == 0)
1418+ wrq.u.retry.flags |= IW_RETRY_LIMIT;
1419+
1420+ wrq.u.retry.disabled = 0;
1421+
1422+ /* Is there any value to grab ? */
1423+ value = strtod(args[0], &unit);
1424+ if(unit == args[0])
1425+ {
1426+ errarg = i;
1427+ return(IWERR_ARG_TYPE);
1428+ }
1429+
1430+ /* Limit is absolute, on the other hand lifetime is seconds */
1431+ if(wrq.u.retry.flags & IW_RETRY_LIFETIME)
1432+ {
1433+ struct iw_range range;
1434+ /* Extract range info to handle properly 'relative' */
1435+ if(iw_get_range_info(skfd, ifname, &range) < 0)
1436+ memset(&range, 0, sizeof(range));
1437+
1438+ if(range.r_time_flags & IW_RETRY_RELATIVE)
12381439 {
1239- struct iw_range range;
1240-
1241- if(++i >= count)
1242- ABORT_ARG_NUM("Set Tx Power", SIOCSIWTXPOW);
1243-
1244- /* Extract range info */
1245- if(iw_get_range_info(skfd, ifname, &range) < 0)
1246- memset(&range, 0, sizeof(range));
1247-
1248- /* Prepare the request */
1249- wrq.u.txpower.value = -1;
1250- wrq.u.txpower.fixed = 1;
1251- wrq.u.txpower.disabled = 0;
1252- wrq.u.txpower.flags = IW_TXPOW_DBM;
1253- if(!strcasecmp(args[i], "off"))
1254- wrq.u.txpower.disabled = 1; /* i.e. turn radio off */
1440+ if(range.we_version_compiled < 21)
1441+ value *= MEGA;
12551442 else
1256- if(!strcasecmp(args[i], "auto"))
1257- wrq.u.txpower.fixed = 0; /* i.e. use power control */
1258- else
1259- {
1260- if(!strcasecmp(args[i], "on"))
1261- {
1262- /* Get old tx-power */
1263- IW_GET_EXT_ERR(skfd, ifname, SIOCGIWTXPOW, &wrq,
1264- "Set Tx Power");
1265- wrq.u.txpower.disabled = 0;
1266- }
1267- else
1268- {
1269- if(!strcasecmp(args[i], "fixed"))
1270- {
1271- /* Get old tx-power */
1272- IW_GET_EXT_ERR(skfd, ifname, SIOCGIWTXPOW, &wrq,
1273- "Set Tx Power");
1274- wrq.u.txpower.fixed = 1;
1275- wrq.u.txpower.disabled = 0;
1276- }
1277- else /* Should be a numeric value */
1278- {
1279- int power;
1280- int ismwatt = 0;
1281-
1282- /* Get the value */
1283- if(sscanf(args[i], "%i", &(power)) != 1)
1284- ABORT_ARG_TYPE("Set Tx Power", SIOCSIWTXPOW,
1285- args[i]);
1286-
1287- /* Check if milliWatt
1288- * We authorise a single 'm' as a shorthand for 'mW',
1289- * on the other hand a 'd' probably means 'dBm'... */
1290- ismwatt = ((index(args[i], 'm') != NULL)
1291- && (index(args[i], 'd') == NULL));
1292-
1293- /* We could check 'W' alone... Another time... */
1294-
1295- /* Convert */
1296- if(range.txpower_capa & IW_TXPOW_RELATIVE)
1297- {
1298- /* Can't convert */
1299- if(ismwatt)
1300- ABORT_ARG_TYPE("Set Tx Power",
1301- SIOCSIWTXPOW,
1302- args[i]);
1303- }
1304- else
1305- if(range.txpower_capa & IW_TXPOW_MWATT)
1306- {
1307- if(!ismwatt)
1308- power = iw_dbm2mwatt(power);
1309- wrq.u.txpower.flags = IW_TXPOW_MWATT;
1310- }
1311- else
1312- {
1313- if(ismwatt)
1314- power = iw_mwatt2dbm(power);
1315- wrq.u.txpower.flags = IW_TXPOW_DBM;
1316- }
1317- wrq.u.txpower.value = power;
1318-
1319- /* Check for an additional argument */
1320- if(((i+1) < count) &&
1321- (!strcasecmp(args[i+1], "auto")))
1322- {
1323- wrq.u.txpower.fixed = 0;
1324- ++i;
1325- }
1326- if(((i+1) < count) &&
1327- (!strcasecmp(args[i+1], "fixed")))
1328- {
1329- wrq.u.txpower.fixed = 1;
1330- ++i;
1331- }
1332- }
1333- }
1334- }
1335-
1336- IW_SET_EXT_ERR(skfd, ifname, SIOCSIWTXPOW, &wrq,
1337- "Set Tx Power");
1338- continue;
1443+ wrq.u.retry.flags |= IW_RETRY_RELATIVE;
13391444 }
1340-
1341- /* ---------- Set Retry limit ---------- */
1342- if(!strncmp(args[i], "retry", 3))
1445+ else
13431446 {
1344- double temp;
1345- int gotone = 0;
1447+ /* Normalise lifetime */
1448+ value *= MEGA; /* default = s */
1449+ if(unit[0] == 'u') value /= MEGA;
1450+ if(unit[0] == 'm') value /= KILO;
1451+ }
1452+ }
1453+ wrq.u.retry.value = (long) value;
1454+ ++i;
13461455
1347- if(++i >= count)
1348- ABORT_ARG_NUM("Set Retry Limit", SIOCSIWRETRY);
1456+ if(iw_set_ext(skfd, ifname, SIOCSIWRETRY, &wrq) < 0)
1457+ return(IWERR_SET_EXT);
13491458
1350- /* Default - nope */
1351- wrq.u.retry.flags = IW_RETRY_LIMIT;
1352- wrq.u.retry.disabled = 0;
1459+ /* Var args */
1460+ return(i);
1461+}
13531462
1354- /* Check value modifier */
1355- if(!strcasecmp(args[i], "min"))
1356- {
1357- wrq.u.retry.flags |= IW_RETRY_MIN;
1358- if(++i >= count)
1359- ABORT_ARG_NUM("Set Retry Limit", SIOCSIWRETRY);
1360- }
1361- else
1362- if(!strcasecmp(args[i], "max"))
1463+/*------------------------------------------------------------------*/
1464+/*
1465+ * Set RTS Threshold
1466+ */
1467+static int
1468+set_rts_info(int skfd,
1469+ char * ifname,
1470+ char * args[], /* Command line args */
1471+ int count) /* Args count */
1472+{
1473+ struct iwreq wrq;
1474+
1475+ /* Avoid "Unused parameter" warning */
1476+ count = count;
1477+
1478+ wrq.u.rts.value = -1;
1479+ wrq.u.rts.fixed = 1;
1480+ wrq.u.rts.disabled = 0;
1481+
1482+ if(!strcasecmp(args[0], "off"))
1483+ wrq.u.rts.disabled = 1; /* i.e. max size */
1484+ else
1485+ if(!strcasecmp(args[0], "auto"))
1486+ wrq.u.rts.fixed = 0;
1487+ else
1488+ {
1489+ if(!strcasecmp(args[0], "fixed"))
1490+ {
1491+ /* Get old RTS threshold */
1492+ if(iw_get_ext(skfd, ifname, SIOCGIWRTS, &wrq) < 0)
1493+ return(IWERR_GET_EXT);
1494+ wrq.u.rts.fixed = 1;
1495+ }
1496+ else
1497+ { /* Should be a numeric value */
1498+ long temp;
1499+ if(sscanf(args[0], "%li", (unsigned long *) &(temp)) != 1)
13631500 {
1364- wrq.u.retry.flags |= IW_RETRY_MAX;
1365- if(++i >= count)
1366- ABORT_ARG_NUM("Set Retry Limit", SIOCSIWRETRY);
1501+ errarg = 0;
1502+ return(IWERR_ARG_TYPE);
13671503 }
1504+ wrq.u.rts.value = temp;
1505+ }
1506+ }
13681507
1369- /* Check value type */
1370- if(!strcasecmp(args[i], "limit"))
1371- {
1372- wrq.u.retry.flags |= IW_RETRY_LIMIT;
1373- if(++i >= count)
1374- ABORT_ARG_NUM("Set Retry Limit", SIOCSIWRETRY);
1375- }
1376- else
1377- if(!strncasecmp(args[i], "lifetime", 4))
1508+ if(iw_set_ext(skfd, ifname, SIOCSIWRTS, &wrq) < 0)
1509+ return(IWERR_SET_EXT);
1510+
1511+ /* 1 arg */
1512+ return(1);
1513+}
1514+
1515+/*------------------------------------------------------------------*/
1516+/*
1517+ * Set Fragmentation Threshold
1518+ */
1519+static int
1520+set_frag_info(int skfd,
1521+ char * ifname,
1522+ char * args[], /* Command line args */
1523+ int count) /* Args count */
1524+{
1525+ struct iwreq wrq;
1526+
1527+ /* Avoid "Unused parameter" warning */
1528+ count = count;
1529+
1530+ wrq.u.frag.value = -1;
1531+ wrq.u.frag.fixed = 1;
1532+ wrq.u.frag.disabled = 0;
1533+
1534+ if(!strcasecmp(args[0], "off"))
1535+ wrq.u.frag.disabled = 1; /* i.e. max size */
1536+ else
1537+ if(!strcasecmp(args[0], "auto"))
1538+ wrq.u.frag.fixed = 0;
1539+ else
1540+ {
1541+ if(!strcasecmp(args[0], "fixed"))
1542+ {
1543+ /* Get old fragmentation threshold */
1544+ if(iw_get_ext(skfd, ifname, SIOCGIWFRAG, &wrq) < 0)
1545+ return(IWERR_GET_EXT);
1546+ wrq.u.frag.fixed = 1;
1547+ }
1548+ else
1549+ { /* Should be a numeric value */
1550+ long temp;
1551+ if(sscanf(args[0], "%li", &(temp))
1552+ != 1)
13781553 {
1379- wrq.u.retry.flags &= ~IW_RETRY_LIMIT;
1380- wrq.u.retry.flags |= IW_RETRY_LIFETIME;
1381- if(++i >= count)
1382- ABORT_ARG_NUM("Set Retry Limit", SIOCSIWRETRY);
1554+ errarg = 0;
1555+ return(IWERR_ARG_TYPE);
13831556 }
1557+ wrq.u.frag.value = temp;
1558+ }
1559+ }
1560+
1561+ if(iw_set_ext(skfd, ifname, SIOCSIWFRAG, &wrq) < 0)
1562+ return(IWERR_SET_EXT);
1563+
1564+ /* 1 arg */
1565+ return(1);
1566+}
1567+
1568+/*------------------------------------------------------------------*/
1569+/*
1570+ * Set Modulation
1571+ */
1572+static int
1573+set_modulation_info(int skfd,
1574+ char * ifname,
1575+ char * args[], /* Command line args */
1576+ int count) /* Args count */
1577+{
1578+ struct iwreq wrq;
1579+ int i = 1;
1580+
1581+ /* Avoid "Unused parameter" warning */
1582+ args = args; count = count;
1583+
1584+ if(!strcasecmp(args[0], "auto"))
1585+ wrq.u.param.fixed = 0; /* i.e. use any modulation */
1586+ else
1587+ {
1588+ if(!strcasecmp(args[0], "fixed"))
1589+ {
1590+ /* Get old modulation */
1591+ if(iw_get_ext(skfd, ifname, SIOCGIWMODUL, &wrq) < 0)
1592+ return(IWERR_GET_EXT);
1593+ wrq.u.param.fixed = 1;
1594+ }
1595+ else
1596+ {
1597+ int k;
13841598
1385- /* Is there any value to grab ? */
1386- if(sscanf(args[i], "%lg", &(temp)) == 1)
1599+ /* Allow multiple modulations, combine them together */
1600+ wrq.u.param.value = 0x0;
1601+ i = 0;
1602+ do
13871603 {
1388- /* Limit is absolute, on the other hand lifetime is seconds */
1389- if(!(wrq.u.retry.flags & IW_RETRY_LIMIT))
1604+ for(k = 0; k < IW_SIZE_MODUL_LIST; k++)
13901605 {
1391- /* Normalise lifetime */
1392- temp *= MEGA; /* default = s */
1393- if(index(args[i], 'u')) temp /= MEGA;
1394- if(index(args[i], 'm')) temp /= KILO;
1606+ if(!strcasecmp(args[i], iw_modul_list[k].cmd))
1607+ {
1608+ wrq.u.param.value |= iw_modul_list[k].mask;
1609+ ++i;
1610+ break;
1611+ }
13951612 }
1396- wrq.u.retry.value = (long) temp;
1613+ }
1614+ /* For as long as current arg matched and not out of args */
1615+ while((i < count) && (k < IW_SIZE_MODUL_LIST));
1616+
1617+ /* Check we got something */
1618+ if(i == 0)
1619+ {
1620+ errarg = 0;
1621+ return(IWERR_ARG_TYPE);
1622+ }
1623+
1624+ /* Check for an additional argument */
1625+ if((i < count) && (!strcasecmp(args[i], "auto")))
1626+ {
1627+ wrq.u.param.fixed = 0;
1628+ ++i;
1629+ }
1630+ if((i < count) && (!strcasecmp(args[i], "fixed")))
1631+ {
1632+ wrq.u.param.fixed = 1;
13971633 ++i;
1398- gotone = 1;
13991634 }
1635+ }
1636+ }
1637+
1638+ if(iw_set_ext(skfd, ifname, SIOCSIWMODUL, &wrq) < 0)
1639+ return(IWERR_SET_EXT);
1640+
1641+ /* Var args */
1642+ return(i);
1643+}
1644+#endif /* WE_ESSENTIAL */
1645+
1646+/*------------------------------------------------------------------*/
1647+/*
1648+ * Set commit
1649+ */
1650+static int
1651+set_commit_info(int skfd,
1652+ char * ifname,
1653+ char * args[], /* Command line args */
1654+ int count) /* Args count */
1655+{
1656+ struct iwreq wrq;
1657+
1658+ /* Avoid "Unused parameter" warning */
1659+ args = args; count = count;
1660+
1661+ if(iw_set_ext(skfd, ifname, SIOCSIWCOMMIT, &wrq) < 0)
1662+ return(IWERR_SET_EXT);
1663+
1664+ /* No args */
1665+ return(0);
1666+}
14001667
1401- if(!gotone)
1402- ABORT_ARG_TYPE("Set Retry Limit", SIOCSIWRETRY, args[i]);
1403- --i;
1668+/************************** SET DISPATCHER **************************/
1669+/*
1670+ * This is a modified version of the dispatcher in iwlist.
1671+ * The main difference is that here we may have multiple commands per
1672+ * line. Also, most commands here do take arguments, and most often
1673+ * a variable number of them.
1674+ * Therefore, the handler *must* return how many args were consumed...
1675+ *
1676+ * Note that the use of multiple commands per line is not advised
1677+ * in scripts, as it makes error management hard. All commands before
1678+ * the error are executed, but commands after the error are not
1679+ * processed.
1680+ * We also try to give as much clue as possible via stderr to the caller
1681+ * on which command did fail, but if there are two time the same command,
1682+ * you don't know which one failed...
1683+ */
14041684
1405- IW_SET_EXT_ERR(skfd, ifname, SIOCSIWRETRY, &wrq,
1406- "Set Retry Limit");
1407- continue;
1685+/*------------------------------------------------------------------*/
1686+/*
1687+ * Map command line arguments to the proper procedure...
1688+ */
1689+typedef struct iwconfig_entry {
1690+ const char * cmd; /* Command line shorthand */
1691+ iw_enum_handler fn; /* Subroutine */
1692+ int min_count;
1693+ int request; /* WE numerical ID */
1694+ const char * name; /* Human readable string */
1695+ const char * argsname; /* Args as human readable string */
1696+} iwconfig_cmd;
1697+
1698+static const struct iwconfig_entry iwconfig_cmds[] = {
1699+ { "essid", set_essid_info, 1, SIOCSIWESSID,
1700+ "Set ESSID", "{NNN|any|on|off}" },
1701+ { "mode", set_mode_info, 1, SIOCSIWMODE,
1702+ "Set Mode", "{managed|ad-hoc|master|...}" },
1703+ { "freq", set_freq_info, 1, SIOCSIWFREQ,
1704+ "Set Frequency", "N.NNN[k|M|G]" },
1705+ { "channel", set_freq_info, 1, SIOCSIWFREQ,
1706+ "Set Frequency", "N" },
1707+ { "bit", set_bitrate_info, 1, SIOCSIWRATE,
1708+ "Set Bit Rate", "{N[k|M|G]|auto|fixed}" },
1709+ { "rate", set_bitrate_info, 1, SIOCSIWRATE,
1710+ "Set Bit Rate", "{N[k|M|G]|auto|fixed}" },
1711+ { "enc", set_enc_info, 1, SIOCSIWENCODE,
1712+ "Set Encode", "{NNNN-NNNN|off}" },
1713+ { "key", set_enc_info, 1, SIOCSIWENCODE,
1714+ "Set Encode", "{NNNN-NNNN|off}" },
1715+ { "power", set_power_info, 1, SIOCSIWPOWER,
1716+ "Set Power Management", "{period N|timeout N|saving N|off}" },
1717+#ifndef WE_ESSENTIAL
1718+ { "nickname", set_nick_info, 1, SIOCSIWNICKN,
1719+ "Set Nickname", "NNN" },
1720+ { "nwid", set_nwid_info, 1, SIOCSIWNWID,
1721+ "Set NWID", "{NN|on|off}" },
1722+ { "ap", set_apaddr_info, 1, SIOCSIWAP,
1723+ "Set AP Address", "{N|off|auto}" },
1724+ { "txpower", set_txpower_info, 1, SIOCSIWTXPOW,
1725+ "Set Tx Power", "{NmW|NdBm|off|auto}" },
1726+ { "sens", set_sens_info, 1, SIOCSIWSENS,
1727+ "Set Sensitivity", "N" },
1728+ { "retry", set_retry_info, 1, SIOCSIWRETRY,
1729+ "Set Retry Limit", "{limit N|lifetime N}" },
1730+ { "rts", set_rts_info, 1, SIOCSIWRTS,
1731+ "Set RTS Threshold", "{N|auto|fixed|off}" },
1732+ { "frag", set_frag_info, 1, SIOCSIWFRAG,
1733+ "Set Fragmentation Threshold", "{N|auto|fixed|off}" },
1734+ { "modulation", set_modulation_info, 1, SIOCGIWMODUL,
1735+ "Set Modulation", "{11g|11a|CCK|OFDMg|...}" },
1736+#endif /* WE_ESSENTIAL */
1737+ { "commit", set_commit_info, 0, SIOCSIWCOMMIT,
1738+ "Commit changes", "" },
1739+ { NULL, NULL, 0, 0, NULL, NULL },
1740+};
1741+
1742+/*------------------------------------------------------------------*/
1743+/*
1744+ * Find the most appropriate command matching the command line
1745+ */
1746+static inline const iwconfig_cmd *
1747+find_command(const char * cmd)
1748+{
1749+ const iwconfig_cmd * found = NULL;
1750+ int ambig = 0;
1751+ unsigned int len = strlen(cmd);
1752+ int i;
1753+
1754+ /* Go through all commands */
1755+ for(i = 0; iwconfig_cmds[i].cmd != NULL; ++i)
1756+ {
1757+ /* No match -> next one */
1758+ if(strncasecmp(iwconfig_cmds[i].cmd, cmd, len) != 0)
1759+ continue;
1760+
1761+ /* Exact match -> perfect */
1762+ if(len == strlen(iwconfig_cmds[i].cmd))
1763+ return &iwconfig_cmds[i];
1764+
1765+ /* Partial match */
1766+ if(found == NULL)
1767+ /* First time */
1768+ found = &iwconfig_cmds[i];
1769+ else
1770+ /* Another time */
1771+ if (iwconfig_cmds[i].fn != found->fn)
1772+ ambig = 1;
1773+ }
1774+
1775+ if(found == NULL)
1776+ {
1777+ fprintf(stderr, "iwconfig: unknown command \"%s\"\n", cmd);
1778+ return NULL;
1779+ }
1780+
1781+ if(ambig)
1782+ {
1783+ fprintf(stderr, "iwconfig: command \"%s\" is ambiguous\n", cmd);
1784+ return NULL;
1785+ }
1786+
1787+ return found;
1788+}
1789+
1790+/*------------------------------------------------------------------*/
1791+/*
1792+ * Set the wireless options requested on command line
1793+ * Find the individual commands and call the appropriate subroutine
1794+ */
1795+static int
1796+set_info(int skfd, /* The socket */
1797+ char * args[], /* Command line args */
1798+ int count, /* Args count */
1799+ char * ifname) /* Dev name */
1800+{
1801+ const iwconfig_cmd * iwcmd;
1802+ int ret;
1803+
1804+ /* Loop until we run out of args... */
1805+ while(count > 0)
1806+ {
1807+ /* find the command matching the keyword */
1808+ iwcmd = find_command(args[0]);
1809+ if(iwcmd == NULL)
1810+ {
1811+ /* Here we have an unrecognised arg... Error already printed out. */
1812+ return(-1);
14081813 }
14091814
1410- /* ---------- Other ---------- */
1411- /* Here we have an unrecognised arg... */
1412- fprintf(stderr, "Error : unrecognised wireless request \"%s\"\n",
1413- args[i]);
1414- return(-1);
1415- } /* for(index ... */
1815+ /* One arg is consumed (the command name) */
1816+ args++;
1817+ count--;
1818+
1819+ /* Check arg numbers */
1820+ if(count < iwcmd->min_count)
1821+ ret = IWERR_ARG_NUM;
1822+ else
1823+ ret = 0;
1824+
1825+ /* Call the command */
1826+ if(!ret)
1827+ ret = (*iwcmd->fn)(skfd, ifname, args, count);
1828+
1829+ /* Deal with various errors */
1830+ if(ret < 0)
1831+ {
1832+ int request = iwcmd->request;
1833+ if(ret == IWERR_GET_EXT)
1834+ request++; /* Transform the SET into GET */
1835+
1836+ fprintf(stderr, "Error for wireless request \"%s\" (%X) :\n",
1837+ iwcmd->name, request);
1838+ switch(ret)
1839+ {
1840+ case IWERR_ARG_NUM:
1841+ fprintf(stderr, " too few arguments.\n");
1842+ break;
1843+ case IWERR_ARG_TYPE:
1844+ if(errarg < 0)
1845+ errarg = 0;
1846+ if(errarg >= count)
1847+ errarg = count - 1;
1848+ fprintf(stderr, " invalid argument \"%s\".\n", args[errarg]);
1849+ break;
1850+ case IWERR_ARG_SIZE:
1851+ fprintf(stderr, " argument too big (max %d)\n", errmax);
1852+ break;
1853+ case IWERR_ARG_CONFLICT:
1854+ if(errarg < 0)
1855+ errarg = 0;
1856+ if(errarg >= count)
1857+ errarg = count - 1;
1858+ fprintf(stderr, " conflicting argument \"%s\".\n", args[errarg]);
1859+ break;
1860+ case IWERR_SET_EXT:
1861+ fprintf(stderr, " SET failed on device %-1.16s ; %s.\n",
1862+ ifname, strerror(errno));
1863+ break;
1864+ case IWERR_GET_EXT:
1865+ fprintf(stderr, " GET failed on device %-1.16s ; %s.\n",
1866+ ifname, strerror(errno));
1867+ break;
1868+ }
1869+ /* Stop processing, we don't know if we are in a consistent state
1870+ * in reading the command line */
1871+ return(ret);
1872+ }
1873+
1874+ /* Substract consumed args from command line */
1875+ args += ret;
1876+ count -= ret;
1877+
1878+ /* Loop back */
1879+ }
1880+
1881+ /* Done, all done */
14161882 return(0);
14171883 }
14181884
1885+/*------------------------------------------------------------------*/
1886+/*
1887+ * Display help
1888+ */
1889+static inline void
1890+iw_usage(void)
1891+{
1892+ int i;
1893+
1894+ fprintf(stderr, "Usage: iwconfig [interface]\n");
1895+ for(i = 0; iwconfig_cmds[i].cmd != NULL; ++i)
1896+ fprintf(stderr, " interface %s %s\n",
1897+ iwconfig_cmds[i].cmd, iwconfig_cmds[i].argsname);
1898+ fprintf(stderr, " Check man pages for more details.\n");
1899+}
1900+
1901+
14191902 /******************************* MAIN ********************************/
14201903
14211904 /*------------------------------------------------------------------*/
--- a/wireless_tools/iwlib.c
+++ b/wireless_tools/iwlib.c
@@ -1,12 +1,12 @@
11 /*
22 * Wireless Tools
33 *
4- * Jean II - HPLB 97->99 - HPL 99->04
4+ * Jean II - HPLB 97->99 - HPL 99->07
55 *
66 * Common subroutines to all the wireless tools...
77 *
88 * This file is released under the GPL license.
9- * Copyright (c) 1997-2004 Jean Tourrilhes <jt@hpl.hp.com>
9+ * Copyright (c) 1997-2007 Jean Tourrilhes <jt@hpl.hp.com>
1010 */
1111
1212 /***************************** INCLUDES *****************************/
@@ -99,7 +99,44 @@ const char * const iw_operation_mode[] = { "Auto",
9999 "Master",
100100 "Repeater",
101101 "Secondary",
102- "Monitor" };
102+ "Monitor",
103+ "Unknown/bug" };
104+
105+/* Modulations as human readable strings */
106+const struct iw_modul_descr iw_modul_list[] = {
107+ /* Start with aggregate types, so that they display first */
108+ { IW_MODUL_11AG, "11ag",
109+ "IEEE 802.11a + 802.11g (2.4 & 5 GHz, up to 54 Mb/s)" },
110+ { IW_MODUL_11AB, "11ab",
111+ "IEEE 802.11a + 802.11b (2.4 & 5 GHz, up to 54 Mb/s)" },
112+ { IW_MODUL_11G, "11g", "IEEE 802.11g (2.4 GHz, up to 54 Mb/s)" },
113+ { IW_MODUL_11A, "11a", "IEEE 802.11a (5 GHz, up to 54 Mb/s)" },
114+ { IW_MODUL_11B, "11b", "IEEE 802.11b (2.4 GHz, up to 11 Mb/s)" },
115+
116+ /* Proprietary aggregates */
117+ { IW_MODUL_TURBO | IW_MODUL_11A, "turboa",
118+ "Atheros turbo mode at 5 GHz (up to 108 Mb/s)" },
119+ { IW_MODUL_TURBO | IW_MODUL_11G, "turbog",
120+ "Atheros turbo mode at 2.4 GHz (up to 108 Mb/s)" },
121+ { IW_MODUL_PBCC | IW_MODUL_11B, "11+",
122+ "TI 802.11+ (2.4 GHz, up to 22 Mb/s)" },
123+
124+ /* Individual modulations */
125+ { IW_MODUL_OFDM_G, "OFDMg",
126+ "802.11g higher rates, OFDM at 2.4 GHz (up to 54 Mb/s)" },
127+ { IW_MODUL_OFDM_A, "OFDMa", "802.11a, OFDM at 5 GHz (up to 54 Mb/s)" },
128+ { IW_MODUL_CCK, "CCK", "802.11b higher rates (2.4 GHz, up to 11 Mb/s)" },
129+ { IW_MODUL_DS, "DS", "802.11 Direct Sequence (2.4 GHz, up to 2 Mb/s)" },
130+ { IW_MODUL_FH, "FH", "802.11 Frequency Hopping (2,4 GHz, up to 2 Mb/s)" },
131+
132+ /* Proprietary modulations */
133+ { IW_MODUL_TURBO, "turbo",
134+ "Atheros turbo mode, channel bonding (up to 108 Mb/s)" },
135+ { IW_MODUL_PBCC, "PBCC",
136+ "TI 802.11+ higher rates (2.4 GHz, up to 22 Mb/s)" },
137+ { IW_MODUL_CUSTOM, "custom",
138+ "Driver specific modulation (check driver documentation)" },
139+};
103140
104141 /* Disable runtime version warning in iw_get_range_info() */
105142 int iw_ignore_version = 0;
@@ -407,7 +444,7 @@ iw_print_version_info(const char * toolname)
407444 if(toolname != NULL)
408445 printf("%-8.16s Wireless-Tools version %d\n", toolname, WT_VERSION);
409446 printf(" Compatible with Wireless Extension v11 to v%d.\n\n",
410- WE_VERSION);
447+ WE_MAX_VERSION);
411448
412449 /* Get version from kernel */
413450 we_kernel_version = iw_get_kernel_we_version();
@@ -521,7 +558,7 @@ iw_get_range_info(int skfd,
521558 if(range->we_version_compiled > WE_MAX_VERSION)
522559 {
523560 fprintf(stderr, "Warning: Driver for device %s has been compiled with version %d\n", ifname, range->we_version_compiled);
524- fprintf(stderr, "of Wireless Extension, while this program supports up to version %d.\n", WE_VERSION);
561+ fprintf(stderr, "of Wireless Extension, while this program supports up to version %d.\n", WE_MAX_VERSION);
525562 fprintf(stderr, "Some things may be broken...\n\n");
526563 }
527564
@@ -681,9 +718,12 @@ iw_get_basic_config(int skfd,
681718 /* Get operation mode */
682719 if(iw_get_ext(skfd, ifname, SIOCGIWMODE, &wrq) >= 0)
683720 {
684- info->mode = wrq.u.mode;
685- if((info->mode < IW_NUM_OPER_MODE) && (info->mode >= 0))
686- info->has_mode = 1;
721+ info->has_mode = 1;
722+ /* Note : event->u.mode is unsigned, no need to check <= 0 */
723+ if(wrq.u.mode < IW_NUM_OPER_MODE)
724+ info->mode = wrq.u.mode;
725+ else
726+ info->mode = IW_NUM_OPER_MODE; /* Unknown/bug */
687727 }
688728
689729 return(0);
@@ -802,10 +842,10 @@ iw_set_basic_config(int skfd,
802842 we_kernel_version = iw_get_kernel_we_version();
803843
804844 wrq.u.essid.pointer = (caddr_t) info->essid;
805- wrq.u.essid.length = strlen(info->essid) + 1;
845+ wrq.u.essid.length = strlen(info->essid);
806846 wrq.u.data.flags = info->essid_on;
807- if(we_kernel_version > 20)
808- wrq.u.essid.length--;
847+ if(we_kernel_version < 21)
848+ wrq.u.essid.length++;
809849
810850 if(iw_set_ext(skfd, ifname, SIOCSIWESSID, &wrq) < 0)
811851 {
@@ -1320,7 +1360,9 @@ iw_print_stats(char * buffer,
13201360 * Further, on 8 bits, 0x100 == 256 == 0.
13211361 *
13221362 * Relative/percent values are always encoded unsigned, between 0 and 255.
1323- * Absolute/dBm values are always encoded negative, between -255 and 0.
1363+ * Absolute/dBm values are always encoded between -192 and 63.
1364+ * (Note that up to version 28 of Wireless Tools, dBm used to be
1365+ * encoded always negative, between -256 and -1).
13241366 *
13251367 * How do we separate relative from absolute values ?
13261368 * The old way is to use the range to do that. As of WE-19, we have
@@ -1329,7 +1371,7 @@ iw_print_stats(char * buffer,
13291371 * range struct only specify one bound of the value, we assume that
13301372 * the other bound is 0 (zero).
13311373 * For relative values, range is [0 ; range->max].
1332- * For absolute values, range is [range->max ; 0].
1374+ * For absolute values, range is [range->max ; 63].
13331375 *
13341376 * Let's take two example :
13351377 * 1) value is 75%. qual->value = 75 ; range->max_qual.value = 100
@@ -1343,7 +1385,8 @@ iw_print_stats(char * buffer,
13431385 * The old way to detect dBm require both the range and a non-null
13441386 * level (which confuse the test). The new way can deal with level of 0
13451387 * because it does an explicit test on the flag. */
1346- if(has_range && ((qual->level != 0) || (qual->updated & IW_QUAL_DBM)))
1388+ if(has_range && ((qual->level != 0)
1389+ || (qual->updated & (IW_QUAL_DBM | IW_QUAL_RCPI))))
13471390 {
13481391 /* Deal with quality : always a relative value */
13491392 if(!(qual->updated & IW_QUAL_QUAL_INVALID))
@@ -1355,16 +1398,17 @@ iw_print_stats(char * buffer,
13551398 buflen -= len;
13561399 }
13571400
1358- /* Check if the statistics are in dBm or relative */
1359- if((qual->updated & IW_QUAL_DBM)
1360- || (qual->level > range->max_qual.level))
1401+ /* Check if the statistics are in RCPI (IEEE 802.11k) */
1402+ if(qual->updated & IW_QUAL_RCPI)
13611403 {
1362- /* Deal with signal level in dBm (absolute power measurement) */
1404+ /* Deal with signal level in RCPI */
1405+ /* RCPI = int{(Power in dBm +110)*2} for 0dbm > Power > -110dBm */
13631406 if(!(qual->updated & IW_QUAL_LEVEL_INVALID))
13641407 {
1365- len = snprintf(buffer, buflen, "Signal level%c%d dBm ",
1408+ double rcpilevel = (qual->level / 2.0) - 110.0;
1409+ len = snprintf(buffer, buflen, "Signal level%c%g dBm ",
13661410 qual->updated & IW_QUAL_LEVEL_UPDATED ? '=' : ':',
1367- qual->level - 0x100);
1411+ rcpilevel);
13681412 buffer += len;
13691413 buflen -= len;
13701414 }
@@ -1372,29 +1416,63 @@ iw_print_stats(char * buffer,
13721416 /* Deal with noise level in dBm (absolute power measurement) */
13731417 if(!(qual->updated & IW_QUAL_NOISE_INVALID))
13741418 {
1375- len = snprintf(buffer, buflen, "Noise level%c%d dBm",
1419+ double rcpinoise = (qual->noise / 2.0) - 110.0;
1420+ len = snprintf(buffer, buflen, "Noise level%c%g dBm",
13761421 qual->updated & IW_QUAL_NOISE_UPDATED ? '=' : ':',
1377- qual->noise - 0x100);
1422+ rcpinoise);
13781423 }
13791424 }
13801425 else
13811426 {
1382- /* Deal with signal level as relative value (0 -> max) */
1383- if(!(qual->updated & IW_QUAL_LEVEL_INVALID))
1427+ /* Check if the statistics are in dBm */
1428+ if((qual->updated & IW_QUAL_DBM)
1429+ || (qual->level > range->max_qual.level))
13841430 {
1385- len = snprintf(buffer, buflen, "Signal level%c%d/%d ",
1386- qual->updated & IW_QUAL_LEVEL_UPDATED ? '=' : ':',
1387- qual->level, range->max_qual.level);
1388- buffer += len;
1389- buflen -= len;
1390- }
1431+ /* Deal with signal level in dBm (absolute power measurement) */
1432+ if(!(qual->updated & IW_QUAL_LEVEL_INVALID))
1433+ {
1434+ int dblevel = qual->level;
1435+ /* Implement a range for dBm [-192; 63] */
1436+ if(qual->level >= 64)
1437+ dblevel -= 0x100;
1438+ len = snprintf(buffer, buflen, "Signal level%c%d dBm ",
1439+ qual->updated & IW_QUAL_LEVEL_UPDATED ? '=' : ':',
1440+ dblevel);
1441+ buffer += len;
1442+ buflen -= len;
1443+ }
13911444
1392- /* Deal with noise level as relative value (0 -> max) */
1393- if(!(qual->updated & IW_QUAL_NOISE_INVALID))
1445+ /* Deal with noise level in dBm (absolute power measurement) */
1446+ if(!(qual->updated & IW_QUAL_NOISE_INVALID))
1447+ {
1448+ int dbnoise = qual->noise;
1449+ /* Implement a range for dBm [-192; 63] */
1450+ if(qual->noise >= 64)
1451+ dbnoise -= 0x100;
1452+ len = snprintf(buffer, buflen, "Noise level%c%d dBm",
1453+ qual->updated & IW_QUAL_NOISE_UPDATED ? '=' : ':',
1454+ dbnoise);
1455+ }
1456+ }
1457+ else
13941458 {
1395- len = snprintf(buffer, buflen, "Noise level%c%d/%d",
1396- qual->updated & IW_QUAL_NOISE_UPDATED ? '=' : ':',
1397- qual->noise, range->max_qual.noise);
1459+ /* Deal with signal level as relative value (0 -> max) */
1460+ if(!(qual->updated & IW_QUAL_LEVEL_INVALID))
1461+ {
1462+ len = snprintf(buffer, buflen, "Signal level%c%d/%d ",
1463+ qual->updated & IW_QUAL_LEVEL_UPDATED ? '=' : ':',
1464+ qual->level, range->max_qual.level);
1465+ buffer += len;
1466+ buflen -= len;
1467+ }
1468+
1469+ /* Deal with noise level as relative value (0 -> max) */
1470+ if(!(qual->updated & IW_QUAL_NOISE_INVALID))
1471+ {
1472+ len = snprintf(buffer, buflen, "Noise level%c%d/%d",
1473+ qual->updated & IW_QUAL_NOISE_UPDATED ? '=' : ':',
1474+ qual->noise, range->max_qual.noise);
1475+ }
13981476 }
13991477 }
14001478 }
@@ -1644,7 +1722,8 @@ void
16441722 iw_print_pm_value(char * buffer,
16451723 int buflen,
16461724 int value,
1647- int flags)
1725+ int flags,
1726+ int we_version)
16481727 {
16491728 /* Check size */
16501729 if(buflen < 25)
@@ -1674,13 +1753,25 @@ iw_print_pm_value(char * buffer,
16741753 }
16751754 else
16761755 {
1677- strcpy(buffer, " period:"); /* Size checked */
1678- buffer += 8;
1756+ if(flags & IW_POWER_SAVING)
1757+ {
1758+ strcpy(buffer, " saving:"); /* Size checked */
1759+ buffer += 8;
1760+ }
1761+ else
1762+ {
1763+ strcpy(buffer, " period:"); /* Size checked */
1764+ buffer += 8;
1765+ }
16791766 }
16801767
16811768 /* Display value without units */
16821769 if(flags & IW_POWER_RELATIVE)
1683- snprintf(buffer, buflen, "%g", ((double) value) / MEGA);
1770+ {
1771+ if(we_version < 21)
1772+ value /= MEGA;
1773+ snprintf(buffer, buflen, "%d", value);
1774+ }
16841775 else
16851776 {
16861777 /* Display value with units */
@@ -1744,15 +1835,16 @@ void
17441835 iw_print_retry_value(char * buffer,
17451836 int buflen,
17461837 int value,
1747- int flags)
1838+ int flags,
1839+ int we_version)
17481840 {
17491841 /* Check buffer size */
1750- if(buflen < 18)
1842+ if(buflen < 20)
17511843 {
17521844 snprintf(buffer, buflen, "<too big>");
17531845 return;
17541846 }
1755- buflen -= 18;
1847+ buflen -= 20;
17561848
17571849 /* Modifiers */
17581850 if(flags & IW_RETRY_MIN)
@@ -1765,6 +1857,16 @@ iw_print_retry_value(char * buffer,
17651857 strcpy(buffer, " max"); /* Size checked */
17661858 buffer += 4;
17671859 }
1860+ if(flags & IW_RETRY_SHORT)
1861+ {
1862+ strcpy(buffer, " short"); /* Size checked */
1863+ buffer += 6;
1864+ }
1865+ if(flags & IW_RETRY_LONG)
1866+ {
1867+ strcpy(buffer, " long"); /* Size checked */
1868+ buffer += 6;
1869+ }
17681870
17691871 /* Type lifetime of limit */
17701872 if(flags & IW_RETRY_LIFETIME)
@@ -1773,8 +1875,12 @@ iw_print_retry_value(char * buffer,
17731875 buffer += 10;
17741876
17751877 /* Display value without units */
1776- if(flags & IW_POWER_RELATIVE)
1777- snprintf(buffer, buflen, "%g", ((double) value) / MEGA);
1878+ if(flags & IW_RETRY_RELATIVE)
1879+ {
1880+ if(we_version < 21)
1881+ value /= MEGA;
1882+ snprintf(buffer, buflen, "%d", value);
1883+ }
17781884 else
17791885 {
17801886 /* Display value with units */
@@ -2125,7 +2231,7 @@ iw_in_addr(int skfd,
21252231 struct sockaddr *sap)
21262232 {
21272233 /* Check if it is a hardware or IP address */
2128- if(index(bufp, ':') == NULL)
2234+ if(strchr(bufp, ':') == NULL)
21292235 {
21302236 struct sockaddr if_address;
21312237 struct arpreq arp_query;
@@ -2467,6 +2573,12 @@ static const struct iw_ioctl_description standard_ioctl_descr[] = {
24672573 [SIOCGIWPOWER - SIOCIWFIRST] = {
24682574 .header_type = IW_HEADER_TYPE_PARAM,
24692575 },
2576+ [SIOCSIWMODUL - SIOCIWFIRST] = {
2577+ .header_type = IW_HEADER_TYPE_PARAM,
2578+ },
2579+ [SIOCGIWMODUL - SIOCIWFIRST] = {
2580+ .header_type = IW_HEADER_TYPE_PARAM,
2581+ },
24702582 [SIOCSIWGENIE - SIOCIWFIRST] = {
24712583 .header_type = IW_HEADER_TYPE_POINT,
24722584 .token_size = 1,
@@ -2560,17 +2672,17 @@ static const unsigned int standard_event_num = (sizeof(standard_event_descr) /
25602672
25612673 /* Size (in bytes) of various events */
25622674 static const int event_type_size[] = {
2563- IW_EV_LCP_LEN, /* IW_HEADER_TYPE_NULL */
2675+ IW_EV_LCP_PK_LEN, /* IW_HEADER_TYPE_NULL */
25642676 0,
2565- IW_EV_CHAR_LEN, /* IW_HEADER_TYPE_CHAR */
2677+ IW_EV_CHAR_PK_LEN, /* IW_HEADER_TYPE_CHAR */
25662678 0,
2567- IW_EV_UINT_LEN, /* IW_HEADER_TYPE_UINT */
2568- IW_EV_FREQ_LEN, /* IW_HEADER_TYPE_FREQ */
2569- IW_EV_ADDR_LEN, /* IW_HEADER_TYPE_ADDR */
2679+ IW_EV_UINT_PK_LEN, /* IW_HEADER_TYPE_UINT */
2680+ IW_EV_FREQ_PK_LEN, /* IW_HEADER_TYPE_FREQ */
2681+ IW_EV_ADDR_PK_LEN, /* IW_HEADER_TYPE_ADDR */
25702682 0,
2571- IW_EV_POINT_LEN, /* Without variable payload */
2572- IW_EV_PARAM_LEN, /* IW_HEADER_TYPE_PARAM */
2573- IW_EV_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */
2683+ IW_EV_POINT_PK_LEN, /* Without variable payload */
2684+ IW_EV_PARAM_PK_LEN, /* IW_HEADER_TYPE_PARAM */
2685+ IW_EV_QUAL_PK_LEN, /* IW_HEADER_TYPE_QUAL */
25742686 };
25752687
25762688 /*------------------------------------------------------------------*/
@@ -2607,29 +2719,26 @@ iw_extract_event_stream(struct stream_descr * stream, /* Stream of events */
26072719 /* Don't "optimise" the following variable, it will crash */
26082720 unsigned cmd_index; /* *MUST* be unsigned */
26092721
2610- /* Unused for now. Will be later on... */
2611- we_version = we_version;
2612-
26132722 /* Check for end of stream */
2614- if((stream->current + IW_EV_LCP_LEN) > stream->end)
2723+ if((stream->current + IW_EV_LCP_PK_LEN) > stream->end)
26152724 return(0);
26162725
2617-#if DEBUG
2726+#ifdef DEBUG
26182727 printf("DBG - stream->current = %p, stream->value = %p, stream->end = %p\n",
26192728 stream->current, stream->value, stream->end);
26202729 #endif
26212730
26222731 /* Extract the event header (to get the event id).
26232732 * Note : the event may be unaligned, therefore copy... */
2624- memcpy((char *) iwe, stream->current, IW_EV_LCP_LEN);
2733+ memcpy((char *) iwe, stream->current, IW_EV_LCP_PK_LEN);
26252734
2626-#if DEBUG
2735+#ifdef DEBUG
26272736 printf("DBG - iwe->cmd = 0x%X, iwe->len = %d\n",
26282737 iwe->cmd, iwe->len);
26292738 #endif
26302739
26312740 /* Check invalid events */
2632- if(iwe->len <= IW_EV_LCP_LEN)
2741+ if(iwe->len <= IW_EV_LCP_PK_LEN)
26332742 return(-1);
26342743
26352744 /* Get the type and length of that event */
@@ -2647,28 +2756,28 @@ iw_extract_event_stream(struct stream_descr * stream, /* Stream of events */
26472756 }
26482757 if(descr != NULL)
26492758 event_type = descr->header_type;
2650- /* Unknown events -> event_type=0 => IW_EV_LCP_LEN */
2759+ /* Unknown events -> event_type=0 => IW_EV_LCP_PK_LEN */
26512760 event_len = event_type_size[event_type];
26522761 /* Fixup for earlier version of WE */
26532762 if((we_version <= 18) && (event_type == IW_HEADER_TYPE_POINT))
26542763 event_len += IW_EV_POINT_OFF;
26552764
26562765 /* Check if we know about this event */
2657- if(event_len <= IW_EV_LCP_LEN)
2766+ if(event_len <= IW_EV_LCP_PK_LEN)
26582767 {
26592768 /* Skip to next event */
26602769 stream->current += iwe->len;
26612770 return(2);
26622771 }
2663- event_len -= IW_EV_LCP_LEN;
2772+ event_len -= IW_EV_LCP_PK_LEN;
26642773
26652774 /* Set pointer on data */
26662775 if(stream->value != NULL)
26672776 pointer = stream->value; /* Next value in event */
26682777 else
2669- pointer = stream->current + IW_EV_LCP_LEN; /* First value in event */
2778+ pointer = stream->current + IW_EV_LCP_PK_LEN; /* First value in event */
26702779
2671-#if DEBUG
2780+#ifdef DEBUG
26722781 printf("DBG - event_type = %d, event_len = %d, pointer = %p\n",
26732782 event_type, event_len, pointer);
26742783 #endif
@@ -2681,6 +2790,7 @@ iw_extract_event_stream(struct stream_descr * stream, /* Stream of events */
26812790 return(-2);
26822791 }
26832792 /* Fixup for WE-19 and later : pointer no longer in the stream */
2793+ /* Beware of alignement. Dest has local alignement, not packed */
26842794 if((we_version > 18) && (event_type == IW_HEADER_TYPE_POINT))
26852795 memcpy((char *) iwe + IW_EV_LCP_LEN + IW_EV_POINT_OFF,
26862796 pointer, event_len);
@@ -2694,7 +2804,7 @@ iw_extract_event_stream(struct stream_descr * stream, /* Stream of events */
26942804 if(event_type == IW_HEADER_TYPE_POINT)
26952805 {
26962806 /* Check the length of the payload */
2697- unsigned int extra_len = iwe->len - (event_len + IW_EV_LCP_LEN);
2807+ unsigned int extra_len = iwe->len - (event_len + IW_EV_LCP_PK_LEN);
26982808 if(extra_len > 0)
26992809 {
27002810 /* Set pointer on variable part (warning : non aligned) */
@@ -2709,9 +2819,35 @@ iw_extract_event_stream(struct stream_descr * stream, /* Stream of events */
27092819 /* Those checks are actually pretty hard to trigger,
27102820 * because of the checks done in the kernel... */
27112821
2822+ unsigned int token_len = iwe->u.data.length * descr->token_size;
2823+
2824+ /* Ugly fixup for alignement issues.
2825+ * If the kernel is 64 bits and userspace 32 bits,
2826+ * we have an extra 4+4 bytes.
2827+ * Fixing that in the kernel would break 64 bits userspace. */
2828+ if((token_len != extra_len) && (extra_len >= 4))
2829+ {
2830+ __u16 alt_dlen = *((__u16 *) pointer);
2831+ unsigned int alt_token_len = alt_dlen * descr->token_size;
2832+ if((alt_token_len + 8) == extra_len)
2833+ {
2834+#ifdef DEBUG
2835+ printf("DBG - alt_token_len = %d\n", alt_token_len);
2836+#endif
2837+ /* Ok, let's redo everything */
2838+ pointer -= event_len;
2839+ pointer += 4;
2840+ /* Dest has local alignement, not packed */
2841+ memcpy((char *) iwe + IW_EV_LCP_LEN + IW_EV_POINT_OFF,
2842+ pointer, event_len);
2843+ pointer += event_len + 4;
2844+ iwe->u.data.pointer = pointer;
2845+ token_len = alt_token_len;
2846+ }
2847+ }
2848+
27122849 /* Discard bogus events which advertise more tokens than
27132850 * what they carry... */
2714- unsigned int token_len = iwe->u.data.length * descr->token_size;
27152851 if(token_len > extra_len)
27162852 iwe->u.data.pointer = NULL; /* Discard paylod */
27172853 /* Check that the advertised token size is not going to
@@ -2722,7 +2858,7 @@ iw_extract_event_stream(struct stream_descr * stream, /* Stream of events */
27222858 /* Same for underflows... */
27232859 if(iwe->u.data.length < descr->min_tokens)
27242860 iwe->u.data.pointer = NULL; /* Discard paylod */
2725-#if DEBUG
2861+#ifdef DEBUG
27262862 printf("DBG - extra_len = %d, token_len = %d, token = %d, max = %d, min = %d\n",
27272863 extra_len, token_len, iwe->u.data.length, descr->max_tokens, descr->min_tokens);
27282864 #endif
@@ -2737,6 +2873,25 @@ iw_extract_event_stream(struct stream_descr * stream, /* Stream of events */
27372873 }
27382874 else
27392875 {
2876+ /* Ugly fixup for alignement issues.
2877+ * If the kernel is 64 bits and userspace 32 bits,
2878+ * we have an extra 4 bytes.
2879+ * Fixing that in the kernel would break 64 bits userspace. */
2880+ if((stream->value == NULL)
2881+ && ((((iwe->len - IW_EV_LCP_PK_LEN) % event_len) == 4)
2882+ || ((iwe->len == 12) && ((event_type == IW_HEADER_TYPE_UINT) ||
2883+ (event_type == IW_HEADER_TYPE_QUAL))) ))
2884+ {
2885+#ifdef DEBUG
2886+ printf("DBG - alt iwe->len = %d\n", iwe->len - 4);
2887+#endif
2888+ pointer -= event_len;
2889+ pointer += 4;
2890+ /* Beware of alignement. Dest has local alignement, not packed */
2891+ memcpy((char *) iwe + IW_EV_LCP_LEN, pointer, event_len);
2892+ pointer += event_len;
2893+ }
2894+
27402895 /* Is there more value in the event ? */
27412896 if((pointer + event_len) <= (stream->current + iwe->len))
27422897 /* Go to next value */
@@ -2847,8 +3002,14 @@ iw_process_scanning_token(struct iw_event * event,
28473002 memcpy(&wscan->stats.qual, &event->u.qual, sizeof(struct iw_quality));
28483003 break;
28493004 case SIOCGIWRATE:
2850- /* Scan may return a list of bitrates. Should we really bother with
2851- * an array of bitrates ? Or only the maximum bitrate ? Jean II */
3005+ /* Scan may return a list of bitrates. As we have space for only
3006+ * a single bitrate, we only keep the largest one. */
3007+ if((!wscan->has_maxbitrate) ||
3008+ (event->u.bitrate.value > wscan->maxbitrate.value))
3009+ {
3010+ wscan->has_maxbitrate = 1;
3011+ memcpy(&(wscan->maxbitrate), &(event->u.bitrate), sizeof(iwparam));
3012+ }
28523013 case IWEVCUSTOM:
28533014 /* How can we deal with those sanely ? Jean II */
28543015 default:
@@ -2893,7 +3054,9 @@ iw_process_scan(int skfd,
28933054 wrq.u.data.pointer = NULL; /* Later */
28943055 wrq.u.data.flags = 0;
28953056 wrq.u.data.length = 0;
2896- if(iw_set_ext(skfd, ifname, SIOCSIWSCAN, &wrq) < 0)
3057+ /* Remember that as non-root, we will get an EPERM here */
3058+ if((iw_set_ext(skfd, ifname, SIOCSIWSCAN, &wrq) < 0)
3059+ && (errno != EPERM))
28973060 return(-1);
28983061 /* Success : now, just wait for event or results */
28993062 return(250); /* Wait 250 ms */
@@ -2959,7 +3122,7 @@ iw_process_scan(int skfd,
29593122 struct stream_descr stream;
29603123 struct wireless_scan * wscan = NULL;
29613124 int ret;
2962-#if DEBUG
3125+#ifdef DEBUG
29633126 /* Debugging code. In theory useless, because it's debugged ;-) */
29643127 int i;
29653128 printf("Scan result [%02X", buffer[0]);
--- a/wireless_tools/iwlib.h
+++ b/wireless_tools/iwlib.h
@@ -1,12 +1,12 @@
11 /*
22 * Wireless Tools
33 *
4- * Jean II - HPLB 97->99 - HPL 99->04
4+ * Jean II - HPLB 97->99 - HPL 99->07
55 *
66 * Common header for the Wireless Extension library...
77 *
88 * This file is released under the GPL license.
9- * Copyright (c) 1997-2004 Jean Tourrilhes <jt@hpl.hp.com>
9+ * Copyright (c) 1997-2007 Jean Tourrilhes <jt@hpl.hp.com>
1010 */
1111
1212 #ifndef IWLIB_H
@@ -33,41 +33,17 @@
3333 #include <unistd.h>
3434
3535 /* This is our header selection. Try to hide the mess and the misery :-(
36- * Don't look, you would go blind ;-) */
37-
38-#ifndef LINUX_VERSION_CODE
39-#include <linux/version.h>
40-#endif
41-
42-/* Kernel headers 2.4.X + Glibc 2.2 - Mandrake 8.0, Debian 2.3, RH 7.1
43- * Kernel headers 2.2.X + Glibc 2.2 - Slackware 8.0 */
44-#if defined(__GLIBC__) \
45- && __GLIBC__ == 2 \
46- && __GLIBC_MINOR__ >= 2 \
47- && LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
48-#define HEADERS_GENERIC
49-
50-/* Kernel headers 2.4.X + Glibc 2.1 - Debian 2.2 upgraded, RH 7.0
51- * Kernel headers 2.2.X + Glibc 2.1 - Debian 2.2, RH 6.1 */
52-#elif defined(__GLIBC__) \
53- && __GLIBC__ == 2 \
54- && __GLIBC_MINOR__ == 1 \
55- && LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
56-#define HEADERS_GENERIC
57-#define HEADERS_KERNEL
58-
59-/* Unsupported combination */
60-#else
61-#error "Your kernel/libc combination is not supported"
62-#endif
36+ * Don't look, you would go blind ;-)
37+ * Note : compatibility with *old* distributions has been removed,
38+ * you will need Glibc 2.2 and older to compile (which means
39+ * Mandrake 8.0, Debian 2.3, RH 7.1 or older).
40+ */
6341
64-#ifdef HEADERS_GENERIC
65-/* Proposed by Dr. Michael Rietz <rietz@mail.amps.de>, 27.3.2 */
42+/* Set of headers proposed by Dr. Michael Rietz <rietz@mail.amps.de>, 27.3.2 */
6643 #include <net/if_arp.h> /* For ARPHRD_ETHER */
6744 #include <sys/socket.h> /* For AF_INET & struct sockaddr */
6845 #include <netinet/in.h> /* For struct sockaddr_in */
6946 #include <netinet/if_ether.h>
70-#endif /* HEADERS_GENERIC */
7147
7248 /* Fixup to be able to include kernel includes in userspace.
7349 * Basically, kill the sparse annotations... Jean II */
@@ -77,15 +53,9 @@
7753
7854 #include <linux/types.h> /* for "caddr_t" et al */
7955
80-#ifdef HEADERS_KERNEL
81-/* Traditionally we have used kernel headers, included in wireless.h */
82-#include <linux/socket.h> /* for "struct sockaddr" et al */
83-#include <linux/if.h> /* for IFNAMSIZ and co... */
84-#else /* !HEADERS_KERNEL */
8556 /* Glibc systems headers are supposedly less problematic than kernel ones */
8657 #include <sys/socket.h> /* for "struct sockaddr" et al */
8758 #include <net/if.h> /* for IFNAMSIZ and co... */
88-#endif /* !HEADERS_KERNEL */
8959
9060 /* Private copy of Wireless extensions (in this directoty) */
9161 #include "wireless.h"
@@ -126,16 +96,17 @@ extern "C" {
12696
12797 /****************************** DEBUG ******************************/
12898
99+//#define DEBUG 1
129100
130101 /************************ CONSTANTS & MACROS ************************/
131102
132103 /* Various versions information */
133104 /* Recommended Wireless Extension version */
134-#define WE_VERSION 20
105+#define WE_VERSION 21
135106 /* Maximum forward compatibility built in this version of WT */
136-#define WE_MAX_VERSION 21
107+#define WE_MAX_VERSION 22
137108 /* Version of Wireless Tools */
138-#define WT_VERSION 28
109+#define WT_VERSION 29
139110
140111 /* Paths */
141112 #define PROC_NET_WIRELESS "/proc/net/wireless"
@@ -153,6 +124,36 @@ extern "C" {
153124 #define ARPHRD_IEEE80211 801 /* IEEE 802.11 */
154125 #endif /* ARPHRD_IEEE80211 */
155126
127+#ifndef IW_EV_LCP_PK_LEN
128+/* Size of the Event prefix when packed in stream */
129+#define IW_EV_LCP_PK_LEN (4)
130+/* Size of the various events when packed in stream */
131+#define IW_EV_CHAR_PK_LEN (IW_EV_LCP_PK_LEN + IFNAMSIZ)
132+#define IW_EV_UINT_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(__u32))
133+#define IW_EV_FREQ_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(struct iw_freq))
134+#define IW_EV_PARAM_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(struct iw_param))
135+#define IW_EV_ADDR_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(struct sockaddr))
136+#define IW_EV_QUAL_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(struct iw_quality))
137+#define IW_EV_POINT_PK_LEN (IW_EV_LCP_PK_LEN + 4)
138+
139+struct iw_pk_event
140+{
141+ __u16 len; /* Real lenght of this stuff */
142+ __u16 cmd; /* Wireless IOCTL */
143+ union iwreq_data u; /* IOCTL fixed payload */
144+} __attribute__ ((packed));
145+struct iw_pk_point
146+{
147+ void __user *pointer; /* Pointer to the data (in user space) */
148+ __u16 length; /* number of fields or size in bytes */
149+ __u16 flags; /* Optional params */
150+} __attribute__ ((packed));
151+
152+#define IW_EV_LCP_PK2_LEN (sizeof(struct iw_pk_event) - sizeof(union iwreq_data))
153+#define IW_EV_POINT_PK2_LEN (IW_EV_LCP_PK2_LEN + sizeof(struct iw_pk_point) - IW_EV_POINT_OFF)
154+
155+#endif /* IW_EV_LCP_PK_LEN */
156+
156157 /****************************** TYPES ******************************/
157158
158159 /* Shortcuts */
@@ -244,6 +245,8 @@ typedef struct wireless_scan
244245 struct wireless_config b; /* Basic information */
245246 iwstats stats; /* Signal strength */
246247 int has_stats;
248+ iwparam maxbitrate; /* Max bit rate in bps */
249+ int has_maxbitrate;
247250 } wireless_scan;
248251
249252 /*
@@ -271,6 +274,14 @@ typedef int (*iw_enum_handler)(int skfd,
271274 char * args[],
272275 int count);
273276
277+/* Describe a modulation */
278+typedef struct iw_modul_descr
279+{
280+ unsigned int mask; /* Modulation bitmask */
281+ char cmd[8]; /* Short name */
282+ char * verbose; /* Verbose description */
283+} iw_modul_descr;
284+
274285 /**************************** PROTOTYPES ****************************/
275286 /*
276287 * All the functions in iwcommon.c
@@ -379,7 +390,8 @@ void
379390 iw_print_pm_value(char * buffer,
380391 int buflen,
381392 int value,
382- int flags);
393+ int flags,
394+ int we_version);
383395 void
384396 iw_print_pm_mode(char * buffer,
385397 int buflen,
@@ -389,7 +401,8 @@ void
389401 iw_print_retry_value(char * buffer,
390402 int buflen,
391403 int value,
392- int flags);
404+ int flags,
405+ int we_version);
393406 /* ----------------------- TIME SUBROUTINES ----------------------- */
394407 void
395408 iw_print_timeval(char * buffer,
@@ -469,6 +482,11 @@ int
469482 /* Modes as human readable strings */
470483 extern const char * const iw_operation_mode[];
471484 #define IW_NUM_OPER_MODE 7
485+#define IW_NUM_OPER_MODE_EXT 8
486+
487+/* Modulations as human readable strings */
488+extern const struct iw_modul_descr iw_modul_list[];
489+#define IW_SIZE_MODUL_LIST 16
472490
473491 /************************* INLINE FUNTIONS *************************/
474492 /*
--- a/wireless_tools/iwlist.8
+++ b/wireless_tools/iwlist.8
@@ -1,7 +1,7 @@
11 .\" Jean II - HPLB - 96
22 .\" iwlist.8
33 .\"
4-.TH IWLIST 8 "23 June 2004" "wireless-tools" "Linux Programmer's Manual"
4+.TH IWLIST 8 "13 April 2006" "wireless-tools" "Linux Programmer's Manual"
55 .\"
66 .\" NAME part
77 .\"
@@ -11,21 +11,29 @@ iwlist \- Get more detailed wireless information from a wireless interface
1111 .\" SYNOPSIS part
1212 .\"
1313 .SH SYNOPSIS
14-.BI "iwlist " interface " scanning"
14+.BI "iwlist [" interface "] scanning"
1515 .br
16-.BI "iwlist " interface " frequency"
16+.BI "iwlist [" interface "] frequency"
1717 .br
18-.BI "iwlist " interface " rate"
18+.BI "iwlist [" interface "] rate"
1919 .br
20-.BI "iwlist " interface " key"
20+.BI "iwlist [" interface "] keys"
2121 .br
22-.BI "iwlist " interface " power"
22+.BI "iwlist [" interface "] power"
2323 .br
24-.BI "iwlist " interface " txpower"
24+.BI "iwlist [" interface "] txpower"
2525 .br
26-.BI "iwlist " interface " retry"
26+.BI "iwlist [" interface "] retry"
2727 .br
28-.BI "iwlist " interface " event"
28+.BI "iwlist [" interface "] event"
29+.br
30+.BI "iwlist [" interface "] auth"
31+.br
32+.BI "iwlist [" interface "] wpakeys"
33+.br
34+.BI "iwlist [" interface "] genie"
35+.br
36+.BI "iwlist [" interface "] modulation"
2937 .br
3038 .BI "iwlist --help"
3139 .br
@@ -58,10 +66,15 @@ the card supports.
5866 Triggering scanning is a privileged operation
5967 .RI ( root
6068 only) and normal users can only read left-over scan results. By
61-default, the way scanning is done (the scope of the scan) will be
62-impacted by the current setting of the driver. Also, this command is
63-supposed to take extra arguments to control the scanning behaviour,
64-but this is currently not implemented.
69+default, the way scanning is done (the scope of the scan) is dependant
70+on the card and card settings.
71+.br
72+This command take optional arguments, however most drivers will ignore
73+those. The option
74+.B essid
75+is used to specify a scan on a specific ESSID. The option
76+.B last
77+do not trigger a scan and read left-over scan results.
6578 .TP
6679 .BR freq [uency]/ channel
6780 Give the list of available frequencies in the device and the number of
@@ -73,9 +86,9 @@ displayed and channel numbers.
7386 .BR rate / bit [rate]
7487 List the bit-rates supported by the device.
7588 .TP
76-.BR key / enc [ryption]
77-List the encryption key sizes supported and display all the encryption
78-keys available in the device.
89+.BR keys / enc [ryption]
90+List the encryption key sizes supported and list all the encryption
91+keys set in the device.
7992 .TP
8093 .B power
8194 List the various Power Management attributes and modes of the device.
@@ -100,10 +113,27 @@ the card. See your driver documentation for details.
100113 .B event
101114 List the wireless events supported by the device.
102115 .TP
116+.B auth
117+List the WPA authentication parametes curently set.
118+.TP
119+.BR wpa [keys]
120+List all the WPA encryption keys set in the device.
121+.TP
122+.B genie
123+List the Generic Information Elements set in the device (used for WPA
124+support).
125+.TP
126+.BR modu [lation]
127+List the modulations supported by the device and the modulations
128+currently enabled.
129+.TP
103130 .B --version
104131 Display the version of the tools, as well as the recommended and
105132 current Wireless Extensions version for the tool and the various
106133 wireless interfaces.
134+.TP
135+.B --help
136+Display short help message.
107137 .\"
108138 .\" FILES part
109139 .\"
--- a/wireless_tools/iwlist.c
+++ b/wireless_tools/iwlist.c
@@ -1,14 +1,14 @@
11 /*
22 * Wireless Tools
33 *
4- * Jean II - HPLB '99 - HPL 99->04
4+ * Jean II - HPLB '99 - HPL 99->07
55 *
66 * This tool can access various piece of information on the card
77 * not part of iwconfig...
88 * You need to link this code against "iwlist.c" and "-lm".
99 *
1010 * This file is released under the GPL license.
11- * Copyright (c) 1997-2004 Jean Tourrilhes <jt@hpl.hp.com>
11+ * Copyright (c) 1997-2007 Jean Tourrilhes <jt@hpl.hp.com>
1212 */
1313
1414 #include "iwlib.h" /* Header */
@@ -26,758 +26,412 @@ typedef struct iwscan_state
2626 int val_index; /* Value in table 0->(N-1) */
2727 } iwscan_state;
2828
29+/*
30+ * Bit to name mapping
31+ */
32+typedef struct iwmask_name
33+{
34+ unsigned int mask; /* bit mask for the value */
35+ const char * name; /* human readable name for the value */
36+} iwmask_name;
2937
30-/*********************** FREQUENCIES/CHANNELS ***********************/
31-
32-/*------------------------------------------------------------------*/
3338 /*
34- * Print the number of channels and available frequency for the device
39+ * Types of authentication parameters
3540 */
36-static int
37-print_freq_info(int skfd,
38- char * ifname,
39- char * args[], /* Command line args */
40- int count) /* Args count */
41+typedef struct iw_auth_descr
4142 {
42- struct iwreq wrq;
43- struct iw_range range;
44- double freq;
45- int k;
46- int channel;
47- char buffer[128]; /* Temporary buffer */
43+ int value; /* Type of auth value */
44+ const char * label; /* User readable version */
45+ const struct iwmask_name * names; /* Names for this value */
46+ const int num_names; /* Number of names */
47+} iw_auth_descr;
4848
49- /* Avoid "Unused parameter" warning */
50- args = args; count = count;
49+/**************************** CONSTANTS ****************************/
5150
52- /* Get list of frequencies / channels */
53- if(iw_get_range_info(skfd, ifname, &range) < 0)
54- fprintf(stderr, "%-8.16s no frequency information.\n\n",
55- ifname);
56- else
57- {
58- if(range.num_frequency > 0)
59- {
60- printf("%-8.16s %d channels in total; available frequencies :\n",
61- ifname, range.num_channels);
62- /* Print them all */
63- for(k = 0; k < range.num_frequency; k++)
64- {
65- freq = iw_freq2float(&(range.freq[k]));
66- iw_print_freq_value(buffer, sizeof(buffer), freq);
67- printf(" Channel %.2d : %s\n",
68- range.freq[k].i, buffer);
69- }
70- }
71- else
72- printf("%-8.16s %d channels\n",
73- ifname, range.num_channels);
51+#define IW_SCAN_HACK 0x8000
7452
75- /* Get current frequency / channel and display it */
76- if(iw_get_ext(skfd, ifname, SIOCGIWFREQ, &wrq) >= 0)
77- {
78- freq = iw_freq2float(&(wrq.u.freq));
79- channel = iw_freq_to_channel(freq, &range);
80- iw_print_freq(buffer, sizeof(buffer),
81- freq, channel, wrq.u.freq.flags);
82- printf(" Current %s\n\n", buffer);
83- }
84- }
85- return(0);
86-}
53+#define IW_EXTKEY_SIZE (sizeof(struct iw_encode_ext) + IW_ENCODING_TOKEN_MAX)
8754
88-/************************ ACCESS POINT LIST ************************/
55+/* ------------------------ WPA CAPA NAMES ------------------------ */
8956 /*
90- * Note : now that we have scanning support, this is depracted and
91- * won't survive long. Actually, next version it's out !
57+ * This is the user readable name of a bunch of WPA constants in wireless.h
58+ * Maybe this should go in iwlib.c ?
9259 */
9360
94-/*------------------------------------------------------------------*/
95-/*
96- * Display the list of ap addresses and the associated stats
97- * Exacly the same as the spy list, only with different IOCTL and messages
98- */
99-static int
100-print_ap_info(int skfd,
101- char * ifname,
102- char * args[], /* Command line args */
103- int count) /* Args count */
104-{
105- struct iwreq wrq;
106- char buffer[(sizeof(struct iw_quality) +
107- sizeof(struct sockaddr)) * IW_MAX_AP];
108- char temp[128];
109- struct sockaddr * hwa;
110- struct iw_quality * qual;
111- iwrange range;
112- int has_range = 0;
113- int has_qual = 0;
114- int n;
115- int i;
61+#ifndef WE_ESSENTIAL
62+#define IW_ARRAY_LEN(x) (sizeof(x)/sizeof((x)[0]))
11663
117- /* Avoid "Unused parameter" warning */
118- args = args; count = count;
64+//static const struct iwmask_name iw_enc_mode_name[] = {
65+// { IW_ENCODE_RESTRICTED, "restricted" },
66+// { IW_ENCODE_OPEN, "open" },
67+//};
68+//#define IW_ENC_MODE_NUM IW_ARRAY_LEN(iw_enc_mode_name)
11969
120- /* Collect stats */
121- wrq.u.data.pointer = (caddr_t) buffer;
122- wrq.u.data.length = IW_MAX_AP;
123- wrq.u.data.flags = 0;
124- if(iw_get_ext(skfd, ifname, SIOCGIWAPLIST, &wrq) < 0)
125- {
126- fprintf(stderr, "%-8.16s Interface doesn't have a list of Peers/Access-Points\n\n", ifname);
127- return(-1);
128- }
70+static const struct iwmask_name iw_auth_capa_name[] = {
71+ { IW_ENC_CAPA_WPA, "WPA" },
72+ { IW_ENC_CAPA_WPA2, "WPA2" },
73+ { IW_ENC_CAPA_CIPHER_TKIP, "CIPHER-TKIP" },
74+ { IW_ENC_CAPA_CIPHER_CCMP, "CIPHER-CCMP" },
75+};
76+#define IW_AUTH_CAPA_NUM IW_ARRAY_LEN(iw_auth_capa_name)
77+
78+static const struct iwmask_name iw_auth_cypher_name[] = {
79+ { IW_AUTH_CIPHER_NONE, "none" },
80+ { IW_AUTH_CIPHER_WEP40, "WEP-40" },
81+ { IW_AUTH_CIPHER_TKIP, "TKIP" },
82+ { IW_AUTH_CIPHER_CCMP, "CCMP" },
83+ { IW_AUTH_CIPHER_WEP104, "WEP-104" },
84+};
85+#define IW_AUTH_CYPHER_NUM IW_ARRAY_LEN(iw_auth_cypher_name)
12986
130- /* Number of addresses */
131- n = wrq.u.data.length;
132- has_qual = wrq.u.data.flags;
87+static const struct iwmask_name iw_wpa_ver_name[] = {
88+ { IW_AUTH_WPA_VERSION_DISABLED, "disabled" },
89+ { IW_AUTH_WPA_VERSION_WPA, "WPA" },
90+ { IW_AUTH_WPA_VERSION_WPA2, "WPA2" },
91+};
92+#define IW_WPA_VER_NUM IW_ARRAY_LEN(iw_wpa_ver_name)
13393
134- /* The two lists */
135- hwa = (struct sockaddr *) buffer;
136- qual = (struct iw_quality *) (buffer + (sizeof(struct sockaddr) * n));
94+static const struct iwmask_name iw_auth_key_mgmt_name[] = {
95+ { IW_AUTH_KEY_MGMT_802_1X, "802.1x" },
96+ { IW_AUTH_KEY_MGMT_PSK, "PSK" },
97+};
98+#define IW_AUTH_KEY_MGMT_NUM IW_ARRAY_LEN(iw_auth_key_mgmt_name)
13799
138- /* Check if we have valid mac address type */
139- if(iw_check_mac_addr_type(skfd, ifname) < 0)
140- {
141- fprintf(stderr, "%-8.16s Interface doesn't support MAC addresses\n\n", ifname);
142- return(-2);
143- }
100+static const struct iwmask_name iw_auth_alg_name[] = {
101+ { IW_AUTH_ALG_OPEN_SYSTEM, "open" },
102+ { IW_AUTH_ALG_SHARED_KEY, "shared-key" },
103+ { IW_AUTH_ALG_LEAP, "LEAP" },
104+};
105+#define IW_AUTH_ALG_NUM IW_ARRAY_LEN(iw_auth_alg_name)
106+
107+static const struct iw_auth_descr iw_auth_settings[] = {
108+ { IW_AUTH_WPA_VERSION, "WPA version", iw_wpa_ver_name, IW_WPA_VER_NUM },
109+ { IW_AUTH_KEY_MGMT, "Key management", iw_auth_key_mgmt_name, IW_AUTH_KEY_MGMT_NUM },
110+ { IW_AUTH_CIPHER_PAIRWISE, "Pairwise cipher", iw_auth_cypher_name, IW_AUTH_CYPHER_NUM },
111+ { IW_AUTH_CIPHER_GROUP, "Pairwise cipher", iw_auth_cypher_name, IW_AUTH_CYPHER_NUM },
112+ { IW_AUTH_TKIP_COUNTERMEASURES, "TKIP countermeasures", NULL, 0 },
113+ { IW_AUTH_DROP_UNENCRYPTED, "Drop unencrypted", NULL, 0 },
114+ { IW_AUTH_80211_AUTH_ALG, "Authentication algorithm", iw_auth_alg_name, IW_AUTH_ALG_NUM },
115+ { IW_AUTH_RX_UNENCRYPTED_EAPOL, "Receive unencrypted EAPOL", NULL, 0 },
116+ { IW_AUTH_ROAMING_CONTROL, "Roaming control", NULL, 0 },
117+ { IW_AUTH_PRIVACY_INVOKED, "Privacy invoked", NULL, 0 },
118+};
119+#define IW_AUTH_SETTINGS_NUM IW_ARRAY_LEN(iw_auth_settings)
120+
121+/* Values for the IW_ENCODE_ALG_* returned by SIOCSIWENCODEEXT */
122+static const char * iw_encode_alg_name[] = {
123+ "none",
124+ "WEP",
125+ "TKIP",
126+ "CCMP",
127+ "unknown"
128+};
129+#define IW_ENCODE_ALG_NUM IW_ARRAY_LEN(iw_encode_alg_name)
130+
131+#ifndef IW_IE_CIPHER_NONE
132+/* Cypher values in GENIE (pairwise and group) */
133+#define IW_IE_CIPHER_NONE 0
134+#define IW_IE_CIPHER_WEP40 1
135+#define IW_IE_CIPHER_TKIP 2
136+#define IW_IE_CIPHER_WRAP 3
137+#define IW_IE_CIPHER_CCMP 4
138+#define IW_IE_CIPHER_WEP104 5
139+/* Key management in GENIE */
140+#define IW_IE_KEY_MGMT_NONE 0
141+#define IW_IE_KEY_MGMT_802_1X 1
142+#define IW_IE_KEY_MGMT_PSK 2
143+#endif /* IW_IE_CIPHER_NONE */
144+
145+/* Values for the IW_IE_CIPHER_* in GENIE */
146+static const char * iw_ie_cypher_name[] = {
147+ "none",
148+ "WEP-40",
149+ "TKIP",
150+ "WRAP",
151+ "CCMP",
152+ "WEP-104",
153+};
154+#define IW_IE_CYPHER_NUM IW_ARRAY_LEN(iw_ie_cypher_name)
144155
145- /* Get range info if we can */
146- if(iw_get_range_info(skfd, ifname, &(range)) >= 0)
147- has_range = 1;
156+/* Values for the IW_IE_KEY_MGMT_* in GENIE */
157+static const char * iw_ie_key_mgmt_name[] = {
158+ "none",
159+ "802.1x",
160+ "PSK",
161+};
162+#define IW_IE_KEY_MGMT_NUM IW_ARRAY_LEN(iw_ie_key_mgmt_name)
148163
149- /* Display it */
150- if(n == 0)
151- printf("%-8.16s No Peers/Access-Point in range\n", ifname);
152- else
153- printf("%-8.16s Peers/Access-Points in range:\n", ifname);
154- for(i = 0; i < n; i++)
164+#endif /* WE_ESSENTIAL */
165+
166+/************************* WPA SUBROUTINES *************************/
167+
168+#ifndef WE_ESSENTIAL
169+/*------------------------------------------------------------------*/
170+/*
171+ * Print all names corresponding to a mask.
172+ * This may want to be used in iw_print_retry_value() ?
173+ */
174+static void
175+iw_print_mask_name(unsigned int mask,
176+ const struct iwmask_name names[],
177+ const unsigned int num_names,
178+ const char * sep)
179+{
180+ unsigned int i;
181+
182+ /* Print out all names for the bitmask */
183+ for(i = 0; i < num_names; i++)
155184 {
156- if(has_qual)
185+ if(mask & names[i].mask)
157186 {
158- /* Print stats for this address */
159- printf(" %s : ", iw_saether_ntop(&hwa[i], temp));
160- iw_print_stats(temp, sizeof(buffer), &qual[i], &range, has_range);
161- printf("%s\n", temp);
187+ /* Print out */
188+ printf("%s%s", sep, names[i].name);
189+ /* Remove the bit from the mask */
190+ mask &= ~names[i].mask;
162191 }
163- else
164- /* Only print the address */
165- printf(" %s\n", iw_saether_ntop(&hwa[i], temp));
166192 }
167- printf("\n");
168- return(0);
193+ /* If there is unconsumed bits... */
194+ if(mask != 0)
195+ printf("%sUnknown", sep);
169196 }
170197
171-/***************************** BITRATES *****************************/
172-
173198 /*------------------------------------------------------------------*/
174199 /*
175- * Print the number of available bitrates for the device
200+ * Print the name corresponding to a value, with overflow check.
176201 */
177-static int
178-print_bitrate_info(int skfd,
179- char * ifname,
180- char * args[], /* Command line args */
181- int count) /* Args count */
202+static void
203+iw_print_value_name(unsigned int value,
204+ const char * names[],
205+ const unsigned int num_names)
182206 {
183- struct iwreq wrq;
184- struct iw_range range;
185- int k;
186- char buffer[128];
207+ if(value >= num_names)
208+ printf(" unknown (%d)", value);
209+ else
210+ printf(" %s", names[value]);
211+}
187212
188- /* Avoid "Unused parameter" warning */
189- args = args; count = count;
213+/*------------------------------------------------------------------*/
214+/*
215+ * Parse, and display the results of an unknown IE.
216+ *
217+ */
218+static void
219+iw_print_ie_unknown(unsigned char * iebuf,
220+ int buflen)
221+{
222+ int ielen = iebuf[1] + 2;
223+ int i;
190224
191- /* Extract range info */
192- if(iw_get_range_info(skfd, ifname, &range) < 0)
193- fprintf(stderr, "%-8.16s no bit-rate information.\n\n",
194- ifname);
195- else
196- {
197- if((range.num_bitrates > 0) && (range.num_bitrates <= IW_MAX_BITRATES))
198- {
199- printf("%-8.16s %d available bit-rates :\n",
200- ifname, range.num_bitrates);
201- /* Print them all */
202- for(k = 0; k < range.num_bitrates; k++)
203- {
204- iw_print_bitrate(buffer, sizeof(buffer), range.bitrate[k]);
205- /* Maybe this should be %10s */
206- printf("\t %s\n", buffer);
207- }
208- }
209- else
210- printf("%-8.16s unknown bit-rate information.\n", ifname);
225+ if(ielen > buflen)
226+ ielen = buflen;
211227
212- /* Get current bit rate */
213- if(iw_get_ext(skfd, ifname, SIOCGIWRATE, &wrq) >= 0)
214- {
215- iw_print_bitrate(buffer, sizeof(buffer), wrq.u.bitrate.value);
216- printf(" Current Bit Rate%c%s\n\n",
217- (wrq.u.bitrate.fixed ? '=' : ':'), buffer);
218- }
219- }
220- return(0);
228+ printf("Unknown: ");
229+ for(i = 0; i < ielen; i++)
230+ printf("%02X", iebuf[i]);
231+ printf("\n");
221232 }
222233
223-/************************* ENCRYPTION KEYS *************************/
224-
225234 /*------------------------------------------------------------------*/
226235 /*
227- * Print the number of available encryption key for the device
236+ * Parse, and display the results of a WPA or WPA2 IE.
237+ *
228238 */
229-static int
230-print_keys_info(int skfd,
231- char * ifname,
232- char * args[], /* Command line args */
233- int count) /* Args count */
239+static inline void
240+iw_print_ie_wpa(unsigned char * iebuf,
241+ int buflen)
234242 {
235- struct iwreq wrq;
236- struct iw_range range;
237- unsigned char key[IW_ENCODING_TOKEN_MAX];
238- int k;
239- char buffer[128];
243+ int ielen = iebuf[1] + 2;
244+ int offset = 2; /* Skip the IE id, and the length. */
245+ unsigned char wpa1_oui[3] = {0x00, 0x50, 0xf2};
246+ unsigned char wpa2_oui[3] = {0x00, 0x0f, 0xac};
247+ unsigned char * wpa_oui;
248+ int i;
249+ uint16_t ver = 0;
250+ uint16_t cnt = 0;
240251
241- /* Avoid "Unused parameter" warning */
242- args = args; count = count;
252+ if(ielen > buflen)
253+ ielen = buflen;
243254
244- /* Extract range info */
245- if(iw_get_range_info(skfd, ifname, &range) < 0)
246- fprintf(stderr, "%-8.16s no encryption keys information.\n\n",
247- ifname);
248- else
255+#ifdef DEBUG
256+ /* Debugging code. In theory useless, because it's debugged ;-) */
257+ printf("IE raw value %d [%02X", buflen, iebuf[0]);
258+ for(i = 1; i < buflen; i++)
259+ printf(":%02X", iebuf[i]);
260+ printf("]\n");
261+#endif
262+
263+ switch(iebuf[0])
249264 {
250- printf("%-8.16s ", ifname);
251- /* Print key sizes */
252- if((range.num_encoding_sizes > 0) &&
253- (range.num_encoding_sizes < IW_MAX_ENCODING_SIZES))
265+ case 0x30: /* WPA2 */
266+ /* Check if we have enough data */
267+ if(ielen < 4)
254268 {
255- printf("%d key sizes : %d", range.num_encoding_sizes,
256- range.encoding_size[0] * 8);
257- /* Print them all */
258- for(k = 1; k < range.num_encoding_sizes; k++)
259- printf(", %d", range.encoding_size[k] * 8);
260- printf("bits\n ");
269+ iw_print_ie_unknown(iebuf, buflen);
270+ return;
261271 }
262- /* Print the keys and associate mode */
263- printf("%d keys available :\n", range.max_encoding_tokens);
264- for(k = 1; k <= range.max_encoding_tokens; k++)
265- {
266- wrq.u.data.pointer = (caddr_t) key;
267- wrq.u.data.length = IW_ENCODING_TOKEN_MAX;
268- wrq.u.data.flags = k;
269- if(iw_get_ext(skfd, ifname, SIOCGIWENCODE, &wrq) < 0)
270- {
271- fprintf(stderr, "Error reading wireless keys (SIOCGIWENCODE): %s\n", strerror(errno));
272- break;
273- }
274- if((wrq.u.data.flags & IW_ENCODE_DISABLED) ||
275- (wrq.u.data.length == 0))
276- printf("\t\t[%d]: off\n", k);
277- else
278- {
279- /* Display the key */
280- iw_print_key(buffer, sizeof(buffer),
281- key, wrq.u.data.length, wrq.u.data.flags);
282- printf("\t\t[%d]: %s", k, buffer);
283272
284- /* Other info... */
285- printf(" (%d bits)", wrq.u.data.length * 8);
286- printf("\n");
287- }
288- }
289- /* Print current key and mode */
290- wrq.u.data.pointer = (caddr_t) key;
291- wrq.u.data.length = IW_ENCODING_TOKEN_MAX;
292- wrq.u.data.flags = 0; /* Set index to zero to get current */
293- if(iw_get_ext(skfd, ifname, SIOCGIWENCODE, &wrq) >= 0)
294- {
295- /* Note : if above fails, we have already printed an error
296- * message int the loop above */
297- printf(" Current Transmit Key: [%d]\n",
298- wrq.u.data.flags & IW_ENCODE_INDEX);
299- if(wrq.u.data.flags & IW_ENCODE_RESTRICTED)
300- printf(" Security mode:restricted\n");
301- if(wrq.u.data.flags & IW_ENCODE_OPEN)
302- printf(" Security mode:open\n");
303- }
273+ wpa_oui = wpa2_oui;
274+ break;
304275
305- /* Print WPA/802.1x/802.11i security parameters */
306- if(range.we_version_compiled > 17)
307- {
308- /* Display advance encryption capabilities */
309- if(range.enc_capa)
310- {
311- const char * auth_string[] = { "WPA",
312- "WPA2",
313- "CIPHER TKIP",
314- "CIPHER CCMP" };
315- const int auth_num = (sizeof(auth_string) /
316- sizeof(auth_string[1]));
317- int i;
318- int mask = 0x1;
319-
320- printf(" Authentication capabilities :\n");
321- for(i = 0; i < auth_num; i++)
322- {
323- if(range.enc_capa & mask)
324- printf("\t\t%s\n", auth_string[i]);
325- mask <<= 1;
326- }
327- }
276+ case 0xdd: /* WPA or else */
277+ wpa_oui = wpa1_oui;
278+
279+ /* Not all IEs that start with 0xdd are WPA.
280+ * So check that the OUI is valid. Note : offset==2 */
281+ if((ielen < 8)
282+ || (memcmp(&iebuf[offset], wpa_oui, 3) != 0)
283+ || (iebuf[offset + 3] != 0x01))
284+ {
285+ iw_print_ie_unknown(iebuf, buflen);
286+ return;
287+ }
328288
329- /* Current values for authentication */
330- wrq.u.param.flags = IW_AUTH_KEY_MGMT;
331- if(iw_get_ext(skfd, ifname, SIOCGIWAUTH, &wrq) >= 0)
332- printf(" Current key_mgmt:0x%X\n",
333- wrq.u.param.value);
334-
335- wrq.u.param.flags = IW_AUTH_CIPHER_PAIRWISE;
336- if(iw_get_ext(skfd, ifname, SIOCGIWAUTH, &wrq) >= 0)
337- printf(" Current cipher_pairwise:0x%X\n",
338- wrq.u.param.value);
339-
340- wrq.u.param.flags = IW_AUTH_CIPHER_GROUP;
341- if(iw_get_ext(skfd, ifname, SIOCGIWAUTH, &wrq) >= 0)
342- printf(" Current cipher_group:0x%X\n",
343- wrq.u.param.value);
344- }
289+ /* Skip the OUI type */
290+ offset += 4;
291+ break;
345292
346- printf("\n\n");
293+ default:
294+ return;
347295 }
348- return(0);
349-}
296+
297+ /* Pick version number (little endian) */
298+ ver = iebuf[offset] | (iebuf[offset + 1] << 8);
299+ offset += 2;
350300
351-/************************* POWER MANAGEMENT *************************/
301+ if(iebuf[0] == 0xdd)
302+ printf("WPA Version %d\n", ver);
303+ if(iebuf[0] == 0x30)
304+ printf("IEEE 802.11i/WPA2 Version %d\n", ver);
352305
353-/*------------------------------------------------------------------*/
354-/*
355- * Print Power Management info for each device
356- */
357-static inline int
358-get_pm_value(int skfd,
359- char * ifname,
360- struct iwreq * pwrq,
361- int flags,
362- char * buffer,
363- int buflen)
364-{
365- /* Get Another Power Management value */
366- pwrq->u.power.flags = flags;
367- if(iw_get_ext(skfd, ifname, SIOCGIWPOWER, pwrq) >= 0)
306+ /* From here, everything is technically optional. */
307+
308+ /* Check if we are done */
309+ if(ielen < (offset + 4))
368310 {
369- /* Let's check the value and its type */
370- if(pwrq->u.power.flags & IW_POWER_TYPE)
371- {
372- iw_print_pm_value(buffer, buflen,
373- pwrq->u.power.value, pwrq->u.power.flags);
374- printf("\n %s", buffer);
375- }
311+ /* We have a short IE. So we should assume TKIP/TKIP. */
312+ printf(" Group Cipher : TKIP\n");
313+ printf(" Pairwise Cipher : TKIP\n");
314+ return;
315+ }
316+
317+ /* Next we have our group cipher. */
318+ if(memcmp(&iebuf[offset], wpa_oui, 3) != 0)
319+ {
320+ printf(" Group Cipher : Proprietary\n");
376321 }
377- return(pwrq->u.power.flags);
378-}
379-
380-/*------------------------------------------------------------------*/
381-/*
382- * Print Power Management info for each device
383- */
384-static int
385-print_pm_info(int skfd,
386- char * ifname,
387- char * args[], /* Command line args */
388- int count) /* Args count */
389-{
390- struct iwreq wrq;
391- struct iw_range range;
392- char buffer[128];
393-
394- /* Avoid "Unused parameter" warning */
395- args = args; count = count;
396-
397- /* Extract range info */
398- if((iw_get_range_info(skfd, ifname, &range) < 0) ||
399- (range.we_version_compiled < 10))
400- fprintf(stderr, "%-8.16s no power management information.\n\n",
401- ifname);
402322 else
403323 {
404- printf("%-8.16s ", ifname);
324+ printf(" Group Cipher :");
325+ iw_print_value_name(iebuf[offset+3],
326+ iw_ie_cypher_name, IW_IE_CYPHER_NUM);
327+ printf("\n");
328+ }
329+ offset += 4;
405330
406- /* Display modes availables */
407- if(range.pm_capa & IW_POWER_MODE)
408- {
409- printf("Supported modes :\n ");
410- if(range.pm_capa & (IW_POWER_UNICAST_R | IW_POWER_MULTICAST_R))
411- printf("\t\to Receive all packets (unicast & multicast)\n ");
412- if(range.pm_capa & IW_POWER_UNICAST_R)
413- printf("\t\to Receive Unicast only (discard multicast)\n ");
414- if(range.pm_capa & IW_POWER_MULTICAST_R)
415- printf("\t\to Receive Multicast only (discard unicast)\n ");
416- if(range.pm_capa & IW_POWER_FORCE_S)
417- printf("\t\to Force sending using Power Management\n ");
418- if(range.pm_capa & IW_POWER_REPEATER)
419- printf("\t\to Repeat multicast\n ");
420- }
421- /* Display min/max period availables */
422- if(range.pmp_flags & IW_POWER_PERIOD)
423- {
424- int flags = (range.pmp_flags & ~(IW_POWER_MIN | IW_POWER_MAX));
425- /* Display if auto or fixed */
426- if(range.pmp_flags & IW_POWER_MIN)
427- printf("Auto period ; ");
428- else
429- printf("Fixed period ; ");
430- /* Print the range */
431- iw_print_pm_value(buffer, sizeof(buffer),
432- range.min_pmp, flags | IW_POWER_MIN);
433- printf("%s\n ", buffer);
434- iw_print_pm_value(buffer, sizeof(buffer),
435- range.max_pmp, flags | IW_POWER_MAX);
436- printf("%s\n ", buffer);
437- }
438- /* Display min/max timeout availables */
439- if(range.pmt_flags & IW_POWER_TIMEOUT)
440- {
441- int flags = (range.pmt_flags & ~(IW_POWER_MIN | IW_POWER_MAX));
442- /* Display if auto or fixed */
443- if(range.pmt_flags & IW_POWER_MIN)
444- printf("Auto timeout ; ");
445- else
446- printf("Fixed timeout ; ");
447- /* Print the range */
448- iw_print_pm_value(buffer, sizeof(buffer),
449- range.min_pmt, flags | IW_POWER_MIN);
450- printf("%s\n ", buffer);
451- iw_print_pm_value(buffer, sizeof(buffer),
452- range.max_pmt, flags | IW_POWER_MAX);
453- printf("%s\n ", buffer);
454- }
331+ /* Check if we are done */
332+ if(ielen < (offset + 2))
333+ {
334+ /* We don't have a pairwise cipher, or auth method. Assume TKIP. */
335+ printf(" Pairwise Ciphers : TKIP\n");
336+ return;
337+ }
455338
456- /* Get current Power Management settings */
457- wrq.u.power.flags = 0;
458- if(iw_get_ext(skfd, ifname, SIOCGIWPOWER, &wrq) >= 0)
459- {
460- int flags = wrq.u.power.flags;
339+ /* Otherwise, we have some number of pairwise ciphers. */
340+ cnt = iebuf[offset] | (iebuf[offset + 1] << 8);
341+ offset += 2;
342+ printf(" Pairwise Ciphers (%d) :", cnt);
461343
462- /* Is it disabled ? */
463- if(wrq.u.power.disabled)
464- printf("Current mode:off\n ");
465- else
466- {
467- int pm_mask = 0;
344+ if(ielen < (offset + 4*cnt))
345+ return;
468346
469- /* Let's check the mode */
470- iw_print_pm_mode(buffer, sizeof(buffer), flags);
471- printf("Current %s", buffer);
347+ for(i = 0; i < cnt; i++)
348+ {
349+ if(memcmp(&iebuf[offset], wpa_oui, 3) != 0)
350+ {
351+ printf(" Proprietary");
352+ }
353+ else
354+ {
355+ iw_print_value_name(iebuf[offset+3],
356+ iw_ie_cypher_name, IW_IE_CYPHER_NUM);
357+ }
358+ offset+=4;
359+ }
360+ printf("\n");
361+
362+ /* Check if we are done */
363+ if(ielen < (offset + 2))
364+ return;
472365
473- /* Let's check if nothing (simply on) */
474- if((flags & IW_POWER_MODE) == IW_POWER_ON)
475- printf("mode:on");
476- printf("\n ");
366+ /* Now, we have authentication suites. */
367+ cnt = iebuf[offset] | (iebuf[offset + 1] << 8);
368+ offset += 2;
369+ printf(" Authentication Suites (%d) :", cnt);
477370
478- /* Let's check the value and its type */
479- if(wrq.u.power.flags & IW_POWER_TYPE)
480- {
481- iw_print_pm_value(buffer, sizeof(buffer),
482- wrq.u.power.value, wrq.u.power.flags);
483- printf("%s", buffer);
484- }
371+ if(ielen < (offset + 4*cnt))
372+ return;
485373
486- /* If we have been returned a MIN value, ask for the MAX */
487- if(flags & IW_POWER_MIN)
488- pm_mask = IW_POWER_MAX;
489- /* If we have been returned a MAX value, ask for the MIN */
490- if(flags & IW_POWER_MAX)
491- pm_mask = IW_POWER_MIN;
492- /* If we have something to ask for... */
493- if(pm_mask)
494- get_pm_value(skfd, ifname, &wrq, pm_mask,
495- buffer, sizeof(buffer));
496-
497- /* And if we have both a period and a timeout, ask the other */
498- pm_mask = (range.pm_capa & (~(wrq.u.power.flags) &
499- IW_POWER_TYPE));
500- if(pm_mask)
501- {
502- int base_mask = pm_mask;
503- flags = get_pm_value(skfd, ifname, &wrq, pm_mask,
504- buffer, sizeof(buffer));
505- pm_mask = 0;
374+ for(i = 0; i < cnt; i++)
375+ {
376+ if(memcmp(&iebuf[offset], wpa_oui, 3) != 0)
377+ {
378+ printf(" Proprietary");
379+ }
380+ else
381+ {
382+ iw_print_value_name(iebuf[offset+3],
383+ iw_ie_key_mgmt_name, IW_IE_KEY_MGMT_NUM);
384+ }
385+ offset+=4;
386+ }
387+ printf("\n");
388+
389+ /* Check if we are done */
390+ if(ielen < (offset + 1))
391+ return;
506392
507- /* If we have been returned a MIN value, ask for the MAX */
508- if(flags & IW_POWER_MIN)
509- pm_mask = IW_POWER_MAX | base_mask;
510- /* If we have been returned a MAX value, ask for the MIN */
511- if(flags & IW_POWER_MAX)
512- pm_mask = IW_POWER_MIN | base_mask;
513- /* If we have something to ask for... */
514- if(pm_mask)
515- get_pm_value(skfd, ifname, &wrq, pm_mask,
516- buffer, sizeof(buffer));
517- }
518- }
519- }
520- printf("\n");
393+ /* Otherwise, we have capabilities bytes.
394+ * For now, we only care about preauth which is in bit position 1 of the
395+ * first byte. (But, preauth with WPA version 1 isn't supposed to be
396+ * allowed.) 8-) */
397+ if(iebuf[offset] & 0x01)
398+ {
399+ printf(" Preauthentication Supported\n");
521400 }
522- return(0);
523401 }
524-
525-/************************** TRANSMIT POWER **************************/
526-
402+
527403 /*------------------------------------------------------------------*/
528404 /*
529- * Print the number of available transmit powers for the device
405+ * Process a generic IE and display the info in human readable form
406+ * for some of the most interesting ones.
407+ * For now, we only decode the WPA IEs.
530408 */
531-static int
532-print_txpower_info(int skfd,
533- char * ifname,
534- char * args[], /* Command line args */
535- int count) /* Args count */
409+static inline void
410+iw_print_gen_ie(unsigned char * buffer,
411+ int buflen)
536412 {
537- struct iwreq wrq;
538- struct iw_range range;
539- int dbm;
540- int mwatt;
541- int k;
542-
543- /* Avoid "Unused parameter" warning */
544- args = args; count = count;
545-
546- /* Extract range info */
547- if((iw_get_range_info(skfd, ifname, &range) < 0) ||
548- (range.we_version_compiled < 10))
549- fprintf(stderr, "%-8.16s no transmit-power information.\n\n",
550- ifname);
551- else
552- {
553- if((range.num_txpower <= 0) || (range.num_txpower > IW_MAX_TXPOWER))
554- printf("%-8.16s unknown transmit-power information.\n\n", ifname);
555- else
556- {
557- printf("%-8.16s %d available transmit-powers :\n",
558- ifname, range.num_txpower);
559- /* Print them all */
560- for(k = 0; k < range.num_txpower; k++)
561- {
562- /* Check for relative values */
563- if(range.txpower_capa & IW_TXPOW_RELATIVE)
564- {
565- printf("\t %d (no units)\n", range.txpower[k]);
566- }
567- else
568- {
569- if(range.txpower_capa & IW_TXPOW_MWATT)
570- {
571- dbm = iw_mwatt2dbm(range.txpower[k]);
572- mwatt = range.txpower[k];
573- }
574- else
575- {
576- dbm = range.txpower[k];
577- mwatt = iw_dbm2mwatt(range.txpower[k]);
578- }
579- printf("\t %d dBm \t(%d mW)\n", dbm, mwatt);
580- }
581- }
582- }
583-
584- /* Get current Transmit Power */
585- if(iw_get_ext(skfd, ifname, SIOCGIWTXPOW, &wrq) >= 0)
586- {
587- printf(" Current Tx-Power");
588- /* Disabled ? */
589- if(wrq.u.txpower.disabled)
590- printf(":off\n\n");
591- else
592- {
593- /* Fixed ? */
594- if(wrq.u.txpower.fixed)
595- printf("=");
596- else
597- printf(":");
598- /* Check for relative values */
599- if(wrq.u.txpower.flags & IW_TXPOW_RELATIVE)
600- {
601- /* I just hate relative value, because they are
602- * driver specific, so not very meaningfull to apps.
603- * But, we have to support that, because
604- * this is the way hardware is... */
605- printf("\t %d (no units)\n", wrq.u.txpower.value);
606- }
607- else
608- {
609- if(wrq.u.txpower.flags & IW_TXPOW_MWATT)
610- {
611- dbm = iw_mwatt2dbm(wrq.u.txpower.value);
612- mwatt = wrq.u.txpower.value;
613- }
614- else
615- {
616- dbm = wrq.u.txpower.value;
617- mwatt = iw_dbm2mwatt(wrq.u.txpower.value);
618- }
619- printf("%d dBm \t(%d mW)\n\n", dbm, mwatt);
620- }
621- }
622- }
623- }
624- return(0);
625-}
626-
627-/*********************** RETRY LIMIT/LIFETIME ***********************/
628-
629-/*------------------------------------------------------------------*/
630-/*
631- * Print one retry value
632- */
633-static inline int
634-get_retry_value(int skfd,
635- char * ifname,
636- struct iwreq * pwrq,
637- int flags,
638- char * buffer,
639- int buflen)
640-{
641- /* Get Another retry value */
642- pwrq->u.retry.flags = flags;
643- if(iw_get_ext(skfd, ifname, SIOCGIWRETRY, pwrq) >= 0)
644- {
645- /* Let's check the value and its type */
646- if(pwrq->u.retry.flags & IW_RETRY_TYPE)
647- {
648- iw_print_retry_value(buffer, buflen,
649- pwrq->u.retry.value, pwrq->u.retry.flags);
650- printf("%s\n ", buffer);
651- }
652- }
653- return(pwrq->u.retry.flags);
654-}
655-
656-/*------------------------------------------------------------------*/
657-/*
658- * Print Retry info for each device
659- */
660-static int
661-print_retry_info(int skfd,
662- char * ifname,
663- char * args[], /* Command line args */
664- int count) /* Args count */
665-{
666- struct iwreq wrq;
667- struct iw_range range;
668- char buffer[128];
669-
670- /* Avoid "Unused parameter" warning */
671- args = args; count = count;
413+ int offset = 0;
672414
673- /* Extract range info */
674- if((iw_get_range_info(skfd, ifname, &range) < 0) ||
675- (range.we_version_compiled < 11))
676- fprintf(stderr, "%-8.16s no retry limit/lifetime information.\n\n",
677- ifname);
678- else
415+ /* Loop on each IE, each IE is minimum 2 bytes */
416+ while(offset <= (buflen - 2))
679417 {
680- printf("%-8.16s ", ifname);
681-
682- /* Display min/max limit availables */
683- if(range.retry_flags & IW_RETRY_LIMIT)
684- {
685- int flags = (range.retry_flags & ~(IW_RETRY_MIN | IW_RETRY_MAX));
686- /* Display if auto or fixed */
687- if(range.retry_flags & IW_RETRY_MIN)
688- printf("Auto limit ; ");
689- else
690- printf("Fixed limit ; ");
691- /* Print the range */
692- iw_print_retry_value(buffer, sizeof(buffer),
693- range.min_retry, flags | IW_RETRY_MIN);
694- printf("%s\n ", buffer);
695- iw_print_retry_value(buffer, sizeof(buffer),
696- range.max_retry, flags | IW_RETRY_MAX);
697- printf("%s\n ", buffer);
698-
699- }
700- /* Display min/max lifetime availables */
701- if(range.r_time_flags & IW_RETRY_LIFETIME)
702- {
703- int flags = (range.r_time_flags & ~(IW_RETRY_MIN | IW_RETRY_MAX));
704- /* Display if auto or fixed */
705- if(range.r_time_flags & IW_RETRY_MIN)
706- printf("Auto lifetime ; ");
707- else
708- printf("Fixed lifetime ; ");
709- /* Print the range */
710- iw_print_retry_value(buffer, sizeof(buffer),
711- range.min_r_time, flags | IW_RETRY_MIN);
712- printf("%s\n ", buffer);
713- iw_print_retry_value(buffer, sizeof(buffer),
714- range.max_r_time, flags | IW_RETRY_MAX);
715- printf("%s\n ", buffer);
716-
717- }
418+ printf(" IE: ");
718419
719- /* Get current retry settings */
720- wrq.u.retry.flags = 0;
721- if(iw_get_ext(skfd, ifname, SIOCGIWRETRY, &wrq) >= 0)
420+ /* Check IE type */
421+ switch(buffer[offset])
722422 {
723- int flags = wrq.u.retry.flags;
724-
725- /* Is it disabled ? */
726- if(wrq.u.retry.disabled)
727- printf("Current mode:off\n ");
728- else
729- {
730- int retry_mask = 0;
731-
732- /* Let's check the mode */
733- printf("Current mode:on\n ");
734-
735- /* Let's check the value and its type */
736- if(wrq.u.retry.flags & IW_RETRY_TYPE)
737- {
738- iw_print_retry_value(buffer, sizeof(buffer),
739- wrq.u.retry.value, wrq.u.retry.flags);
740- printf("%s\n ", buffer);
741- }
742-
743- /* If we have been returned a MIN value, ask for the MAX */
744- if(flags & IW_RETRY_MIN)
745- retry_mask = IW_RETRY_MAX;
746- /* If we have been returned a MAX value, ask for the MIN */
747- if(flags & IW_RETRY_MAX)
748- retry_mask = IW_RETRY_MIN;
749- /* If we have something to ask for... */
750- if(retry_mask)
751- get_retry_value(skfd, ifname, &wrq, retry_mask,
752- buffer, sizeof(buffer));
753-
754- /* And if we have both a period and a timeout, ask the other */
755- retry_mask = (range.retry_capa & (~(wrq.u.retry.flags) &
756- IW_RETRY_TYPE));
757- if(retry_mask)
758- {
759- int base_mask = retry_mask;
760- flags = get_retry_value(skfd, ifname, &wrq, retry_mask,
761- buffer, sizeof(buffer));
762- retry_mask = 0;
763-
764- /* If we have been returned a MIN value, ask for the MAX */
765- if(flags & IW_RETRY_MIN)
766- retry_mask = IW_RETRY_MAX | base_mask;
767- /* If we have been returned a MAX value, ask for the MIN */
768- if(flags & IW_RETRY_MAX)
769- retry_mask = IW_RETRY_MIN | base_mask;
770- /* If we have something to ask for... */
771- if(retry_mask)
772- get_retry_value(skfd, ifname, &wrq, retry_mask,
773- buffer, sizeof(buffer));
774- }
775- }
423+ case 0xdd: /* WPA1 (and other) */
424+ case 0x30: /* WPA2 */
425+ iw_print_ie_wpa(buffer + offset, buflen);
426+ break;
427+ default:
428+ iw_print_ie_unknown(buffer + offset, buflen);
776429 }
777- printf("\n");
430+ /* Skip over this IE to the next one in the list. */
431+ offset += buffer[offset+1] + 2;
778432 }
779- return(0);
780433 }
434+#endif /* WE_ESSENTIAL */
781435
782436 /***************************** SCANNING *****************************/
783437 /*
@@ -792,317 +446,53 @@ print_retry_info(int skfd,
792446
793447 /*------------------------------------------------------------------*/
794448 /*
795- * Parse, and display the results of a WPA or WPA2 IE.
796- *
449+ * Print one element from the scanning results
797450 */
798-static void
799-iw_print_ie_unknown(unsigned char * iebuf,
800- int buflen)
451+static inline void
452+print_scanning_token(struct stream_descr * stream, /* Stream of events */
453+ struct iw_event * event, /* Extracted token */
454+ struct iwscan_state * state,
455+ struct iw_range * iw_range, /* Range info */
456+ int has_range)
801457 {
802- int ielen = iebuf[1] + 2;
803- int i;
804-
805- if(ielen > buflen)
806- ielen = buflen;
807-
808- printf("Unknown: ");
809- for(i = 0; i < ielen; i++)
810- printf("%02X", iebuf[i]);
811- printf("\n");
812-}
458+ char buffer[128]; /* Temporary buffer */
813459
814-/*-----------------------------------------------------------------*/
815-/*
816- * Display the cipher type for the value passed in.
817- *
818- */
819-static inline void
820-iw_print_ie_cipher(unsigned char csuite)
821-{
822- switch (csuite)
460+ /* Now, let's decode the event */
461+ switch(event->cmd)
823462 {
824- case 0x00:
825- printf("None or same as Group ");
463+ case SIOCGIWAP:
464+ printf(" Cell %02d - Address: %s\n", state->ap_num,
465+ iw_saether_ntop(&event->u.ap_addr, buffer));
466+ state->ap_num++;
826467 break;
827-
828- case 0x01:
829- printf("WEP-40 ");
468+ case SIOCGIWNWID:
469+ if(event->u.nwid.disabled)
470+ printf(" NWID:off/any\n");
471+ else
472+ printf(" NWID:%X\n", event->u.nwid.value);
830473 break;
831-
832- case 0x02:
833- printf("TKIP ");
474+ case SIOCGIWFREQ:
475+ {
476+ double freq; /* Frequency/channel */
477+ int channel = -1; /* Converted to channel */
478+ freq = iw_freq2float(&(event->u.freq));
479+ /* Convert to channel if possible */
480+ if(has_range)
481+ channel = iw_freq_to_channel(freq, iw_range);
482+ iw_print_freq(buffer, sizeof(buffer),
483+ freq, channel, event->u.freq.flags);
484+ printf(" %s\n", buffer);
485+ }
834486 break;
835-
836- case 0x03:
837- printf("WRAP ");
487+ case SIOCGIWMODE:
488+ /* Note : event->u.mode is unsigned, no need to check <= 0 */
489+ if(event->u.mode >= IW_NUM_OPER_MODE)
490+ event->u.mode = IW_NUM_OPER_MODE;
491+ printf(" Mode:%s\n",
492+ iw_operation_mode[event->u.mode]);
838493 break;
839-
840- case 0x04:
841- printf("CCMP ");
842- break;
843-
844- case 0x05:
845- printf("WEP-104 ");
846- break;
847-
848- default:
849- printf("Unknown ");
850- break;
851- }
852- }
853-
854-/*------------------------------------------------------------------*/
855-/*
856- * Parse, and display the results of a WPA or WPA2 IE.
857- *
858- */
859-static inline void
860-iw_print_ie_wpa(unsigned char * iebuf,
861- int buflen)
862-{
863- int ielen = iebuf[1] + 2;
864- int offset = 2; /* Skip the IE id, and the length. */
865- unsigned char wpa1_oui[3] = {0x00, 0x50, 0xf2};
866- unsigned char wpa2_oui[3] = {0x00, 0x0f, 0xac};
867- unsigned char * wpa_oui;
868- int i;
869- uint16_t ver = 0;
870- uint16_t cnt = 0;
871-
872- if(ielen > buflen)
873- ielen = buflen;
874-
875- switch(iebuf[0])
876- {
877- case 0x30: /* WPA2 */
878- /* Check if we have enough data */
879- if(ielen < 4)
880- {
881- iw_print_ie_unknown(iebuf, buflen);
882- return;
883- }
884-
885- wpa_oui = wpa2_oui;
886- break;
887-
888- case 0xdd: /* WPA or else */
889- wpa_oui = wpa1_oui;
890-
891- /* Not all IEs that start with 0xdd are WPA.
892- * So check that the OUI is valid. */
893- if((ielen < 8)
894- || ((memcmp(&iebuf[offset], wpa_oui, 3) != 0)
895- && (iebuf[offset+3] == 0x01)))
896- {
897- iw_print_ie_unknown(iebuf, buflen);
898- return;
899- }
900-
901- offset += 4;
902- break;
903-
904- default:
905- return;
906- }
907-
908- /* Pick version number (little endian) */
909- ver = iebuf[offset] | (iebuf[offset + 1] << 8);
910- offset += 2;
911-
912- if(iebuf[0] == 0xdd)
913- printf("WPA Version %d\n", ver);
914- if(iebuf[0] == 0x30)
915- printf("IEEE 802.11i/WPA2 Version %d\n", ver);
916-
917- /* From here, everything is technically optional. */
918-
919- /* Check if we are done */
920- if(ielen < (offset + 4))
921- {
922- /* We have a short IE. So we should assume TKIP/TKIP. */
923- printf(" Group Cipher : TKIP\n");
924- printf(" Pairwise Cipher : TKIP\n");
925- return;
926- }
927-
928- /* Next we have our group cipher. */
929- if(memcmp(&iebuf[offset], wpa_oui, 3) != 0)
930- {
931- printf(" Group Cipher : Proprietary\n");
932- }
933- else
934- {
935- printf(" Group Cipher : ");
936- iw_print_ie_cipher(iebuf[offset+3]);
937- printf("\n");
938- }
939- offset += 4;
940-
941- /* Check if we are done */
942- if(ielen < (offset + 2))
943- {
944- /* We don't have a pairwise cipher, or auth method. Assume TKIP. */
945- printf(" Pairwise Ciphers (1) : TKIP\n");
946- return;
947- }
948-
949- /* Otherwise, we have some number of pairwise ciphers. */
950- cnt = iebuf[offset] | (iebuf[offset + 1] << 8);
951- offset += 2;
952- printf(" Pairwise Ciphers (%d) : ", cnt);
953-
954- if(ielen < (offset + 4*cnt))
955- return;
956-
957- for(i = 0; i < cnt; i++)
958- {
959- if(memcmp(&iebuf[offset], wpa_oui, 3) != 0)
960- {
961- printf("Proprietary ");
962- }
963- else
964- {
965- iw_print_ie_cipher(iebuf[offset+3]);
966- }
967- offset+=4;
968- }
969- printf("\n");
970-
971- /* Check if we are done */
972- if(ielen < (offset + 2))
973- return;
974-
975- /* Now, we have authentication suites. */
976- cnt = iebuf[offset] | (iebuf[offset + 1] << 8);
977- offset += 2;
978- printf(" Authentication Suites (%d) : ", cnt);
979-
980- if(ielen < (offset + 4*cnt))
981- return;
982-
983- for(i = 0; i < cnt; i++)
984- {
985- if(memcmp(&iebuf[offset], wpa_oui, 3) != 0)
986- {
987- printf("Proprietary ");
988- }
989- else
990- {
991- switch(iebuf[offset+3])
992- {
993- case 0x00:
994- printf("Reserved ");
995- break;
996-
997- case 0x01:
998- printf("802.1X ");
999- break;
1000-
1001- case 0x02:
1002- printf("PSK ");
1003- break;
1004-
1005- default:
1006- printf("Unknown ");
1007- break;
1008- }
1009- }
1010- offset+=4;
1011- }
1012- printf("\n");
1013-
1014- /* Check if we are done */
1015- if(ielen < (offset + 1))
1016- return;
1017-
1018- /* Otherwise, we have capabilities bytes.
1019- * For now, we only care about preauth which is in bit position 1 of the
1020- * first byte. (But, preauth with WPA version 1 isn't supposed to be
1021- * allowed.) 8-) */
1022- if(iebuf[offset] & 0x01)
1023- {
1024- printf(" Preauthentication Supported\n");
1025- }
1026-}
1027-
1028-/*------------------------------------------------------------------*/
1029-/*
1030- * Process a generic IE and display the info in human readable form
1031- * for some of the most interesting ones.
1032- * For now, we only decode the WPA IEs.
1033- */
1034-static inline void
1035-iw_print_gen_ie(unsigned char * buffer,
1036- int buflen)
1037-{
1038- int offset = 0;
1039-
1040- /* Loop on each IE, each IE is minimum 2 bytes */
1041- while(offset <= (buflen - 2))
1042- {
1043- printf(" IE: ");
1044-
1045- /* Check IE type */
1046- switch(buffer[offset])
1047- {
1048- case 0xdd: /* WPA1 (and other) */
1049- case 0x30: /* WPA2 */
1050- iw_print_ie_wpa(buffer + offset, buflen);
1051- break;
1052- default:
1053- iw_print_ie_unknown(buffer + offset, buflen);
1054- }
1055- /* Skip over this IE to the next one in the list. */
1056- offset += buffer[offset+1] + 2;
1057- }
1058-}
1059-
1060-/*------------------------------------------------------------------*/
1061-/*
1062- * Print one element from the scanning results
1063- */
1064-static inline void
1065-print_scanning_token(struct stream_descr * stream, /* Stream of events */
1066- struct iw_event * event, /* Extracted token */
1067- struct iwscan_state * state,
1068- struct iw_range * iw_range, /* Range info */
1069- int has_range)
1070-{
1071- char buffer[128]; /* Temporary buffer */
1072-
1073- /* Now, let's decode the event */
1074- switch(event->cmd)
1075- {
1076- case SIOCGIWAP:
1077- printf(" Cell %02d - Address: %s\n", state->ap_num,
1078- iw_saether_ntop(&event->u.ap_addr, buffer));
1079- state->ap_num++;
1080- break;
1081- case SIOCGIWNWID:
1082- if(event->u.nwid.disabled)
1083- printf(" NWID:off/any\n");
1084- else
1085- printf(" NWID:%X\n", event->u.nwid.value);
1086- break;
1087- case SIOCGIWFREQ:
1088- {
1089- double freq; /* Frequency/channel */
1090- int channel = -1; /* Converted to channel */
1091- freq = iw_freq2float(&(event->u.freq));
1092- /* Convert to channel if possible */
1093- if(has_range)
1094- channel = iw_freq_to_channel(freq, iw_range);
1095- iw_print_freq(buffer, sizeof(buffer),
1096- freq, channel, event->u.freq.flags);
1097- printf(" %s\n", buffer);
1098- }
1099- break;
1100- case SIOCGIWMODE:
1101- printf(" Mode:%s\n",
1102- iw_operation_mode[event->u.mode]);
1103- break;
1104- case SIOCGIWNAME:
1105- printf(" Protocol:%-1.16s\n", event->u.name);
494+ case SIOCGIWNAME:
495+ printf(" Protocol:%-1.16s\n", event->u.name);
1106496 break;
1107497 case SIOCGIWESSID:
1108498 {
@@ -1164,230 +554,1111 @@ print_scanning_token(struct stream_descr * stream, /* Stream of events */
1164554 /* Check for termination */
1165555 if(stream->value == NULL)
1166556 {
1167- printf("\n");
1168- state->val_index = 0;
557+ printf("\n");
558+ state->val_index = 0;
559+ }
560+ else
561+ state->val_index++;
562+ break;
563+ case SIOCGIWMODUL:
564+ {
565+ unsigned int modul = event->u.param.value;
566+ int i;
567+ int n = 0;
568+ printf(" Modulations :");
569+ for(i = 0; i < IW_SIZE_MODUL_LIST; i++)
570+ {
571+ if((modul & iw_modul_list[i].mask) == iw_modul_list[i].mask)
572+ {
573+ if((n++ % 8) == 7)
574+ printf("\n ");
575+ else
576+ printf(" ; ");
577+ printf("%s", iw_modul_list[i].cmd);
578+ }
579+ }
580+ printf("\n");
581+ }
582+ break;
583+ case IWEVQUAL:
584+ iw_print_stats(buffer, sizeof(buffer),
585+ &event->u.qual, iw_range, has_range);
586+ printf(" %s\n", buffer);
587+ break;
588+#ifndef WE_ESSENTIAL
589+ case IWEVGENIE:
590+ /* Informations Elements are complex, let's do only some of them */
591+ iw_print_gen_ie(event->u.data.pointer, event->u.data.length);
592+ break;
593+#endif /* WE_ESSENTIAL */
594+ case IWEVCUSTOM:
595+ {
596+ char custom[IW_CUSTOM_MAX+1];
597+ if((event->u.data.pointer) && (event->u.data.length))
598+ memcpy(custom, event->u.data.pointer, event->u.data.length);
599+ custom[event->u.data.length] = '\0';
600+ printf(" Extra:%s\n", custom);
601+ }
602+ break;
603+ default:
604+ printf(" (Unknown Wireless Token 0x%04X)\n",
605+ event->cmd);
606+ } /* switch(event->cmd) */
607+}
608+
609+/*------------------------------------------------------------------*/
610+/*
611+ * Perform a scanning on one device
612+ */
613+static int
614+print_scanning_info(int skfd,
615+ char * ifname,
616+ char * args[], /* Command line args */
617+ int count) /* Args count */
618+{
619+ struct iwreq wrq;
620+ struct iw_scan_req scanopt; /* Options for 'set' */
621+ int scanflags = 0; /* Flags for scan */
622+ unsigned char * buffer = NULL; /* Results */
623+ int buflen = IW_SCAN_MAX_DATA; /* Min for compat WE<17 */
624+ struct iw_range range;
625+ int has_range;
626+ struct timeval tv; /* Select timeout */
627+ int timeout = 15000000; /* 15s */
628+
629+ /* Avoid "Unused parameter" warning */
630+ args = args; count = count;
631+
632+ /* Debugging stuff */
633+ if((IW_EV_LCP_PK2_LEN != IW_EV_LCP_PK_LEN) || (IW_EV_POINT_PK2_LEN != IW_EV_POINT_PK_LEN))
634+ {
635+ fprintf(stderr, "*** Please report to jt@hpl.hp.com your platform details\n");
636+ fprintf(stderr, "*** and the following line :\n");
637+ fprintf(stderr, "*** IW_EV_LCP_PK2_LEN = %zu ; IW_EV_POINT_PK2_LEN = %zu\n\n",
638+ IW_EV_LCP_PK2_LEN, IW_EV_POINT_PK2_LEN);
639+ }
640+
641+ /* Get range stuff */
642+ has_range = (iw_get_range_info(skfd, ifname, &range) >= 0);
643+
644+ /* Check if the interface could support scanning. */
645+ if((!has_range) || (range.we_version_compiled < 14))
646+ {
647+ fprintf(stderr, "%-8.16s Interface doesn't support scanning.\n\n",
648+ ifname);
649+ return(-1);
650+ }
651+
652+ /* Init timeout value -> 250ms between set and first get */
653+ tv.tv_sec = 0;
654+ tv.tv_usec = 250000;
655+
656+ /* Clean up set args */
657+ memset(&scanopt, 0, sizeof(scanopt));
658+
659+ /* Parse command line arguments and extract options.
660+ * Note : when we have enough options, we should use the parser
661+ * from iwconfig... */
662+ while(count > 0)
663+ {
664+ /* One arg is consumed (the option name) */
665+ count--;
666+
667+ /*
668+ * Check for Active Scan (scan with specific essid)
669+ */
670+ if(!strncmp(args[0], "essid", 5))
671+ {
672+ if(count < 1)
673+ {
674+ fprintf(stderr, "Too few arguments for scanning option [%s]\n",
675+ args[0]);
676+ return(-1);
677+ }
678+ args++;
679+ count--;
680+
681+ /* Store the ESSID in the scan options */
682+ scanopt.essid_len = strlen(args[0]);
683+ memcpy(scanopt.essid, args[0], scanopt.essid_len);
684+ /* Initialise BSSID as needed */
685+ if(scanopt.bssid.sa_family == 0)
686+ {
687+ scanopt.bssid.sa_family = ARPHRD_ETHER;
688+ memset(scanopt.bssid.sa_data, 0xff, ETH_ALEN);
689+ }
690+ /* Scan only this ESSID */
691+ scanflags |= IW_SCAN_THIS_ESSID;
692+ }
693+ else
694+ /* Check for last scan result (do not trigger scan) */
695+ if(!strncmp(args[0], "last", 4))
696+ {
697+ /* Hack */
698+ scanflags |= IW_SCAN_HACK;
699+ }
700+ else
701+ {
702+ fprintf(stderr, "Invalid scanning option [%s]\n", args[0]);
703+ return(-1);
704+ }
705+
706+ /* Next arg */
707+ args++;
708+ }
709+
710+ /* Check if we have scan options */
711+ if(scanflags)
712+ {
713+ wrq.u.data.pointer = (caddr_t) &scanopt;
714+ wrq.u.data.length = sizeof(scanopt);
715+ wrq.u.data.flags = scanflags;
716+ }
717+ else
718+ {
719+ wrq.u.data.pointer = NULL;
720+ wrq.u.data.flags = 0;
721+ wrq.u.data.length = 0;
722+ }
723+
724+ /* If only 'last' was specified on command line, don't trigger a scan */
725+ if(scanflags == IW_SCAN_HACK)
726+ {
727+ /* Skip waiting */
728+ tv.tv_usec = 0;
729+ }
730+ else
731+ {
732+ /* Initiate Scanning */
733+ if(iw_set_ext(skfd, ifname, SIOCSIWSCAN, &wrq) < 0)
734+ {
735+ if((errno != EPERM) || (scanflags != 0))
736+ {
737+ fprintf(stderr, "%-8.16s Interface doesn't support scanning : %s\n\n",
738+ ifname, strerror(errno));
739+ return(-1);
740+ }
741+ /* If we don't have the permission to initiate the scan, we may
742+ * still have permission to read left-over results.
743+ * But, don't wait !!! */
744+#if 0
745+ /* Not cool, it display for non wireless interfaces... */
746+ fprintf(stderr, "%-8.16s (Could not trigger scanning, just reading left-over results)\n", ifname);
747+#endif
748+ tv.tv_usec = 0;
749+ }
750+ }
751+ timeout -= tv.tv_usec;
752+
753+ /* Forever */
754+ while(1)
755+ {
756+ fd_set rfds; /* File descriptors for select */
757+ int last_fd; /* Last fd */
758+ int ret;
759+
760+ /* Guess what ? We must re-generate rfds each time */
761+ FD_ZERO(&rfds);
762+ last_fd = -1;
763+
764+ /* In here, add the rtnetlink fd in the list */
765+
766+ /* Wait until something happens */
767+ ret = select(last_fd + 1, &rfds, NULL, NULL, &tv);
768+
769+ /* Check if there was an error */
770+ if(ret < 0)
771+ {
772+ if(errno == EAGAIN || errno == EINTR)
773+ continue;
774+ fprintf(stderr, "Unhandled signal - exiting...\n");
775+ return(-1);
776+ }
777+
778+ /* Check if there was a timeout */
779+ if(ret == 0)
780+ {
781+ unsigned char * newbuf;
782+
783+ realloc:
784+ /* (Re)allocate the buffer - realloc(NULL, len) == malloc(len) */
785+ newbuf = realloc(buffer, buflen);
786+ if(newbuf == NULL)
787+ {
788+ if(buffer)
789+ free(buffer);
790+ fprintf(stderr, "%s: Allocation failed\n", __FUNCTION__);
791+ return(-1);
792+ }
793+ buffer = newbuf;
794+
795+ /* Try to read the results */
796+ wrq.u.data.pointer = buffer;
797+ wrq.u.data.flags = 0;
798+ wrq.u.data.length = buflen;
799+ if(iw_get_ext(skfd, ifname, SIOCGIWSCAN, &wrq) < 0)
800+ {
801+ /* Check if buffer was too small (WE-17 only) */
802+ if((errno == E2BIG) && (range.we_version_compiled > 16))
803+ {
804+ /* Some driver may return very large scan results, either
805+ * because there are many cells, or because they have many
806+ * large elements in cells (like IWEVCUSTOM). Most will
807+ * only need the regular sized buffer. We now use a dynamic
808+ * allocation of the buffer to satisfy everybody. Of course,
809+ * as we don't know in advance the size of the array, we try
810+ * various increasing sizes. Jean II */
811+
812+ /* Check if the driver gave us any hints. */
813+ if(wrq.u.data.length > buflen)
814+ buflen = wrq.u.data.length;
815+ else
816+ buflen *= 2;
817+
818+ /* Try again */
819+ goto realloc;
820+ }
821+
822+ /* Check if results not available yet */
823+ if(errno == EAGAIN)
824+ {
825+ /* Restart timer for only 100ms*/
826+ tv.tv_sec = 0;
827+ tv.tv_usec = 100000;
828+ timeout -= tv.tv_usec;
829+ if(timeout > 0)
830+ continue; /* Try again later */
831+ }
832+
833+ /* Bad error */
834+ free(buffer);
835+ fprintf(stderr, "%-8.16s Failed to read scan data : %s\n\n",
836+ ifname, strerror(errno));
837+ return(-2);
838+ }
839+ else
840+ /* We have the results, go to process them */
841+ break;
842+ }
843+
844+ /* In here, check if event and event type
845+ * if scan event, read results. All errors bad & no reset timeout */
846+ }
847+
848+ if(wrq.u.data.length)
849+ {
850+ struct iw_event iwe;
851+ struct stream_descr stream;
852+ struct iwscan_state state = { .ap_num = 1, .val_index = 0 };
853+ int ret;
854+
855+#ifdef DEBUG
856+ /* Debugging code. In theory useless, because it's debugged ;-) */
857+ int i;
858+ printf("Scan result %d [%02X", wrq.u.data.length, buffer[0]);
859+ for(i = 1; i < wrq.u.data.length; i++)
860+ printf(":%02X", buffer[i]);
861+ printf("]\n");
862+#endif
863+ printf("%-8.16s Scan completed :\n", ifname);
864+ iw_init_event_stream(&stream, (char *) buffer, wrq.u.data.length);
865+ do
866+ {
867+ /* Extract an event and print it */
868+ ret = iw_extract_event_stream(&stream, &iwe,
869+ range.we_version_compiled);
870+ if(ret > 0)
871+ print_scanning_token(&stream, &iwe, &state,
872+ &range, has_range);
873+ }
874+ while(ret > 0);
875+ printf("\n");
876+ }
877+ else
878+ printf("%-8.16s No scan results\n\n", ifname);
879+
880+ free(buffer);
881+ return(0);
882+}
883+
884+/*********************** FREQUENCIES/CHANNELS ***********************/
885+
886+/*------------------------------------------------------------------*/
887+/*
888+ * Print the number of channels and available frequency for the device
889+ */
890+static int
891+print_freq_info(int skfd,
892+ char * ifname,
893+ char * args[], /* Command line args */
894+ int count) /* Args count */
895+{
896+ struct iwreq wrq;
897+ struct iw_range range;
898+ double freq;
899+ int k;
900+ int channel;
901+ char buffer[128]; /* Temporary buffer */
902+
903+ /* Avoid "Unused parameter" warning */
904+ args = args; count = count;
905+
906+ /* Get list of frequencies / channels */
907+ if(iw_get_range_info(skfd, ifname, &range) < 0)
908+ fprintf(stderr, "%-8.16s no frequency information.\n\n",
909+ ifname);
910+ else
911+ {
912+ if(range.num_frequency > 0)
913+ {
914+ printf("%-8.16s %d channels in total; available frequencies :\n",
915+ ifname, range.num_channels);
916+ /* Print them all */
917+ for(k = 0; k < range.num_frequency; k++)
918+ {
919+ freq = iw_freq2float(&(range.freq[k]));
920+ iw_print_freq_value(buffer, sizeof(buffer), freq);
921+ printf(" Channel %.2d : %s\n",
922+ range.freq[k].i, buffer);
923+ }
924+ }
925+ else
926+ printf("%-8.16s %d channels\n",
927+ ifname, range.num_channels);
928+
929+ /* Get current frequency / channel and display it */
930+ if(iw_get_ext(skfd, ifname, SIOCGIWFREQ, &wrq) >= 0)
931+ {
932+ freq = iw_freq2float(&(wrq.u.freq));
933+ channel = iw_freq_to_channel(freq, &range);
934+ iw_print_freq(buffer, sizeof(buffer),
935+ freq, channel, wrq.u.freq.flags);
936+ printf(" Current %s\n\n", buffer);
937+ }
938+ }
939+ return(0);
940+}
941+
942+/***************************** BITRATES *****************************/
943+
944+/*------------------------------------------------------------------*/
945+/*
946+ * Print the number of available bitrates for the device
947+ */
948+static int
949+print_bitrate_info(int skfd,
950+ char * ifname,
951+ char * args[], /* Command line args */
952+ int count) /* Args count */
953+{
954+ struct iwreq wrq;
955+ struct iw_range range;
956+ int k;
957+ char buffer[128];
958+
959+ /* Avoid "Unused parameter" warning */
960+ args = args; count = count;
961+
962+ /* Extract range info */
963+ if(iw_get_range_info(skfd, ifname, &range) < 0)
964+ fprintf(stderr, "%-8.16s no bit-rate information.\n\n",
965+ ifname);
966+ else
967+ {
968+ if((range.num_bitrates > 0) && (range.num_bitrates <= IW_MAX_BITRATES))
969+ {
970+ printf("%-8.16s %d available bit-rates :\n",
971+ ifname, range.num_bitrates);
972+ /* Print them all */
973+ for(k = 0; k < range.num_bitrates; k++)
974+ {
975+ iw_print_bitrate(buffer, sizeof(buffer), range.bitrate[k]);
976+ /* Maybe this should be %10s */
977+ printf("\t %s\n", buffer);
978+ }
979+ }
980+ else
981+ printf("%-8.16s unknown bit-rate information.\n", ifname);
982+
983+ /* Get current bit rate */
984+ if(iw_get_ext(skfd, ifname, SIOCGIWRATE, &wrq) >= 0)
985+ {
986+ iw_print_bitrate(buffer, sizeof(buffer), wrq.u.bitrate.value);
987+ printf(" Current Bit Rate%c%s\n",
988+ (wrq.u.bitrate.fixed ? '=' : ':'), buffer);
989+ }
990+
991+ /* Try to get the broadcast bitrate if it exist... */
992+ if(range.bitrate_capa & IW_BITRATE_BROADCAST)
993+ {
994+ wrq.u.bitrate.flags = IW_BITRATE_BROADCAST;
995+ if(iw_get_ext(skfd, ifname, SIOCGIWRATE, &wrq) >= 0)
996+ {
997+ iw_print_bitrate(buffer, sizeof(buffer), wrq.u.bitrate.value);
998+ printf(" Broadcast Bit Rate%c%s\n",
999+ (wrq.u.bitrate.fixed ? '=' : ':'), buffer);
1000+ }
1001+ }
1002+
1003+ printf("\n");
1004+ }
1005+ return(0);
1006+}
1007+
1008+/************************* ENCRYPTION KEYS *************************/
1009+
1010+/*------------------------------------------------------------------*/
1011+/*
1012+ * Print all the available encryption keys for the device
1013+ */
1014+static int
1015+print_keys_info(int skfd,
1016+ char * ifname,
1017+ char * args[], /* Command line args */
1018+ int count) /* Args count */
1019+{
1020+ struct iwreq wrq;
1021+ struct iw_range range;
1022+ unsigned char key[IW_ENCODING_TOKEN_MAX];
1023+ unsigned int k;
1024+ char buffer[128];
1025+
1026+ /* Avoid "Unused parameter" warning */
1027+ args = args; count = count;
1028+
1029+ /* Extract range info */
1030+ if(iw_get_range_info(skfd, ifname, &range) < 0)
1031+ fprintf(stderr, "%-8.16s no encryption keys information.\n\n",
1032+ ifname);
1033+ else
1034+ {
1035+ printf("%-8.16s ", ifname);
1036+ /* Print key sizes */
1037+ if((range.num_encoding_sizes > 0) &&
1038+ (range.num_encoding_sizes < IW_MAX_ENCODING_SIZES))
1039+ {
1040+ printf("%d key sizes : %d", range.num_encoding_sizes,
1041+ range.encoding_size[0] * 8);
1042+ /* Print them all */
1043+ for(k = 1; k < range.num_encoding_sizes; k++)
1044+ printf(", %d", range.encoding_size[k] * 8);
1045+ printf("bits\n ");
1046+ }
1047+ /* Print the keys and associate mode */
1048+ printf("%d keys available :\n", range.max_encoding_tokens);
1049+ for(k = 1; k <= range.max_encoding_tokens; k++)
1050+ {
1051+ wrq.u.data.pointer = (caddr_t) key;
1052+ wrq.u.data.length = IW_ENCODING_TOKEN_MAX;
1053+ wrq.u.data.flags = k;
1054+ if(iw_get_ext(skfd, ifname, SIOCGIWENCODE, &wrq) < 0)
1055+ {
1056+ fprintf(stderr, "Error reading wireless keys (SIOCGIWENCODE): %s\n", strerror(errno));
1057+ break;
1058+ }
1059+ if((wrq.u.data.flags & IW_ENCODE_DISABLED) ||
1060+ (wrq.u.data.length == 0))
1061+ printf("\t\t[%d]: off\n", k);
1062+ else
1063+ {
1064+ /* Display the key */
1065+ iw_print_key(buffer, sizeof(buffer),
1066+ key, wrq.u.data.length, wrq.u.data.flags);
1067+ printf("\t\t[%d]: %s", k, buffer);
1068+
1069+ /* Other info... */
1070+ printf(" (%d bits)", wrq.u.data.length * 8);
1071+ printf("\n");
1072+ }
1073+ }
1074+ /* Print current key index and mode */
1075+ wrq.u.data.pointer = (caddr_t) key;
1076+ wrq.u.data.length = IW_ENCODING_TOKEN_MAX;
1077+ wrq.u.data.flags = 0; /* Set index to zero to get current */
1078+ if(iw_get_ext(skfd, ifname, SIOCGIWENCODE, &wrq) >= 0)
1079+ {
1080+ /* Note : if above fails, we have already printed an error
1081+ * message int the loop above */
1082+ printf(" Current Transmit Key: [%d]\n",
1083+ wrq.u.data.flags & IW_ENCODE_INDEX);
1084+ if(wrq.u.data.flags & IW_ENCODE_RESTRICTED)
1085+ printf(" Security mode:restricted\n");
1086+ if(wrq.u.data.flags & IW_ENCODE_OPEN)
1087+ printf(" Security mode:open\n");
1088+ }
1089+
1090+ printf("\n\n");
1091+ }
1092+ return(0);
1093+}
1094+
1095+/************************* POWER MANAGEMENT *************************/
1096+
1097+/*------------------------------------------------------------------*/
1098+/*
1099+ * Print Power Management info for each device
1100+ */
1101+static int
1102+get_pm_value(int skfd,
1103+ char * ifname,
1104+ struct iwreq * pwrq,
1105+ int flags,
1106+ char * buffer,
1107+ int buflen,
1108+ int we_version_compiled)
1109+{
1110+ /* Get Another Power Management value */
1111+ pwrq->u.power.flags = flags;
1112+ if(iw_get_ext(skfd, ifname, SIOCGIWPOWER, pwrq) >= 0)
1113+ {
1114+ /* Let's check the value and its type */
1115+ if(pwrq->u.power.flags & IW_POWER_TYPE)
1116+ {
1117+ iw_print_pm_value(buffer, buflen,
1118+ pwrq->u.power.value, pwrq->u.power.flags,
1119+ we_version_compiled);
1120+ printf("\n %s", buffer);
1121+ }
1122+ }
1123+ return(pwrq->u.power.flags);
1124+}
1125+
1126+/*------------------------------------------------------------------*/
1127+/*
1128+ * Print Power Management range for each type
1129+ */
1130+static void
1131+print_pm_value_range(char * name,
1132+ int mask,
1133+ int iwr_flags,
1134+ int iwr_min,
1135+ int iwr_max,
1136+ char * buffer,
1137+ int buflen,
1138+ int we_version_compiled)
1139+{
1140+ if(iwr_flags & mask)
1141+ {
1142+ int flags = (iwr_flags & ~(IW_POWER_MIN | IW_POWER_MAX));
1143+ /* Display if auto or fixed */
1144+ printf("%s %s ; ",
1145+ (iwr_flags & IW_POWER_MIN) ? "Auto " : "Fixed",
1146+ name);
1147+ /* Print the range */
1148+ iw_print_pm_value(buffer, buflen,
1149+ iwr_min, flags | IW_POWER_MIN,
1150+ we_version_compiled);
1151+ printf("%s\n ", buffer);
1152+ iw_print_pm_value(buffer, buflen,
1153+ iwr_max, flags | IW_POWER_MAX,
1154+ we_version_compiled);
1155+ printf("%s\n ", buffer);
1156+ }
1157+}
1158+
1159+/*------------------------------------------------------------------*/
1160+/*
1161+ * Power Management types of values
1162+ */
1163+static const unsigned int pm_type_flags[] = {
1164+ IW_POWER_PERIOD,
1165+ IW_POWER_TIMEOUT,
1166+ IW_POWER_SAVING,
1167+};
1168+static const int pm_type_flags_size = (sizeof(pm_type_flags)/sizeof(pm_type_flags[0]));
1169+
1170+/*------------------------------------------------------------------*/
1171+/*
1172+ * Print Power Management info for each device
1173+ */
1174+static int
1175+print_pm_info(int skfd,
1176+ char * ifname,
1177+ char * args[], /* Command line args */
1178+ int count) /* Args count */
1179+{
1180+ struct iwreq wrq;
1181+ struct iw_range range;
1182+ char buffer[128];
1183+
1184+ /* Avoid "Unused parameter" warning */
1185+ args = args; count = count;
1186+
1187+ /* Extract range info */
1188+ if((iw_get_range_info(skfd, ifname, &range) < 0) ||
1189+ (range.we_version_compiled < 10))
1190+ fprintf(stderr, "%-8.16s no power management information.\n\n",
1191+ ifname);
1192+ else
1193+ {
1194+ printf("%-8.16s ", ifname);
1195+
1196+ /* Display modes availables */
1197+ if(range.pm_capa & IW_POWER_MODE)
1198+ {
1199+ printf("Supported modes :\n ");
1200+ if(range.pm_capa & (IW_POWER_UNICAST_R | IW_POWER_MULTICAST_R))
1201+ printf("\t\to Receive all packets (unicast & multicast)\n ");
1202+ if(range.pm_capa & IW_POWER_UNICAST_R)
1203+ printf("\t\to Receive Unicast only (discard multicast)\n ");
1204+ if(range.pm_capa & IW_POWER_MULTICAST_R)
1205+ printf("\t\to Receive Multicast only (discard unicast)\n ");
1206+ if(range.pm_capa & IW_POWER_FORCE_S)
1207+ printf("\t\to Force sending using Power Management\n ");
1208+ if(range.pm_capa & IW_POWER_REPEATER)
1209+ printf("\t\to Repeat multicast\n ");
1210+ }
1211+ /* Display min/max period availables */
1212+ print_pm_value_range("period ", IW_POWER_PERIOD,
1213+ range.pmp_flags, range.min_pmp, range.max_pmp,
1214+ buffer, sizeof(buffer), range.we_version_compiled);
1215+ /* Display min/max timeout availables */
1216+ print_pm_value_range("timeout", IW_POWER_TIMEOUT,
1217+ range.pmt_flags, range.min_pmt, range.max_pmt,
1218+ buffer, sizeof(buffer), range.we_version_compiled);
1219+ /* Display min/max saving availables */
1220+ print_pm_value_range("saving ", IW_POWER_SAVING,
1221+ range.pms_flags, range.min_pms, range.max_pms,
1222+ buffer, sizeof(buffer), range.we_version_compiled);
1223+
1224+ /* Get current Power Management settings */
1225+ wrq.u.power.flags = 0;
1226+ if(iw_get_ext(skfd, ifname, SIOCGIWPOWER, &wrq) >= 0)
1227+ {
1228+ int flags = wrq.u.power.flags;
1229+
1230+ /* Is it disabled ? */
1231+ if(wrq.u.power.disabled)
1232+ printf("Current mode:off\n");
1233+ else
1234+ {
1235+ unsigned int pm_type = 0;
1236+ unsigned int pm_mask = 0;
1237+ unsigned int remain_mask = range.pm_capa & IW_POWER_TYPE;
1238+ int i = 0;
1239+
1240+ /* Let's check the mode */
1241+ iw_print_pm_mode(buffer, sizeof(buffer), flags);
1242+ printf("Current %s", buffer);
1243+
1244+ /* Let's check if nothing (simply on) */
1245+ if((flags & IW_POWER_MODE) == IW_POWER_ON)
1246+ printf("mode:on");
1247+
1248+ /* Let's check the value and its type */
1249+ if(wrq.u.power.flags & IW_POWER_TYPE)
1250+ {
1251+ iw_print_pm_value(buffer, sizeof(buffer),
1252+ wrq.u.power.value, wrq.u.power.flags,
1253+ range.we_version_compiled);
1254+ printf("\n %s", buffer);
1255+ }
1256+
1257+ while(1)
1258+ {
1259+ /* Deal with min/max for the current value */
1260+ pm_mask = 0;
1261+ /* If we have been returned a MIN value, ask for the MAX */
1262+ if(flags & IW_POWER_MIN)
1263+ pm_mask = IW_POWER_MAX;
1264+ /* If we have been returned a MAX value, ask for the MIN */
1265+ if(flags & IW_POWER_MAX)
1266+ pm_mask = IW_POWER_MIN;
1267+ /* If we have something to ask for... */
1268+ if(pm_mask)
1269+ {
1270+ pm_mask |= pm_type;
1271+ get_pm_value(skfd, ifname, &wrq, pm_mask,
1272+ buffer, sizeof(buffer),
1273+ range.we_version_compiled);
1274+ }
1275+
1276+ /* Remove current type from mask */
1277+ remain_mask &= ~(wrq.u.power.flags);
1278+
1279+ /* Check what other types we still have to read */
1280+ while(i < pm_type_flags_size)
1281+ {
1282+ pm_type = remain_mask & pm_type_flags[i];
1283+ if(pm_type)
1284+ break;
1285+ i++;
1286+ }
1287+ /* Nothing anymore : exit the loop */
1288+ if(!pm_type)
1289+ break;
1290+
1291+ /* Ask for this other type of value */
1292+ flags = get_pm_value(skfd, ifname, &wrq, pm_type,
1293+ buffer, sizeof(buffer),
1294+ range.we_version_compiled);
1295+ /* Loop back for min/max */
1296+ }
1297+ printf("\n");
1298+ }
1299+ }
1300+ printf("\n");
1301+ }
1302+ return(0);
1303+}
1304+
1305+#ifndef WE_ESSENTIAL
1306+/************************** TRANSMIT POWER **************************/
1307+
1308+/*------------------------------------------------------------------*/
1309+/*
1310+ * Print the number of available transmit powers for the device
1311+ */
1312+static int
1313+print_txpower_info(int skfd,
1314+ char * ifname,
1315+ char * args[], /* Command line args */
1316+ int count) /* Args count */
1317+{
1318+ struct iwreq wrq;
1319+ struct iw_range range;
1320+ int dbm;
1321+ int mwatt;
1322+ int k;
1323+
1324+ /* Avoid "Unused parameter" warning */
1325+ args = args; count = count;
1326+
1327+ /* Extract range info */
1328+ if((iw_get_range_info(skfd, ifname, &range) < 0) ||
1329+ (range.we_version_compiled < 10))
1330+ fprintf(stderr, "%-8.16s no transmit-power information.\n\n",
1331+ ifname);
1332+ else
1333+ {
1334+ if((range.num_txpower <= 0) || (range.num_txpower > IW_MAX_TXPOWER))
1335+ printf("%-8.16s unknown transmit-power information.\n\n", ifname);
1336+ else
1337+ {
1338+ printf("%-8.16s %d available transmit-powers :\n",
1339+ ifname, range.num_txpower);
1340+ /* Print them all */
1341+ for(k = 0; k < range.num_txpower; k++)
1342+ {
1343+ /* Check for relative values */
1344+ if(range.txpower_capa & IW_TXPOW_RELATIVE)
1345+ {
1346+ printf("\t %d (no units)\n", range.txpower[k]);
1347+ }
1348+ else
1349+ {
1350+ if(range.txpower_capa & IW_TXPOW_MWATT)
1351+ {
1352+ dbm = iw_mwatt2dbm(range.txpower[k]);
1353+ mwatt = range.txpower[k];
1354+ }
1355+ else
1356+ {
1357+ dbm = range.txpower[k];
1358+ mwatt = iw_dbm2mwatt(range.txpower[k]);
1359+ }
1360+ printf("\t %d dBm \t(%d mW)\n", dbm, mwatt);
1361+ }
1362+ }
1363+ }
1364+
1365+ /* Get current Transmit Power */
1366+ if(iw_get_ext(skfd, ifname, SIOCGIWTXPOW, &wrq) >= 0)
1367+ {
1368+ printf(" Current Tx-Power");
1369+ /* Disabled ? */
1370+ if(wrq.u.txpower.disabled)
1371+ printf(":off\n\n");
1372+ else
1373+ {
1374+ /* Fixed ? */
1375+ if(wrq.u.txpower.fixed)
1376+ printf("=");
1377+ else
1378+ printf(":");
1379+ /* Check for relative values */
1380+ if(wrq.u.txpower.flags & IW_TXPOW_RELATIVE)
1381+ {
1382+ /* I just hate relative value, because they are
1383+ * driver specific, so not very meaningfull to apps.
1384+ * But, we have to support that, because
1385+ * this is the way hardware is... */
1386+ printf("\t %d (no units)\n", wrq.u.txpower.value);
1387+ }
1388+ else
1389+ {
1390+ if(wrq.u.txpower.flags & IW_TXPOW_MWATT)
1391+ {
1392+ dbm = iw_mwatt2dbm(wrq.u.txpower.value);
1393+ mwatt = wrq.u.txpower.value;
1394+ }
1395+ else
1396+ {
1397+ dbm = wrq.u.txpower.value;
1398+ mwatt = iw_dbm2mwatt(wrq.u.txpower.value);
1399+ }
1400+ printf("%d dBm \t(%d mW)\n\n", dbm, mwatt);
1401+ }
1402+ }
1403+ }
1404+ }
1405+ return(0);
1406+}
1407+
1408+/*********************** RETRY LIMIT/LIFETIME ***********************/
1409+
1410+/*------------------------------------------------------------------*/
1411+/*
1412+ * Print one retry value
1413+ */
1414+static int
1415+get_retry_value(int skfd,
1416+ char * ifname,
1417+ struct iwreq * pwrq,
1418+ int flags,
1419+ char * buffer,
1420+ int buflen,
1421+ int we_version_compiled)
1422+{
1423+ /* Get Another retry value */
1424+ pwrq->u.retry.flags = flags;
1425+ if(iw_get_ext(skfd, ifname, SIOCGIWRETRY, pwrq) >= 0)
1426+ {
1427+ /* Let's check the value and its type */
1428+ if(pwrq->u.retry.flags & IW_RETRY_TYPE)
1429+ {
1430+ iw_print_retry_value(buffer, buflen,
1431+ pwrq->u.retry.value, pwrq->u.retry.flags,
1432+ we_version_compiled);
1433+ printf("%s\n ", buffer);
11691434 }
1170- else
1171- state->val_index++;
1172- break;
1173- case IWEVQUAL:
1174- {
1175- iw_print_stats(buffer, sizeof(buffer),
1176- &event->u.qual, iw_range, has_range);
1177- printf(" %s\n", buffer);
1178- break;
1179- }
1180- case IWEVGENIE:
1181- /* Informations Elements are complex, let's do only some of them */
1182- iw_print_gen_ie(event->u.data.pointer, event->u.data.length);
1183- break;
1184- case IWEVCUSTOM:
1185- {
1186- char custom[IW_CUSTOM_MAX+1];
1187- if((event->u.data.pointer) && (event->u.data.length))
1188- memcpy(custom, event->u.data.pointer, event->u.data.length);
1189- custom[event->u.data.length] = '\0';
1190- printf(" Extra:%s\n", custom);
1191- }
1192- break;
1193- default:
1194- printf(" (Unknown Wireless Token 0x%04X)\n",
1195- event->cmd);
1196- } /* switch(event->cmd) */
1435+ }
1436+ return(pwrq->u.retry.flags);
11971437 }
11981438
11991439 /*------------------------------------------------------------------*/
12001440 /*
1201- * Perform a scanning on one device
1441+ * Print Power Management range for each type
1442+ */
1443+static void
1444+print_retry_value_range(char * name,
1445+ int mask,
1446+ int iwr_flags,
1447+ int iwr_min,
1448+ int iwr_max,
1449+ char * buffer,
1450+ int buflen,
1451+ int we_version_compiled)
1452+{
1453+ if(iwr_flags & mask)
1454+ {
1455+ int flags = (iwr_flags & ~(IW_RETRY_MIN | IW_RETRY_MAX));
1456+ /* Display if auto or fixed */
1457+ printf("%s %s ; ",
1458+ (iwr_flags & IW_POWER_MIN) ? "Auto " : "Fixed",
1459+ name);
1460+ /* Print the range */
1461+ iw_print_retry_value(buffer, buflen,
1462+ iwr_min, flags | IW_POWER_MIN,
1463+ we_version_compiled);
1464+ printf("%s\n ", buffer);
1465+ iw_print_retry_value(buffer, buflen,
1466+ iwr_max, flags | IW_POWER_MAX,
1467+ we_version_compiled);
1468+ printf("%s\n ", buffer);
1469+ }
1470+}
1471+
1472+/*------------------------------------------------------------------*/
1473+/*
1474+ * Print Retry info for each device
12021475 */
12031476 static int
1204-print_scanning_info(int skfd,
1205- char * ifname,
1206- char * args[], /* Command line args */
1207- int count) /* Args count */
1477+print_retry_info(int skfd,
1478+ char * ifname,
1479+ char * args[], /* Command line args */
1480+ int count) /* Args count */
12081481 {
12091482 struct iwreq wrq;
1210- unsigned char * buffer = NULL; /* Results */
1211- int buflen = IW_SCAN_MAX_DATA; /* Min for compat WE<17 */
12121483 struct iw_range range;
1213- int has_range;
1214- struct timeval tv; /* Select timeout */
1215- int timeout = 15000000; /* 15s */
1484+ char buffer[128];
12161485
12171486 /* Avoid "Unused parameter" warning */
12181487 args = args; count = count;
12191488
1220- /* Get range stuff */
1221- has_range = (iw_get_range_info(skfd, ifname, &range) >= 0);
1222-
1223- /* Check if the interface could support scanning. */
1224- if((!has_range) || (range.we_version_compiled < 14))
1489+ /* Extract range info */
1490+ if((iw_get_range_info(skfd, ifname, &range) < 0) ||
1491+ (range.we_version_compiled < 11))
1492+ fprintf(stderr, "%-8.16s no retry limit/lifetime information.\n\n",
1493+ ifname);
1494+ else
12251495 {
1226- fprintf(stderr, "%-8.16s Interface doesn't support scanning.\n\n",
1227- ifname);
1228- return(-1);
1229- }
1230-
1231- /* Init timeout value -> 250ms*/
1232- tv.tv_sec = 0;
1233- tv.tv_usec = 250000;
1496+ printf("%-8.16s ", ifname);
12341497
1235- /*
1236- * Here we should look at the command line args and set the IW_SCAN_ flags
1237- * properly
1238- */
1239- wrq.u.data.pointer = NULL; /* Later */
1240- wrq.u.data.flags = 0;
1241- wrq.u.data.length = 0;
1498+ /* Display min/max limit availables */
1499+ print_retry_value_range("limit ", IW_RETRY_LIMIT, range.retry_flags,
1500+ range.min_retry, range.max_retry,
1501+ buffer, sizeof(buffer),
1502+ range.we_version_compiled);
1503+ /* Display min/max lifetime availables */
1504+ print_retry_value_range("lifetime", IW_RETRY_LIFETIME,
1505+ range.r_time_flags,
1506+ range.min_r_time, range.max_r_time,
1507+ buffer, sizeof(buffer),
1508+ range.we_version_compiled);
12421509
1243- /* Initiate Scanning */
1244- if(iw_set_ext(skfd, ifname, SIOCSIWSCAN, &wrq) < 0)
1245- {
1246- if(errno != EPERM)
1510+ /* Get current retry settings */
1511+ wrq.u.retry.flags = 0;
1512+ if(iw_get_ext(skfd, ifname, SIOCGIWRETRY, &wrq) >= 0)
12471513 {
1248- fprintf(stderr, "%-8.16s Interface doesn't support scanning : %s\n\n",
1249- ifname, strerror(errno));
1250- return(-1);
1251- }
1252- /* If we don't have the permission to initiate the scan, we may
1253- * still have permission to read left-over results.
1254- * But, don't wait !!! */
1255-#if 0
1256- /* Not cool, it display for non wireless interfaces... */
1257- fprintf(stderr, "%-8.16s (Could not trigger scanning, just reading left-over results)\n", ifname);
1258-#endif
1259- tv.tv_usec = 0;
1260- }
1261- timeout -= tv.tv_usec;
1262-
1263- /* Forever */
1264- while(1)
1265- {
1266- fd_set rfds; /* File descriptors for select */
1267- int last_fd; /* Last fd */
1268- int ret;
1269-
1270- /* Guess what ? We must re-generate rfds each time */
1271- FD_ZERO(&rfds);
1272- last_fd = -1;
1514+ int flags = wrq.u.retry.flags;
12731515
1274- /* In here, add the rtnetlink fd in the list */
1516+ /* Is it disabled ? */
1517+ if(wrq.u.retry.disabled)
1518+ printf("Current mode:off\n ");
1519+ else
1520+ {
1521+ unsigned int retry_type = 0;
1522+ unsigned int retry_mask = 0;
1523+ unsigned int remain_mask = range.retry_capa & IW_RETRY_TYPE;
12751524
1276- /* Wait until something happens */
1277- ret = select(last_fd + 1, &rfds, NULL, NULL, &tv);
1525+ /* Let's check the mode */
1526+ printf("Current mode:on\n ");
12781527
1279- /* Check if there was an error */
1280- if(ret < 0)
1281- {
1282- if(errno == EAGAIN || errno == EINTR)
1283- continue;
1284- fprintf(stderr, "Unhandled signal - exiting...\n");
1285- return(-1);
1286- }
1528+ /* Let's check the value and its type */
1529+ if(wrq.u.retry.flags & IW_RETRY_TYPE)
1530+ {
1531+ iw_print_retry_value(buffer, sizeof(buffer),
1532+ wrq.u.retry.value, wrq.u.retry.flags,
1533+ range.we_version_compiled);
1534+ printf("%s\n ", buffer);
1535+ }
12871536
1288- /* Check if there was a timeout */
1289- if(ret == 0)
1290- {
1291- unsigned char * newbuf;
1537+ while(1)
1538+ {
1539+ /* Deal with min/max/short/long for the current value */
1540+ retry_mask = 0;
1541+ /* If we have been returned a MIN value, ask for the MAX */
1542+ if(flags & IW_RETRY_MIN)
1543+ retry_mask = IW_RETRY_MAX;
1544+ /* If we have been returned a MAX value, ask for the MIN */
1545+ if(flags & IW_RETRY_MAX)
1546+ retry_mask = IW_RETRY_MIN;
1547+ /* Same for SHORT and LONG */
1548+ if(flags & IW_RETRY_SHORT)
1549+ retry_mask = IW_RETRY_LONG;
1550+ if(flags & IW_RETRY_LONG)
1551+ retry_mask = IW_RETRY_SHORT;
1552+ /* If we have something to ask for... */
1553+ if(retry_mask)
1554+ {
1555+ retry_mask |= retry_type;
1556+ get_retry_value(skfd, ifname, &wrq, retry_mask,
1557+ buffer, sizeof(buffer),
1558+ range.we_version_compiled);
1559+ }
12921560
1293- realloc:
1294- /* (Re)allocate the buffer - realloc(NULL, len) == malloc(len) */
1295- newbuf = realloc(buffer, buflen);
1296- if(newbuf == NULL)
1297- {
1298- if(buffer)
1299- free(buffer);
1300- fprintf(stderr, "%s: Allocation failed\n", __FUNCTION__);
1301- return(-1);
1561+ /* And if we have both a limit and a lifetime,
1562+ * ask the other one */
1563+ remain_mask &= ~(wrq.u.retry.flags);
1564+ retry_type = remain_mask;
1565+ /* Nothing anymore : exit the loop */
1566+ if(!retry_type)
1567+ break;
1568+
1569+ /* Ask for this other type of value */
1570+ flags = get_retry_value(skfd, ifname, &wrq, retry_type,
1571+ buffer, sizeof(buffer),
1572+ range.we_version_compiled);
1573+ /* Loop back for min/max/short/long */
1574+ }
13021575 }
1303- buffer = newbuf;
1576+ }
1577+ printf("\n");
1578+ }
1579+ return(0);
1580+}
13041581
1305- /* Try to read the results */
1306- wrq.u.data.pointer = buffer;
1307- wrq.u.data.flags = 0;
1308- wrq.u.data.length = buflen;
1309- if(iw_get_ext(skfd, ifname, SIOCGIWSCAN, &wrq) < 0)
1310- {
1311- /* Check if buffer was too small (WE-17 only) */
1312- if((errno == E2BIG) && (range.we_version_compiled > 16))
1313- {
1314- /* Some driver may return very large scan results, either
1315- * because there are many cells, or because they have many
1316- * large elements in cells (like IWEVCUSTOM). Most will
1317- * only need the regular sized buffer. We now use a dynamic
1318- * allocation of the buffer to satisfy everybody. Of course,
1319- * as we don't know in advance the size of the array, we try
1320- * various increasing sizes. Jean II */
1582+/************************ ACCESS POINT LIST ************************/
1583+/*
1584+ * Note : now that we have scanning support, this is depracted and
1585+ * won't survive long. Actually, next version it's out !
1586+ */
13211587
1322- /* Check if the driver gave us any hints. */
1323- if(wrq.u.data.length > buflen)
1324- buflen = wrq.u.data.length;
1325- else
1326- buflen *= 2;
1588+/*------------------------------------------------------------------*/
1589+/*
1590+ * Display the list of ap addresses and the associated stats
1591+ * Exacly the same as the spy list, only with different IOCTL and messages
1592+ */
1593+static int
1594+print_ap_info(int skfd,
1595+ char * ifname,
1596+ char * args[], /* Command line args */
1597+ int count) /* Args count */
1598+{
1599+ struct iwreq wrq;
1600+ char buffer[(sizeof(struct iw_quality) +
1601+ sizeof(struct sockaddr)) * IW_MAX_AP];
1602+ char temp[128];
1603+ struct sockaddr * hwa;
1604+ struct iw_quality * qual;
1605+ iwrange range;
1606+ int has_range = 0;
1607+ int has_qual = 0;
1608+ int n;
1609+ int i;
13271610
1328- /* Try again */
1329- goto realloc;
1330- }
1611+ /* Avoid "Unused parameter" warning */
1612+ args = args; count = count;
13311613
1332- /* Check if results not available yet */
1333- if(errno == EAGAIN)
1334- {
1335- /* Restart timer for only 100ms*/
1336- tv.tv_sec = 0;
1337- tv.tv_usec = 100000;
1338- timeout -= tv.tv_usec;
1339- if(timeout > 0)
1340- continue; /* Try again later */
1341- }
1614+ /* Collect stats */
1615+ wrq.u.data.pointer = (caddr_t) buffer;
1616+ wrq.u.data.length = IW_MAX_AP;
1617+ wrq.u.data.flags = 0;
1618+ if(iw_get_ext(skfd, ifname, SIOCGIWAPLIST, &wrq) < 0)
1619+ {
1620+ fprintf(stderr, "%-8.16s Interface doesn't have a list of Peers/Access-Points\n\n", ifname);
1621+ return(-1);
1622+ }
13421623
1343- /* Bad error */
1344- free(buffer);
1345- fprintf(stderr, "%-8.16s Failed to read scan data : %s\n\n",
1346- ifname, strerror(errno));
1347- return(-2);
1348- }
1349- else
1350- /* We have the results, go to process them */
1351- break;
1352- }
1624+ /* Number of addresses */
1625+ n = wrq.u.data.length;
1626+ has_qual = wrq.u.data.flags;
13531627
1354- /* In here, check if event and event type
1355- * if scan event, read results. All errors bad & no reset timeout */
1628+ /* The two lists */
1629+ hwa = (struct sockaddr *) buffer;
1630+ qual = (struct iw_quality *) (buffer + (sizeof(struct sockaddr) * n));
1631+
1632+ /* Check if we have valid mac address type */
1633+ if(iw_check_mac_addr_type(skfd, ifname) < 0)
1634+ {
1635+ fprintf(stderr, "%-8.16s Interface doesn't support MAC addresses\n\n", ifname);
1636+ return(-2);
13561637 }
13571638
1358- if(wrq.u.data.length)
1639+ /* Get range info if we can */
1640+ if(iw_get_range_info(skfd, ifname, &(range)) >= 0)
1641+ has_range = 1;
1642+
1643+ /* Display it */
1644+ if(n == 0)
1645+ printf("%-8.16s No Peers/Access-Point in range\n", ifname);
1646+ else
1647+ printf("%-8.16s Peers/Access-Points in range:\n", ifname);
1648+ for(i = 0; i < n; i++)
13591649 {
1360- struct iw_event iwe;
1361- struct stream_descr stream;
1362- struct iwscan_state state = { .ap_num = 1, .val_index = 0 };
1363- int ret;
1364-
1365-#if 0
1366- /* Debugging code. In theory useless, because it's debugged ;-) */
1367- int i;
1368- printf("Scan result %d [%02X", wrq.u.data.length, buffer[0]);
1369- for(i = 1; i < wrq.u.data.length; i++)
1370- printf(":%02X", buffer[i]);
1371- printf("]\n");
1372-#endif
1373- printf("%-8.16s Scan completed :\n", ifname);
1374- iw_init_event_stream(&stream, (char *) buffer, wrq.u.data.length);
1375- do
1650+ if(has_qual)
13761651 {
1377- /* Extract an event and print it */
1378- ret = iw_extract_event_stream(&stream, &iwe,
1379- range.we_version_compiled);
1380- if(ret > 0)
1381- print_scanning_token(&stream, &iwe, &state,
1382- &range, has_range);
1652+ /* Print stats for this address */
1653+ printf(" %s : ", iw_saether_ntop(&hwa[i], temp));
1654+ iw_print_stats(temp, sizeof(buffer), &qual[i], &range, has_range);
1655+ printf("%s\n", temp);
13831656 }
1384- while(ret > 0);
1385- printf("\n");
1657+ else
1658+ /* Only print the address */
1659+ printf(" %s\n", iw_saether_ntop(&hwa[i], temp));
13861660 }
1387- else
1388- printf("%-8.16s No scan results\n", ifname);
1389-
1390- free(buffer);
1661+ printf("\n");
13911662 return(0);
13921663 }
13931664
@@ -1419,7 +1690,7 @@ static const char * event_capa_evt[] =
14191690
14201691 /*------------------------------------------------------------------*/
14211692 /*
1422- * Print the number of available transmit powers for the device
1693+ * Print the event capability for the device
14231694 */
14241695 static int
14251696 print_event_capa_info(int skfd,
@@ -1440,7 +1711,7 @@ print_event_capa_info(int skfd,
14401711 ifname);
14411712 else
14421713 {
1443-#if 0
1714+#ifdef DEBUG
14441715 /* Debugging ;-) */
14451716 for(cmd = 0x8B00; cmd < 0x8C0F; cmd++)
14461717 {
@@ -1473,6 +1744,296 @@ print_event_capa_info(int skfd,
14731744 return(0);
14741745 }
14751746
1747+/*************************** WPA SUPPORT ***************************/
1748+
1749+/*------------------------------------------------------------------*/
1750+/*
1751+ * Print the authentication parameters for the device
1752+ */
1753+static int
1754+print_auth_info(int skfd,
1755+ char * ifname,
1756+ char * args[], /* Command line args */
1757+ int count) /* Args count */
1758+{
1759+ struct iwreq wrq;
1760+ struct iw_range range;
1761+ unsigned int k;
1762+
1763+ /* Avoid "Unused parameter" warning */
1764+ args = args; count = count;
1765+
1766+ /* Extract range info */
1767+ if((iw_get_range_info(skfd, ifname, &range) < 0) ||
1768+ (range.we_version_compiled < 18))
1769+ fprintf(stderr, "%-8.16s no authentication information.\n\n",
1770+ ifname);
1771+ else
1772+ {
1773+ /* Print WPA/802.1x/802.11i security parameters */
1774+ if(!range.enc_capa)
1775+ {
1776+ printf("%-8.16s unknown authentication information.\n\n", ifname);
1777+ }
1778+ else
1779+ {
1780+ /* Display advanced encryption capabilities */
1781+ printf("%-8.16s Authentication capabilities :", ifname);
1782+ iw_print_mask_name(range.enc_capa,
1783+ iw_auth_capa_name, IW_AUTH_CAPA_NUM,
1784+ "\n\t\t");
1785+ printf("\n");
1786+
1787+ /* Extract all auth settings */
1788+ for(k = 0; k < IW_AUTH_SETTINGS_NUM; k++)
1789+ {
1790+ wrq.u.param.flags = iw_auth_settings[k].value;
1791+ if(iw_get_ext(skfd, ifname, SIOCGIWAUTH, &wrq) >= 0)
1792+ {
1793+ printf(" Current %s :", iw_auth_settings[k].label);
1794+ if(iw_auth_settings[k].names != NULL)
1795+ iw_print_mask_name(wrq.u.param.value,
1796+ iw_auth_settings[k].names,
1797+ iw_auth_settings[k].num_names,
1798+ "\n\t\t");
1799+ else
1800+ printf((wrq.u.param.value) ? " yes" : " no");
1801+ printf("\n");
1802+ }
1803+ }
1804+ }
1805+
1806+ printf("\n\n");
1807+ }
1808+ return(0);
1809+}
1810+
1811+/*------------------------------------------------------------------*/
1812+/*
1813+ * Print all the available wpa keys for the device
1814+ */
1815+static int
1816+print_wpakeys_info(int skfd,
1817+ char * ifname,
1818+ char * args[], /* Command line args */
1819+ int count) /* Args count */
1820+{
1821+ struct iwreq wrq;
1822+ struct iw_range range;
1823+ unsigned char extbuf[IW_EXTKEY_SIZE];
1824+ struct iw_encode_ext *extinfo;
1825+ unsigned int k;
1826+ char buffer[128];
1827+
1828+ /* Avoid "Unused parameter" warning */
1829+ args = args; count = count;
1830+
1831+ /* This always point to the same place */
1832+ extinfo = (struct iw_encode_ext *) extbuf;
1833+
1834+ /* Extract range info */
1835+ if(iw_get_range_info(skfd, ifname, &range) < 0)
1836+ fprintf(stderr, "%-8.16s no wpa key information.\n\n",
1837+ ifname);
1838+ else
1839+ {
1840+ printf("%-8.16s ", ifname);
1841+ /* Print key sizes */
1842+ if((range.num_encoding_sizes > 0) &&
1843+ (range.num_encoding_sizes < IW_MAX_ENCODING_SIZES))
1844+ {
1845+ printf("%d key sizes : %d", range.num_encoding_sizes,
1846+ range.encoding_size[0] * 8);
1847+ /* Print them all */
1848+ for(k = 1; k < range.num_encoding_sizes; k++)
1849+ printf(", %d", range.encoding_size[k] * 8);
1850+ printf("bits\n ");
1851+ }
1852+
1853+ /* Print the keys */
1854+ printf("%d keys available :\n", range.max_encoding_tokens);
1855+ for(k = 1; k <= range.max_encoding_tokens; k++)
1856+ {
1857+ /* Cleanup. Driver may not fill everything */
1858+ memset(extbuf, '\0', IW_EXTKEY_SIZE);
1859+
1860+ /* Get whole struct containing one WPA key */
1861+ wrq.u.data.pointer = (caddr_t) extbuf;
1862+ wrq.u.data.length = IW_EXTKEY_SIZE;
1863+ wrq.u.data.flags = k;
1864+ if(iw_get_ext(skfd, ifname, SIOCGIWENCODEEXT, &wrq) < 0)
1865+ {
1866+ fprintf(stderr, "Error reading wpa keys (SIOCGIWENCODEEXT): %s\n", strerror(errno));
1867+ break;
1868+ }
1869+
1870+ /* Sanity check */
1871+ if(wrq.u.data.length <
1872+ (sizeof(struct iw_encode_ext) + extinfo->key_len))
1873+ break;
1874+
1875+ /* Check if key is disabled */
1876+ if((wrq.u.data.flags & IW_ENCODE_DISABLED) ||
1877+ (extinfo->key_len == 0))
1878+ printf("\t\t[%d]: off\n", k);
1879+ else
1880+ {
1881+ /* Display the key */
1882+ iw_print_key(buffer, sizeof(buffer),
1883+ extinfo->key, extinfo->key_len, wrq.u.data.flags);
1884+ printf("\t\t[%d]: %s", k, buffer);
1885+
1886+ /* Key size */
1887+ printf(" (%d bits)", extinfo->key_len * 8);
1888+ printf("\n");
1889+
1890+ /* Other info... */
1891+ printf("\t\t Address: %s\n",
1892+ iw_saether_ntop(&extinfo->addr, buffer));
1893+
1894+ printf("\t\t Algorithm:");
1895+ iw_print_value_name(extinfo->alg,
1896+ iw_encode_alg_name, IW_ENCODE_ALG_NUM);
1897+
1898+ printf("\n\t\t Flags: 0x%08x\n", extinfo->ext_flags);
1899+ if (extinfo->ext_flags & IW_ENCODE_EXT_TX_SEQ_VALID)
1900+ printf("\t\t tx-seq-valid\n");
1901+ if (extinfo->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID)
1902+ printf("\t\t rx-seq-valid\n");
1903+ if (extinfo->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
1904+ printf("\t\t group-key\n");
1905+ }
1906+ }
1907+ /* Print current key index and mode */
1908+ wrq.u.data.pointer = (caddr_t) extbuf;
1909+ wrq.u.data.length = IW_EXTKEY_SIZE;
1910+ wrq.u.data.flags = 0; /* Set index to zero to get current */
1911+ if(iw_get_ext(skfd, ifname, SIOCGIWENCODEEXT, &wrq) >= 0)
1912+ {
1913+ /* Note : if above fails, we have already printed an error
1914+ * message int the loop above */
1915+ printf(" Current Transmit Key: [%d]\n",
1916+ wrq.u.data.flags & IW_ENCODE_INDEX);
1917+ if(wrq.u.data.flags & IW_ENCODE_RESTRICTED)
1918+ printf(" Security mode:restricted\n");
1919+ if(wrq.u.data.flags & IW_ENCODE_OPEN)
1920+ printf(" Security mode:open\n");
1921+ }
1922+
1923+ printf("\n\n");
1924+ }
1925+ return(0);
1926+}
1927+
1928+/*------------------------------------------------------------------*/
1929+/*
1930+ * Print the Generic IE for the device
1931+ * Note : indentation is broken. We need to fix that.
1932+ */
1933+static int
1934+print_gen_ie_info(int skfd,
1935+ char * ifname,
1936+ char * args[], /* Command line args */
1937+ int count) /* Args count */
1938+{
1939+ struct iwreq wrq;
1940+ unsigned char buf[IW_GENERIC_IE_MAX];
1941+
1942+ /* Avoid "Unused parameter" warning */
1943+ args = args; count = count;
1944+
1945+ wrq.u.data.pointer = (caddr_t)buf;
1946+ wrq.u.data.length = IW_GENERIC_IE_MAX;
1947+ wrq.u.data.flags = 0;
1948+
1949+ if(iw_get_ext(skfd, ifname, SIOCGIWGENIE, &wrq) < 0)
1950+ fprintf(stderr, "%-8.16s no generic IE (%s).\n\n",
1951+ ifname, strerror(errno));
1952+ else
1953+ {
1954+ fprintf(stderr, "%-8.16s\n", ifname);
1955+ if(wrq.u.data.length == 0)
1956+ printf(" empty generic IE\n");
1957+ else
1958+ iw_print_gen_ie(buf, wrq.u.data.length);
1959+ printf("\n");
1960+ }
1961+ return(0);
1962+}
1963+
1964+/**************************** MODULATION ****************************/
1965+
1966+/*------------------------------------------------------------------*/
1967+/*
1968+ * Print Modulation info for each device
1969+ */
1970+static int
1971+print_modul_info(int skfd,
1972+ char * ifname,
1973+ char * args[], /* Command line args */
1974+ int count) /* Args count */
1975+{
1976+ struct iwreq wrq;
1977+ struct iw_range range;
1978+
1979+ /* Avoid "Unused parameter" warning */
1980+ args = args; count = count;
1981+
1982+ /* Extract range info */
1983+ if((iw_get_range_info(skfd, ifname, &range) < 0) ||
1984+ (range.we_version_compiled < 11))
1985+ fprintf(stderr, "%-8.16s no modulation information.\n\n",
1986+ ifname);
1987+ else
1988+ {
1989+ if(range.modul_capa == 0x0)
1990+ printf("%-8.16s unknown modulation information.\n\n", ifname);
1991+ else
1992+ {
1993+ int i;
1994+ printf("%-8.16s Modulations available :\n", ifname);
1995+
1996+ /* Display each modulation available */
1997+ for(i = 0; i < IW_SIZE_MODUL_LIST; i++)
1998+ {
1999+ if((range.modul_capa & iw_modul_list[i].mask)
2000+ == iw_modul_list[i].mask)
2001+ printf(" %-8s: %s\n",
2002+ iw_modul_list[i].cmd, iw_modul_list[i].verbose);
2003+ }
2004+
2005+ /* Get current modulations settings */
2006+ wrq.u.param.flags = 0;
2007+ if(iw_get_ext(skfd, ifname, SIOCGIWMODUL, &wrq) >= 0)
2008+ {
2009+ unsigned int modul = wrq.u.param.value;
2010+ int n = 0;
2011+
2012+ printf(" Current modulations %c",
2013+ wrq.u.param.fixed ? '=' : ':');
2014+
2015+ /* Display each modulation enabled */
2016+ for(i = 0; i < IW_SIZE_MODUL_LIST; i++)
2017+ {
2018+ if((modul & iw_modul_list[i].mask) == iw_modul_list[i].mask)
2019+ {
2020+ if((n++ % 8) == 0)
2021+ printf("\n ");
2022+ else
2023+ printf(" ; ");
2024+ printf("%s", iw_modul_list[i].cmd);
2025+ }
2026+ }
2027+
2028+ printf("\n");
2029+ }
2030+ printf("\n");
2031+ }
2032+ }
2033+ return(0);
2034+}
2035+#endif /* WE_ESSENTIAL */
2036+
14762037 /************************* COMMON UTILITIES *************************/
14772038 /*
14782039 * This section was initially written by Michael Tokarev <mjt@tls.msk.ru>
@@ -1484,27 +2045,33 @@ print_event_capa_info(int skfd,
14842045 * Map command line arguments to the proper procedure...
14852046 */
14862047 typedef struct iwlist_entry {
1487- const char *cmd;
1488- iw_enum_handler fn;
1489- int min_count;
1490- int max_count;
2048+ const char * cmd; /* Command line shorthand */
2049+ iw_enum_handler fn; /* Subroutine */
2050+ int max_count;
2051+ const char * argsname; /* Args as human readable string */
14912052 } iwlist_cmd;
14922053
14932054 static const struct iwlist_entry iwlist_cmds[] = {
1494- { "scanning", print_scanning_info, 0, 5 },
1495- { "frequency", print_freq_info, 0, 0 },
1496- { "channel", print_freq_info, 0, 0 },
1497- { "bitrate", print_bitrate_info, 0, 0 },
1498- { "rate", print_bitrate_info, 0, 0 },
1499- { "encryption", print_keys_info, 0, 0 },
1500- { "key", print_keys_info, 0, 0 },
1501- { "power", print_pm_info, 0, 0 },
1502- { "txpower", print_txpower_info, 0, 0 },
1503- { "retry", print_retry_info, 0, 0 },
1504- { "ap", print_ap_info, 0, 0 },
1505- { "accesspoints", print_ap_info, 0, 0 },
1506- { "peers", print_ap_info, 0, 0 },
1507- { "event", print_event_capa_info, 0, 0 },
2055+ { "scanning", print_scanning_info, -1, "[essid NNN] [last]" },
2056+ { "frequency", print_freq_info, 0, NULL },
2057+ { "channel", print_freq_info, 0, NULL },
2058+ { "bitrate", print_bitrate_info, 0, NULL },
2059+ { "rate", print_bitrate_info, 0, NULL },
2060+ { "encryption", print_keys_info, 0, NULL },
2061+ { "keys", print_keys_info, 0, NULL },
2062+ { "power", print_pm_info, 0, NULL },
2063+#ifndef WE_ESSENTIAL
2064+ { "txpower", print_txpower_info, 0, NULL },
2065+ { "retry", print_retry_info, 0, NULL },
2066+ { "ap", print_ap_info, 0, NULL },
2067+ { "accesspoints", print_ap_info, 0, NULL },
2068+ { "peers", print_ap_info, 0, NULL },
2069+ { "event", print_event_capa_info, 0, NULL },
2070+ { "auth", print_auth_info, 0, NULL },
2071+ { "wpakeys", print_wpakeys_info, 0, NULL },
2072+ { "genie", print_gen_ie_info, 0, NULL },
2073+ { "modulation", print_modul_info, 0, NULL },
2074+#endif /* WE_ESSENTIAL */
15082075 { NULL, NULL, 0, 0 },
15092076 };
15102077
@@ -1543,13 +2110,13 @@ find_command(const char * cmd)
15432110
15442111 if(found == NULL)
15452112 {
1546- fprintf(stderr, "iwlist: unknown command `%s'\n", cmd);
2113+ fprintf(stderr, "iwlist: unknown command `%s' (check 'iwlist --help').\n", cmd);
15472114 return NULL;
15482115 }
15492116
15502117 if(ambig)
15512118 {
1552- fprintf(stderr, "iwlist: command `%s' is ambiguous\n", cmd);
2119+ fprintf(stderr, "iwlist: command `%s' is ambiguous (check 'iwlist --help').\n", cmd);
15532120 return NULL;
15542121 }
15552122
@@ -1562,12 +2129,17 @@ find_command(const char * cmd)
15622129 */
15632130 static void iw_usage(int status)
15642131 {
1565- FILE* f = status ? stderr : stdout;
1566- int i;
2132+ FILE * f = status ? stderr : stdout;
2133+ int i;
2134+
2135+ for(i = 0; iwlist_cmds[i].cmd != NULL; ++i)
2136+ {
2137+ fprintf(f, "%s [interface] %s %s\n",
2138+ (i ? " " : "Usage: iwlist"),
2139+ iwlist_cmds[i].cmd,
2140+ iwlist_cmds[i].argsname ? iwlist_cmds[i].argsname : "");
2141+ }
15672142
1568- fprintf(f, "Usage: iwlist [interface] %s\n", iwlist_cmds[0].cmd);
1569- for(i = 1; iwlist_cmds[i].cmd != NULL; ++i)
1570- fprintf(f, " [interface] %s\n", iwlist_cmds[i].cmd);
15712143 exit(status);
15722144 }
15732145
@@ -1588,7 +2160,7 @@ main(int argc,
15882160 int count; /* Number of arguments */
15892161 const iwlist_cmd *iwcmd;
15902162
1591- if(argc == 1 || argc > 3)
2163+ if(argc < 2)
15922164 iw_usage(1);
15932165
15942166 /* Those don't apply to all interfaces */
@@ -1618,14 +2190,10 @@ main(int argc,
16182190 return 1;
16192191
16202192 /* Check arg numbers */
1621- if(count < iwcmd->min_count)
1622- {
1623- fprintf(stderr, "iwlist: command `%s' needs more arguments\n", cmd);
1624- return 1;
1625- }
1626- if(count > iwcmd->max_count)
2193+ if((iwcmd->max_count >= 0) && (count > iwcmd->max_count))
16272194 {
1628- fprintf(stderr, "iwlist: command `%s' needs fewer arguments\n", cmd);
2195+ fprintf(stderr, "iwlist: command `%s' needs fewer arguments (max %d)\n",
2196+ iwcmd->cmd, iwcmd->max_count);
16292197 return 1;
16302198 }
16312199
--- a/wireless_tools/iwmulticall.c
+++ b/wireless_tools/iwmulticall.c
@@ -61,21 +61,27 @@ extern int
6161 /* Get iwconfig in there. Mandatory. */
6262 #define main(args...) main_iwconfig(args)
6363 #define iw_usage(args...) iwconfig_usage(args)
64+#define find_command(args...) iwconfig_find_command(args)
6465 #include "iwconfig.c"
66+#undef find_command
6567 #undef iw_usage
6668 #undef main
6769
6870 /* Get iwlist in there. Scanning support is pretty sweet. */
6971 #define main(args...) main_iwlist(args)
7072 #define iw_usage(args...) iwlist_usage(args)
73+#define find_command(args...) iwlist_find_command(args)
7174 #include "iwlist.c"
75+#undef find_command
7276 #undef iw_usage
7377 #undef main
7478
79+#ifndef WE_ESSENTIAL
7580 /* Get iwspy in there, it's not that big. */
7681 #define main(args...) main_iwspy(args)
7782 #include "iwspy.c"
7883 #undef main
84+#endif /* WE_ESSENTIAL */
7985
8086 /* Get iwpriv in there. Mandatory for HostAP and some other drivers. */
8187 #define main(args...) main_iwpriv(args)
@@ -122,8 +128,10 @@ main(int argc,
122128 return(main_iwconfig(argc, argv));
123129 if(!strcmp(call_name, "iwlist"))
124130 return(main_iwlist(argc, argv));
131+#ifndef WE_ESSENTIAL
125132 if(!strcmp(call_name, "iwspy"))
126133 return(main_iwspy(argc, argv));
134+#endif /* WE_ESSENTIAL */
127135 if(!strcmp(call_name, "iwpriv"))
128136 return(main_iwpriv(argc, argv));
129137 if(!strcmp(call_name, "iwgetid"))
--- a/wireless_tools/iwpriv.8
+++ b/wireless_tools/iwpriv.8
@@ -16,13 +16,9 @@ network interface
1616 .br
1717 .BI "iwpriv " "interface private-command " "[" private-parameters ]
1818 .br
19-.BI "iwpriv " "interface private-command [I] " "[" private-parameters ]
19+.BI "iwpriv " "interface private-command " [ I "] [" private-parameters ]
2020 .br
2121 .BI "iwpriv " interface " --all"
22-.br
23-.BI "iwpriv " interface " roam " {on,off}
24-.br
25-.BI "iwpriv " interface " port " {ad-hoc,managed,N}
2622 .\"
2723 .\" DESCRIPTION part
2824 .\"
@@ -64,7 +60,7 @@ about those parameters.
6460 However you should refer to the device driver documentation for
6561 information on how to properly use the command and the effect.
6662 .TP
67-.I "private-command [I]" "[" private-parameters ]
63+.IR "private-command " [ I "] [" private-parameters ]
6864 Idem, except that
6965 .I I
7066 (an integer) is passed to the command as a
@@ -75,19 +71,6 @@ the driver documentation should tell you when it's needed.
7571 .BR -a / --all
7672 Execute and display all the private commands that don't take any
7773 arguments (i.e. read only).
78-.TP
79-.B roam
80-Enable or disable roaming, if supported. Call the private command
81-.IR setroam .
82-Found in the
83-.I wavelan_cs
84-driver.
85-.TP
86-.B port
87-Read or configure the port type. Call the private commands
88-.IR gport_type ", " sport_type ", " get_port " or " set_port
89-found in the
90-.IR wavelan2_cs " and " wvlan_cs " drivers."
9174 .\"
9275 .\" DISPLAY part
9376 .\"
--- a/wireless_tools/iwpriv.c
+++ b/wireless_tools/iwpriv.c
@@ -1,14 +1,14 @@
11 /*
22 * Wireless Tools
33 *
4- * Jean II - HPLB 97->99 - HPL 99->04
4+ * Jean II - HPLB 97->99 - HPL 99->07
55 *
66 * Main code for "iwconfig". This is the generic tool for most
77 * manipulations...
88 * You need to link this code against "iwlib.c" and "-lm".
99 *
1010 * This file is released under the GPL license.
11- * Copyright (c) 1997-2004 Jean Tourrilhes <jt@hpl.hp.com>
11+ * Copyright (c) 1997-2007 Jean Tourrilhes <jt@hpl.hp.com>
1212 */
1313
1414 #include "iwlib.h" /* Header */
@@ -384,9 +384,9 @@ set_private_cmd(int skfd, /* Socket */
384384 printf("Invalid float [%s]...\n", args[i]);
385385 return(-1);
386386 }
387- if(index(args[i], 'G')) freq *= GIGA;
388- if(index(args[i], 'M')) freq *= MEGA;
389- if(index(args[i], 'k')) freq *= KILO;
387+ if(strchr(args[i], 'G')) freq *= GIGA;
388+ if(strchr(args[i], 'M')) freq *= MEGA;
389+ if(strchr(args[i], 'k')) freq *= KILO;
390390 sscanf(args[i], "%i", &temp);
391391 iw_float2freq(freq, ((struct iw_freq *) buffer) + i);
392392 }
@@ -690,6 +690,7 @@ print_priv_all(int skfd,
690690 * Convenient access to some private ioctls of some devices
691691 */
692692
693+#if 0
693694 /*------------------------------------------------------------------*/
694695 /*
695696 * Set roaming mode on and off