external/wireless-tools
Revision | c7b2e81e6d53daac413a19d5446ab68b8395c849 (tree) |
---|---|
Time | 2016-10-12 06:17:19 |
Author | chris-kirby <chris.kirby@hpe....> |
Commiter | chris-kirby |
v29
@@ -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" |
@@ -1,7 +1,7 @@ | ||
1 | 1 | /* |
2 | 2 | * Wireless Tools |
3 | 3 | * |
4 | - * Jean II - HPLB 97->99 - HPL 99->04 | |
4 | + * Jean II - HPLB 97->99 - HPL 99->07 | |
5 | 5 | * |
6 | 6 | * The changelog... |
7 | 7 | * |
@@ -625,6 +625,121 @@ | ||
625 | 625 | * o Add WE-20 headers, compile with that as default |
626 | 626 | * --- |
627 | 627 | * 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] | |
628 | 743 | */ |
629 | 744 | |
630 | 745 | /* ----------------------------- TODO ----------------------------- */ |
@@ -635,10 +750,7 @@ | ||
635 | 750 | * -------- |
636 | 751 | * Make disable a per encryption key modifier if some hardware |
637 | 752 | * requires it. |
638 | - * | |
639 | - * iwpriv : | |
640 | - * ------ | |
641 | - * Remove 'port' and 'roam' cruft now that we have mode in iwconfig | |
753 | + * IW_QUAL_RCPI | |
642 | 754 | * |
643 | 755 | * iwspy : |
644 | 756 | * ----- |
@@ -79,21 +79,21 @@ interfaces, with rules such as : | ||
79 | 79 | http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev.html |
80 | 80 | |
81 | 81 | Advantages over 'ifrename' : |
82 | - + integrated into 'udev' | |
83 | 82 | + simpler to setup if 'udev' is already properly setup |
83 | + + automatically generates persistent rules | |
84 | 84 | Drawbacks compared to 'ifrename' : |
85 | 85 | - Less selectors that 'ifrename' |
86 | 86 | - Require kernel 2.6.X or later with sysfs support |
87 | 87 | - Do no support non-hotplug interfaces |
88 | 88 | - Require 'udev', not everybody uses it (static /dev, devfs) |
89 | - - Does not support module on-demand loading | |
90 | 89 | Comments : |
91 | 90 | 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. | |
97 | 97 | o Not all interfaces are managed by hotplug. All |
98 | 98 | virtual devices, such as tunnels and loopbacks, are not associated |
99 | 99 | with a hardware bus, and therefore are not managed by hotplug. All |
@@ -102,7 +102,9 @@ hotplug. 'udev' can't deal with those devices. | ||
102 | 102 | o It is common practice on embedded system to use a |
103 | 103 | static /dev and not 'udev' to save space and boot time. And to not use |
104 | 104 | 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. | |
106 | 108 | |
107 | 109 | SELECTOR AWARE NETWORK SCRIPTS |
108 | 110 | ------------------------------ |
@@ -36,17 +36,87 @@ Create a local copy of the tools : | ||
36 | 36 | -------------------------------- |
37 | 37 | By default, the package is built with iwlib as a dynamic |
38 | 38 | 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. | |
40 | 41 | If you just want to experiment with a "local" version of the |
41 | 42 | tools, you may want to pass the BUILD_STATIC flag to Makefile. It will |
42 | 43 | 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 | + ------------- | |
47 | 48 | The resulting binary can be used in the compilation directory |
48 | 49 | or installed in any place you like. |
49 | 50 | |
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 | + | |
50 | 120 | Wireless headers (past history) : |
51 | 121 | ------------------------------- |
52 | 122 | Previous version of the Wireless Tools had to be compiled with |
@@ -63,18 +133,6 @@ you that. | ||
63 | 133 | Note that the previous option to make versioned installed of |
64 | 134 | the tools no longer make sense and therefore is gone. |
65 | 135 | |
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 | - | |
78 | 136 | Old kernel with older Wireless Extensions : |
79 | 137 | ----------------------------------------- |
80 | 138 | Kernel prior to 2.2.14 : Those kernels include Wireless |
@@ -2,31 +2,36 @@ | ||
2 | 2 | ## Please check the configurion parameters below |
3 | 3 | ## |
4 | 4 | |
5 | -## Installation directory. By default, go in /usr/local | |
5 | +## Installation directory. By default, go in /usr/local. | |
6 | 6 | ## Distributions should probably use /, but they probably know better... |
7 | 7 | ifndef PREFIX |
8 | 8 | PREFIX = /usr/local |
9 | 9 | endif |
10 | 10 | |
11 | -## Compiler to use (modify this for cross compile) | |
11 | +## Compiler to use (modify this for cross compile). | |
12 | 12 | 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). | |
14 | 14 | AR = ar |
15 | 15 | RANLIB = ranlib |
16 | 16 | |
17 | -## Uncomment this to build tools using static version of the library | |
17 | +## Uncomment this to build tools using static version of the library. | |
18 | 18 | ## Mostly useful for embedded platforms without ldd, or to create |
19 | 19 | ## a local version (non-root). |
20 | 20 | # BUILD_STATIC = y |
21 | 21 | |
22 | -## Uncomment this to build without using libm (less efficient) | |
22 | +## Uncomment this to build without using libm (less efficient). | |
23 | 23 | ## This is mostly useful for embedded platforms without maths. |
24 | 24 | # BUILD_NOLIBM = y |
25 | 25 | |
26 | -## Uncomment this to strip binary from symbols. This reduce binary size | |
26 | +## Uncomment this to strip binary from symbols. This reduce binary size. | |
27 | 27 | ## by a few percent but make debug worse... |
28 | 28 | # BUILD_STRIPPING = y |
29 | 29 | |
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 | + | |
30 | 35 | # *************************************************************************** |
31 | 36 | # ***** Most users should not need to change anything beyond this point ***** |
32 | 37 | # *************************************************************************** |
@@ -91,12 +96,17 @@ else | ||
91 | 96 | STRIPFLAGS= |
92 | 97 | endif |
93 | 98 | |
99 | +# Do we want to build with only essential functionality ? | |
100 | +ifdef BUILD_WE_ESSENTIAL | |
101 | + WEDEF_FLAG= -DWE_ESSENTIAL=y | |
102 | +endif | |
103 | + | |
94 | 104 | # Other flags |
95 | 105 | CFLAGS=-Os -W -Wall -Wstrict-prototypes -Wmissing-prototypes -Wshadow \ |
96 | 106 | -Wpointer-arith -Wcast-qual -Winline -I. |
97 | 107 | #CFLAGS=-O2 -W -Wall -Wstrict-prototypes -I. |
98 | 108 | DEPFLAGS=-MMD |
99 | -XCFLAGS=$(CFLAGS) $(DEPFLAGS) $(WARN) $(HEADERS) $(WELIB_FLAG) | |
109 | +XCFLAGS=$(CFLAGS) $(DEPFLAGS) $(WARN) $(HEADERS) $(WELIB_FLAG) $(WEDEF_FLAG) | |
100 | 110 | PICFLAG=-fPIC |
101 | 111 | |
102 | 112 | # Standard compilation targets |
@@ -1,10 +1,12 @@ | ||
1 | - Wireless Tools | |
2 | - -------------- | |
1 | + Wireless Tools & IfRename | |
2 | + ------------------------- | |
3 | 3 | |
4 | 4 | This package contains the Wireless tools, used to manipulate |
5 | 5 | the Wireless Extensions. The Wireless Extensions is an interface |
6 | 6 | allowing you to set Wireless LAN specific parameters and get the |
7 | 7 | specific stats. |
8 | + It also contains the IfRename package, used for advance | |
9 | +renaming of network interfaces. | |
8 | 10 | |
9 | 11 | web page : |
10 | 12 | -------- |
@@ -112,6 +114,10 @@ iwlib.c | ||
112 | 114 | The Wireless Tools helper library. May be useful if you want |
113 | 115 | to create your own applications using Wireless Extensions. |
114 | 116 | |
117 | +iwmulticall.c | |
118 | +------------- | |
119 | + Multicall version of the tools for embedded systems. | |
120 | + | |
115 | 121 | Changelog, contributions : |
116 | 122 | ------------------------ |
117 | 123 | See CHANGELOG.h |
@@ -136,6 +142,10 @@ more tricky features of Wireless Extensions in your driver. | ||
136 | 142 | alone works, but it should point you in the proper direction. |
137 | 143 | Also, have a look at existing drivers in the Linux kernel. |
138 | 144 | |
145 | +19-udev-ifrename.rules : | |
146 | +---------------------- | |
147 | + udev rules to integrate properly ifrename (udev >= 107). | |
148 | + | |
139 | 149 | Other tools : |
140 | 150 | ----------- |
141 | 151 | My web page lists many other tools using Wireless |
@@ -1,7 +1,7 @@ | ||
1 | -.\" Jean II - HPL - 2004 | |
1 | +.\" Jean II - HPL - 2004-2007 | |
2 | 2 | .\" ifrename.8 |
3 | 3 | .\" |
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" | |
5 | 5 | .\" |
6 | 6 | .\" NAME part |
7 | 7 | .\" |
@@ -11,7 +11,7 @@ ifrename \- rename network interfaces based on various static criteria | ||
11 | 11 | .\" SYNOPSIS part |
12 | 12 | .\" |
13 | 13 | .SH SYNOPSIS |
14 | -.B "ifrename [-c configfile] [-p] [-d] [-v] [-V] [-D]" | |
14 | +.B "ifrename [-c configfile] [-p] [-d] [-u] [-v] [-V] [-D]" | |
15 | 15 | .br |
16 | 16 | .B "ifrename [-c configfile] [-i interface] [-n newname]" |
17 | 17 | .\" |
@@ -124,12 +124,38 @@ In any case, name swapping and the use of this feature is discouraged, | ||
124 | 124 | and you are invited to choose unique and unambiguous names for your |
125 | 125 | interfaces... |
126 | 126 | .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 | |
127 | 147 | .B -D |
128 | 148 | Dry-run mode. Ifrename won't change any interface, it will only print |
129 | 149 | new interface name, if applicable, and return. |
130 | 150 | .br |
131 | 151 | In dry-run mode, interface name wildcards are not resolved. New |
132 | 152 | 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. | |
133 | 159 | .TP |
134 | 160 | .B -V |
135 | 161 | Verbose mode. Ifrename will display internal results of parsing its |
@@ -1,14 +1,14 @@ | ||
1 | 1 | /* |
2 | 2 | * Wireless Tools |
3 | 3 | * |
4 | - * Jean II - HPL 04 | |
4 | + * Jean II - HPL 04 -> 07 | |
5 | 5 | * |
6 | 6 | * Main code for "ifrename". This is tool allows to rename network |
7 | 7 | * interfaces based on various criteria (not only wireless). |
8 | 8 | * You need to link this code against "iwlib.c" and "-lm". |
9 | 9 | * |
10 | 10 | * 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> | |
12 | 12 | */ |
13 | 13 | |
14 | 14 | /* |
@@ -30,7 +30,7 @@ | ||
30 | 30 | * Difference with standard 'nameif' : |
31 | 31 | * o 'nameif' has only a single selector, the interface MAC address. |
32 | 32 | * 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... | |
34 | 34 | * o hotplug invocation support. |
35 | 35 | * o module loading support. |
36 | 36 | * o MAC address wildcard. |
@@ -82,7 +82,8 @@ const int SELECT_INTERRUPT = 9; /* Select by HW Irq line */ | ||
82 | 82 | const int SELECT_IWPROTO = 10; /* Select by Wireless Protocol */ |
83 | 83 | const int SELECT_PCMCIASLOT = 11; /* Select by Pcmcia Slot */ |
84 | 84 | 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 | |
86 | 87 | |
87 | 88 | #define HAS_MAC_EXACT 1 |
88 | 89 | #define HAS_MAC_FILTER 2 |
@@ -99,6 +100,7 @@ const struct option long_opt[] = | ||
99 | 100 | {"interface", 1, NULL, 'i' }, |
100 | 101 | {"newname", 1, NULL, 'n' }, |
101 | 102 | {"takeover", 0, NULL, 't' }, |
103 | + {"udev", 0, NULL, 'u' }, | |
102 | 104 | {"version", 0, NULL, 'v' }, |
103 | 105 | {"verbose", 0, NULL, 'V' }, |
104 | 106 | {NULL, 0, NULL, '\0' }, |
@@ -108,8 +110,8 @@ const struct option long_opt[] = | ||
108 | 110 | #define PCMCIA_STAB1 "/var/lib/pcmcia/stab" |
109 | 111 | #define PCMCIA_STAB2 "/var/run/stab" |
110 | 112 | |
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 | |
113 | 115 | |
114 | 116 | /* Userspace headers lag, fix that... */ |
115 | 117 | #ifndef ARPHRD_IEEE1394 |
@@ -160,6 +162,8 @@ typedef struct if_mapping | ||
160 | 162 | |
161 | 163 | /* Name of this interface */ |
162 | 164 | char ifname[IFNAMSIZ+1]; |
165 | + char * sysfs_devpath; | |
166 | + int sysfs_devplen; | |
163 | 167 | |
164 | 168 | /* Selectors for this interface */ |
165 | 169 | int active[SELECT_NUM]; /* Selectors active */ |
@@ -177,6 +181,7 @@ typedef struct if_mapping | ||
177 | 181 | char iwproto[IFNAMSIZ + 1]; /* Wireless/protocol name */ |
178 | 182 | int pcmcia_slot; /* Pcmcia slot */ |
179 | 183 | char * sysfs[SYSFS_MAX_FILE]; /* sysfs selectors */ |
184 | + char prevname[IFNAMSIZ+1]; /* previous interface name */ | |
180 | 185 | } if_mapping; |
181 | 186 | |
182 | 187 | /* Extra parsing information when adding a mapping */ |
@@ -358,6 +363,21 @@ static int | ||
358 | 363 | const char * ifname, |
359 | 364 | struct if_mapping * target, |
360 | 365 | 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); | |
361 | 381 | |
362 | 382 | /**************************** VARIABLES ****************************/ |
363 | 383 |
@@ -390,6 +410,8 @@ const struct mapping_selector selector_list[] = | ||
390 | 410 | { "pcmciaslot", &mapping_addpcmciaslot, &mapping_cmppcmciaslot, &mapping_getpcmciaslot }, |
391 | 411 | /* sysfs file (udev emulation) */ |
392 | 412 | { "sysfs", &mapping_addsysfs, &mapping_cmpsysfs, &mapping_getsysfs }, |
413 | + /* previous interface name */ | |
414 | + { "prevname", &mapping_addprevname, &mapping_cmpprevname, &mapping_getprevname }, | |
393 | 415 | /* The Terminator */ |
394 | 416 | { NULL, NULL, NULL, NULL }, |
395 | 417 | }; |
@@ -419,6 +441,9 @@ int dry_run = 0; /* Just print new name, don't rename */ | ||
419 | 441 | /* Verbose support (i.e. debugging) */ |
420 | 442 | int verbose = 0; |
421 | 443 | |
444 | +/* udev output support (print new DEVPATH) */ | |
445 | +int udev_output = 0; | |
446 | + | |
422 | 447 | /* sysfs global data */ |
423 | 448 | struct sysfs_metadata sysfs_global = |
424 | 449 | { |
@@ -449,8 +474,8 @@ if_match_ifname(const char * pattern, | ||
449 | 474 | int n; |
450 | 475 | int ret; |
451 | 476 | |
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, '*'); | |
454 | 479 | |
455 | 480 | /* No wildcard, simple comparison */ |
456 | 481 | if(p == NULL) |
@@ -473,7 +498,7 @@ if_match_ifname(const char * pattern, | ||
473 | 498 | while(isdigit(*v)); |
474 | 499 | |
475 | 500 | /* Pattern suffix */ |
476 | - p += 2; | |
501 | + p += 1; | |
477 | 502 | |
478 | 503 | /* Compare suffixes */ |
479 | 504 | return(strcmp(p, v)); |
@@ -539,6 +564,7 @@ if_set_name(int skfd, | ||
539 | 564 | char * retname) |
540 | 565 | { |
541 | 566 | struct ifreq ifr; |
567 | + char * star; | |
542 | 568 | int ret; |
543 | 569 | |
544 | 570 | /* The kernel doesn't check is the interface already has the correct |
@@ -562,6 +588,22 @@ if_set_name(int skfd, | ||
562 | 588 | strncpy(ifr.ifr_name, oldname, IFNAMSIZ); |
563 | 589 | strncpy(ifr.ifr_newname, newname, IFNAMSIZ); |
564 | 590 | |
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 | + | |
565 | 607 | /* Do it */ |
566 | 608 | ret = ioctl(skfd, SIOCSIFNAME, &ifr); |
567 | 609 |
@@ -613,7 +655,7 @@ mapping_addmac(struct if_mapping * ifnode, | ||
613 | 655 | /* Verify validity of string */ |
614 | 656 | if(len >= sizeof(ifnode->mac_filter)) |
615 | 657 | { |
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); | |
617 | 659 | return(-1); |
618 | 660 | } |
619 | 661 | n = strspn(string, "0123456789ABCDEFabcdef:*"); |
@@ -1544,6 +1586,8 @@ mapping_getsysfs(int skfd, | ||
1544 | 1586 | int flag) |
1545 | 1587 | { |
1546 | 1588 | FILE * stream; |
1589 | + char * fname; | |
1590 | + int fnsize; | |
1547 | 1591 | char * linebuf = NULL; |
1548 | 1592 | size_t linelen = 0; |
1549 | 1593 | char * sdup; |
@@ -1553,83 +1597,116 @@ mapping_getsysfs(int skfd, | ||
1553 | 1597 | skfd = skfd; |
1554 | 1598 | flag = flag; |
1555 | 1599 | |
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) | |
1558 | 1602 | { |
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) | |
1572 | 1605 | { |
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 | + } | |
1575 | 1614 | |
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) | |
1581 | 1619 | { |
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++) | |
1589 | 1636 | { |
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; | |
1593 | 1643 | } |
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 */ | |
1598 | 1663 | } |
1599 | - /* Finished -> next line */ | |
1600 | - } | |
1601 | 1664 | |
1602 | - /* Cleanup */ | |
1603 | - fclose(stream); | |
1665 | + /* Cleanup */ | |
1666 | + fclose(stream); | |
1604 | 1667 | |
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) | |
1607 | 1683 | { |
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"); | |
1610 | 1685 | return(-1); |
1611 | 1686 | } |
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; | |
1612 | 1691 | } |
1613 | 1692 | |
1614 | 1693 | /* Loop on all sysfs selector */ |
1615 | 1694 | for(findex = 0; findex < sysfs_global.filenum; findex++) |
1616 | 1695 | { |
1617 | - char * fname; | |
1618 | - int flen; | |
1619 | 1696 | char * p; |
1620 | 1697 | ssize_t n; |
1621 | 1698 | |
1622 | 1699 | /* 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); | |
1626 | 1703 | if(fname == NULL) |
1627 | 1704 | { |
1628 | 1705 | fprintf(stderr, "Error: Can't allocate SYSFS filename\n"); |
1629 | 1706 | free(linebuf); |
1630 | 1707 | return(-1); |
1631 | 1708 | } |
1632 | - sprintf(fname, "%s/class/net/%s/%s", sysfs_global.root, ifname, | |
1709 | + sprintf(fname, "%s/%s", target->sysfs_devpath, | |
1633 | 1710 | sysfs_global.filename[findex]); |
1634 | 1711 | |
1635 | 1712 | /* Open the sysfs file for reading */ |
@@ -1649,18 +1726,103 @@ mapping_getsysfs(int skfd, | ||
1649 | 1726 | fclose(stream); |
1650 | 1727 | if(n <= 0) |
1651 | 1728 | { |
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; | |
1658 | 1744 | |
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 | + } | |
1664 | 1826 | if(sdup == NULL) |
1665 | 1827 | { |
1666 | 1828 | fprintf(stderr, "Error: Can't allocate SYSFS value\n"); |
@@ -1686,6 +1848,77 @@ mapping_getsysfs(int skfd, | ||
1686 | 1848 | return(target->active[SELECT_SYSFS] ? 0 : -1); |
1687 | 1849 | } |
1688 | 1850 | |
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 | + | |
1689 | 1922 | |
1690 | 1923 | /*********************** MAPPING MANAGEMENTS ***********************/ |
1691 | 1924 | /* |
@@ -1706,8 +1939,10 @@ mapping_create(char * pos, | ||
1706 | 1939 | struct if_mapping * ifnode; |
1707 | 1940 | char * star; |
1708 | 1941 | |
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) | |
1711 | 1946 | { |
1712 | 1947 | fprintf(stderr, "Error: Interface name `%.*s' too long at line %d\n", |
1713 | 1948 | (int) len, pos, linenum); |
@@ -1738,29 +1973,6 @@ mapping_create(char * pos, | ||
1738 | 1973 | fprintf(stderr, "Warning: Alias device `%s' at line %d probably can't be mapped.\n", |
1739 | 1974 | ifnode->ifname, linenum); |
1740 | 1975 | |
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 | - | |
1764 | 1976 | if(verbose) |
1765 | 1977 | fprintf(stderr, "Parsing : Added Mapping `%s' from line %d.\n", |
1766 | 1978 | ifnode->ifname, linenum); |
@@ -2215,37 +2427,23 @@ probe_debian(int skfd) | ||
2215 | 2427 | static int |
2216 | 2428 | process_rename(int skfd, |
2217 | 2429 | char * ifname, |
2218 | - char * pattern) | |
2430 | + char * newname) | |
2219 | 2431 | { |
2220 | - char newname[IFNAMSIZ+1]; | |
2221 | 2432 | char retname[IFNAMSIZ+1]; |
2222 | 2433 | int len; |
2223 | 2434 | char * star; |
2224 | 2435 | |
2225 | - len = strlen(pattern); | |
2226 | - star = strchr(pattern, '*'); | |
2436 | + len = strlen(newname); | |
2437 | + star = strchr(newname, '*'); | |
2227 | 2438 | |
2228 | 2439 | /* Check newname length, need one extra char for wildcard */ |
2229 | 2440 | if((len + (star != NULL)) > IFNAMSIZ) |
2230 | 2441 | { |
2231 | 2442 | fprintf(stderr, "Error: Interface name `%s' too long.\n", |
2232 | - pattern); | |
2443 | + newname); | |
2233 | 2444 | return(-1); |
2234 | 2445 | } |
2235 | 2446 | |
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 | - | |
2249 | 2447 | /* Change the name of the interface */ |
2250 | 2448 | if(if_set_name(skfd, ifname, newname, retname) < 0) |
2251 | 2449 | { |
@@ -2285,6 +2483,24 @@ process_ifname(int skfd, | ||
2285 | 2483 | if(target == NULL) |
2286 | 2484 | return(-1); |
2287 | 2485 | |
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 | + | |
2288 | 2504 | /* Find matching mapping */ |
2289 | 2505 | mapping = mapping_find(target); |
2290 | 2506 | if(mapping == NULL) |
@@ -2300,26 +2516,47 @@ process_ifname(int skfd, | ||
2300 | 2516 | * That would be tricky to do... */ |
2301 | 2517 | if(dry_run) |
2302 | 2518 | { |
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); | |
2306 | 2522 | } |
2307 | - | |
2308 | - /* Change the name of the interface */ | |
2309 | - if(if_set_name(skfd, target->ifname, mapping->ifname, retname) < 0) | |
2523 | + else | |
2310 | 2524 | { |
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 | + } | |
2314 | 2532 | } |
2315 | 2533 | |
2316 | 2534 | /* Check if called with an explicit interface name */ |
2317 | 2535 | if(print_newname) |
2318 | 2536 | { |
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 | + } | |
2323 | 2560 | } |
2324 | 2561 | |
2325 | 2562 | /* Done */ |
@@ -2387,7 +2624,7 @@ main(int argc, | ||
2387 | 2624 | /* Loop over all command line options */ |
2388 | 2625 | while(1) |
2389 | 2626 | { |
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); | |
2391 | 2628 | if(c == -1) |
2392 | 2629 | break; |
2393 | 2630 |
@@ -2417,6 +2654,9 @@ main(int argc, | ||
2417 | 2654 | case 't': |
2418 | 2655 | force_takeover = 1; |
2419 | 2656 | break; |
2657 | + case 'u': | |
2658 | + udev_output = 1; | |
2659 | + break; | |
2420 | 2660 | case 'v': |
2421 | 2661 | printf("%-8.16s Wireless-Tools version %d\n", "ifrename", WT_VERSION); |
2422 | 2662 | return(0); |
@@ -2449,7 +2689,8 @@ main(int argc, | ||
2449 | 2689 | else |
2450 | 2690 | { |
2451 | 2691 | /* 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). | |
2453 | 2694 | * Process the network interface specified on the command line, |
2454 | 2695 | * and return the new name on stdout. |
2455 | 2696 | */ |
@@ -1,7 +1,7 @@ | ||
1 | -.\" Jean II - HPL - 2004 | |
1 | +.\" Jean II - HPL - 2004-2007 | |
2 | 2 | .\" iftab.5 |
3 | 3 | .\" |
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" | |
5 | 5 | .\" |
6 | 6 | .\" NAME part |
7 | 7 | .\" |
@@ -98,7 +98,9 @@ the goal is to uniquely identify each piece of hardware. | ||
98 | 98 | .PP |
99 | 99 | Most users will only use the |
100 | 100 | .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. | |
102 | 104 | .TP |
103 | 105 | .BI mac " mac address" |
104 | 106 | 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 | ||
106 | 108 | .IR ifconfig (8) |
107 | 109 | or |
108 | 110 | .IR ip (8). |
109 | -The specified MAC address may contain a '*' for wilcard matching. | |
110 | 111 | .br |
111 | 112 | This is the most common selector, as most interfaces have a unique MAC |
112 | 113 | address allowing to identify network interfaces without ambiguity. |
113 | 114 | 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. | |
115 | 116 | .TP |
116 | 117 | .BI arp " arp type" |
117 | 118 | 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 | |
119 | 121 | .IR ifconfig (8) |
120 | 122 | 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 . | |
122 | 132 | .br |
123 | 133 | This selector is useful when a driver create multiple network |
124 | 134 | interfaces for a single network card. |
@@ -159,7 +169,9 @@ not sufficient to uniquely identify an interface. | ||
159 | 169 | Matches the Wireless Protocol of the interface with the specified |
160 | 170 | wireless protocol. The Wireless Protocol of the interface can be shown |
161 | 171 | using |
162 | -.IR iwconfig (8). | |
172 | +.IR iwconfig (8) | |
173 | +or | |
174 | +.IR iwgetid (8). | |
163 | 175 | .br |
164 | 176 | This selector is only supported on wireless interfaces and is not |
165 | 177 | sufficient to uniquely identify an interface. |
@@ -174,21 +186,97 @@ This selector is usually only supported on 16 bits cards, for 32 bits | ||
174 | 186 | cards it is advised to use the selector |
175 | 187 | .BR businfo . |
176 | 188 | .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 | |
177 | 198 | .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. | |
184 | 203 | .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 | |
185 | 228 | 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. | |
188 | 276 | .\" |
189 | -.\" EXAMPLE part | |
277 | +.\" EXAMPLES part | |
190 | 278 | .\" |
191 | -.SH EXAMPLE | |
279 | +.SH EXAMPLES | |
192 | 280 | # This is a comment |
193 | 281 | .br |
194 | 282 | eth2 mac 08:00:09:DE:82:0E |
@@ -199,7 +287,11 @@ eth4 driver pcnet32 businfo 0000:02:05.0 | ||
199 | 287 | .br |
200 | 288 | air* mac 00:07:0E:* arp 1 |
201 | 289 | .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 | |
203 | 295 | .\" |
204 | 296 | .\" AUTHOR part |
205 | 297 | .\" |
@@ -1,7 +1,7 @@ | ||
1 | 1 | .\" Jean II - HPLB - 1996 => HPL - 2004 |
2 | 2 | .\" iwconfig.8 |
3 | 3 | .\" |
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" | |
5 | 5 | .\" |
6 | 6 | .\" NAME part |
7 | 7 | .\" |
@@ -21,7 +21,7 @@ iwconfig \- configure a wireless network interface | ||
21 | 21 | .br |
22 | 22 | .BI " [enc " E "] [key " K "] [power " P "] [retry " R ] |
23 | 23 | .br |
24 | -.BI " [commit] | |
24 | +.BI " [modu " M "] [commit] | |
25 | 25 | .br |
26 | 26 | .BI "iwconfig --help" |
27 | 27 | .br |
@@ -78,11 +78,10 @@ to escape it. | ||
78 | 78 | .br |
79 | 79 | .I " iwconfig eth0 essid -- ""ANY"" |
80 | 80 | .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. | |
86 | 85 | .br |
87 | 86 | This parameter is only used for pre-802.11 hardware, the 802.11 |
88 | 87 | protocol uses the ESSID and AP Address for this function. |
@@ -285,14 +284,15 @@ behaviour of the retry mechanism. | ||
285 | 284 | .br |
286 | 285 | To set the maximum number of retries, enter |
287 | 286 | .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). | |
289 | 289 | To set the maximum length of time the MAC should retry, enter |
290 | 290 | .IR "lifetime `value'" . |
291 | 291 | By defaults, this value in in seconds, append the suffix m or u to |
292 | 292 | specify values in milliseconds or microseconds. |
293 | 293 | .br |
294 | 294 | You can also add the |
295 | -.IR min " and " max | |
295 | +.IR short ", " long ", " min " and " max | |
296 | 296 | modifiers. If the card supports automatic mode, they define the bounds |
297 | 297 | of the limit or lifetime. Some other cards define different values |
298 | 298 | depending on packet size, for example in 802.11 |
@@ -305,6 +305,8 @@ is the short retry limit (non RTS/CTS packets). | ||
305 | 305 | .br |
306 | 306 | .I " iwconfig eth0 retry lifetime 300m" |
307 | 307 | .br |
308 | +.I " iwconfig eth0 retry short 12" | |
309 | +.br | |
308 | 310 | .I " iwconfig eth0 retry min limit 8" |
309 | 311 | .TP |
310 | 312 | .BR rts [_threshold] |
@@ -406,12 +408,14 @@ To set the period between wake ups, enter | ||
406 | 408 | .IR "period `value'" . |
407 | 409 | To set the timeout before going back to sleep, enter |
408 | 410 | .IR "timeout `value'" . |
411 | +To set the generic level of power saving, enter | |
412 | +.IR "saving `value'" . | |
409 | 413 | You can also add the |
410 | 414 | .IR min " and " max |
411 | 415 | modifiers. By default, those values are in seconds, append the suffix |
412 | 416 | 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). | |
415 | 419 | .br |
416 | 420 | .IR off " and " on |
417 | 421 | disable and reenable power management. Finally, you may set the power |
@@ -431,15 +435,43 @@ management mode to | ||
431 | 435 | .br |
432 | 436 | .I " iwconfig eth0 power timeout 300u all" |
433 | 437 | .br |
438 | +.I " iwconfig eth0 power saving 3" | |
439 | +.br | |
434 | 440 | .I " iwconfig eth0 power off" |
435 | 441 | .br |
436 | 442 | .I " iwconfig eth0 power min period 2 power max period 4" |
437 | 443 | .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 | |
438 | 468 | .BR commit |
439 | 469 | Some cards may not apply changes done through Wireless Extensions |
440 | 470 | 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. | |
443 | 475 | .br |
444 | 476 | This is normally not needed, because the card will eventually apply |
445 | 477 | the changes, but can be useful for debugging. |
@@ -1,48 +1,37 @@ | ||
1 | 1 | /* |
2 | 2 | * Wireless Tools |
3 | 3 | * |
4 | - * Jean II - HPLB 97->99 - HPL 99->04 | |
4 | + * Jean II - HPLB 97->99 - HPL 99->07 | |
5 | 5 | * |
6 | 6 | * Main code for "iwconfig". This is the generic tool for most |
7 | 7 | * manipulations... |
8 | 8 | * You need to link this code against "iwlib.c" and "-lm". |
9 | 9 | * |
10 | 10 | * 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> | |
12 | 12 | */ |
13 | 13 | |
14 | 14 | #include "iwlib.h" /* Header */ |
15 | 15 | |
16 | -/************************* MISC SUBROUTINES **************************/ | |
16 | +/**************************** CONSTANTS ****************************/ | |
17 | 17 | |
18 | -/*------------------------------------------------------------------*/ | |
19 | 18 | /* |
20 | - * Print usage string | |
19 | + * Error codes defined for setting args | |
21 | 20 | */ |
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 ****************************/ | |
45 | 29 | |
30 | +/* | |
31 | + * Ugly, but deal with errors in set_info() efficiently... | |
32 | + */ | |
33 | +static int errarg; | |
34 | +static int errmax; | |
46 | 35 | |
47 | 36 | /************************* DISPLAY ROUTINES **************************/ |
48 | 37 |
@@ -79,13 +68,6 @@ get_info(int skfd, | ||
79 | 68 | if(iw_get_range_info(skfd, ifname, &(info->range)) >= 0) |
80 | 69 | info->has_range = 1; |
81 | 70 | |
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 | - | |
89 | 71 | /* Get AP address */ |
90 | 72 | if(iw_get_ext(skfd, ifname, SIOCGIWAP, &wrq) >= 0) |
91 | 73 | { |
@@ -93,14 +75,6 @@ get_info(int skfd, | ||
93 | 75 | memcpy(&(info->ap_addr), &(wrq.u.ap_addr), sizeof (sockaddr)); |
94 | 76 | } |
95 | 77 | |
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 | - | |
104 | 78 | /* Get bit rate */ |
105 | 79 | if(iw_get_ext(skfd, ifname, SIOCGIWRATE, &wrq) >= 0) |
106 | 80 | { |
@@ -108,20 +82,6 @@ get_info(int skfd, | ||
108 | 82 | memcpy(&(info->bitrate), &(wrq.u.bitrate), sizeof(iwparam)); |
109 | 83 | } |
110 | 84 | |
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 | - | |
125 | 85 | /* Get Power Management settings */ |
126 | 86 | wrq.u.power.flags = 0; |
127 | 87 | if(iw_get_ext(skfd, ifname, SIOCGIWPOWER, &wrq) >= 0) |
@@ -130,6 +90,22 @@ get_info(int skfd, | ||
130 | 90 | memcpy(&(info->power), &(wrq.u.power), sizeof(iwparam)); |
131 | 91 | } |
132 | 92 | |
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 | + | |
133 | 109 | if((info->has_range) && (info->range.we_version_compiled > 9)) |
134 | 110 | { |
135 | 111 | /* Get Transmit Power */ |
@@ -140,6 +116,13 @@ get_info(int skfd, | ||
140 | 116 | } |
141 | 117 | } |
142 | 118 | |
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 | + | |
143 | 126 | if((info->has_range) && (info->range.we_version_compiled > 10)) |
144 | 127 | { |
145 | 128 | /* Get retry limit/lifetime */ |
@@ -150,44 +133,20 @@ get_info(int skfd, | ||
150 | 133 | } |
151 | 134 | } |
152 | 135 | |
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) | |
156 | 138 | { |
157 | - info->has_stats = 1; | |
139 | + info->has_rts = 1; | |
140 | + memcpy(&(info->rts), &(wrq.u.rts), sizeof(iwparam)); | |
158 | 141 | } |
159 | 142 | |
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) | |
168 | 145 | { |
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)); | |
189 | 148 | } |
190 | -#endif | |
149 | +#endif /* WE_ESSENTIAL */ | |
191 | 150 | |
192 | 151 | return(0); |
193 | 152 | } |
@@ -225,9 +184,11 @@ display_info(struct wireless_info * info, | ||
225 | 184 | printf("ESSID:off/any "); |
226 | 185 | } |
227 | 186 | |
187 | +#ifndef WE_ESSENTIAL | |
228 | 188 | /* Display NickName (station name), if any */ |
229 | 189 | if(info->has_nickname) |
230 | 190 | printf("Nickname:\"%s\"", info->nickname); |
191 | +#endif /* WE_ESSENTIAL */ | |
231 | 192 | |
232 | 193 | /* Formatting */ |
233 | 194 | if(info->b.has_essid || info->has_nickname) |
@@ -236,6 +197,7 @@ display_info(struct wireless_info * info, | ||
236 | 197 | tokens = 0; |
237 | 198 | } |
238 | 199 | |
200 | +#ifndef WE_ESSENTIAL | |
239 | 201 | /* Display Network ID */ |
240 | 202 | if(info->b.has_nwid) |
241 | 203 | { |
@@ -247,6 +209,7 @@ display_info(struct wireless_info * info, | ||
247 | 209 | printf("NWID:%X ", info->b.nwid.value); |
248 | 210 | tokens +=2; |
249 | 211 | } |
212 | +#endif /* WE_ESSENTIAL */ | |
250 | 213 | |
251 | 214 | /* Display the current mode of operation */ |
252 | 215 | if(info->b.has_mode) |
@@ -306,6 +269,7 @@ display_info(struct wireless_info * info, | ||
306 | 269 | printf("Bit Rate%c%s ", (info->bitrate.fixed ? '=' : ':'), buffer); |
307 | 270 | } |
308 | 271 | |
272 | +#ifndef WE_ESSENTIAL | |
309 | 273 | /* Display the Transmit Power */ |
310 | 274 | if(info->has_txpower) |
311 | 275 | { |
@@ -334,10 +298,7 @@ display_info(struct wireless_info * info, | ||
334 | 298 | tokens +=4; |
335 | 299 | |
336 | 300 | /* Fixed ? */ |
337 | - if(info->sens.fixed) | |
338 | - printf("Sensitivity="); | |
339 | - else | |
340 | - printf("Sensitivity:"); | |
301 | + printf("Sensitivity%c", info->sens.fixed ? '=' : ':'); | |
341 | 302 | |
342 | 303 | if(info->has_range) |
343 | 304 | /* Display in dBm ? */ |
@@ -348,10 +309,12 @@ display_info(struct wireless_info * info, | ||
348 | 309 | else |
349 | 310 | printf("%d ", info->sens.value); |
350 | 311 | } |
312 | +#endif /* WE_ESSENTIAL */ | |
351 | 313 | |
352 | 314 | printf("\n "); |
353 | 315 | tokens = 0; |
354 | 316 | |
317 | +#ifndef WE_ESSENTIAL | |
355 | 318 | /* Display retry limit/lifetime information */ |
356 | 319 | if(info->has_retry) |
357 | 320 | { |
@@ -365,7 +328,8 @@ display_info(struct wireless_info * info, | ||
365 | 328 | if(info->retry.flags & IW_RETRY_TYPE) |
366 | 329 | { |
367 | 330 | 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); | |
369 | 333 | printf("%s", buffer); |
370 | 334 | } |
371 | 335 |
@@ -386,12 +350,9 @@ display_info(struct wireless_info * info, | ||
386 | 350 | else |
387 | 351 | { |
388 | 352 | /* 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); | |
395 | 356 | } |
396 | 357 | tokens += 3; |
397 | 358 | } |
@@ -413,18 +374,16 @@ display_info(struct wireless_info * info, | ||
413 | 374 | else |
414 | 375 | { |
415 | 376 | /* 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); | |
422 | 380 | } |
423 | 381 | } |
424 | 382 | |
425 | 383 | /* Formating */ |
426 | 384 | if(tokens > 0) |
427 | 385 | printf("\n "); |
386 | +#endif /* WE_ESSENTIAL */ | |
428 | 387 | |
429 | 388 | /* Display encryption information */ |
430 | 389 | /* Note : we display only the "current" key, use iwlist to list all keys */ |
@@ -451,22 +410,6 @@ display_info(struct wireless_info * info, | ||
451 | 410 | printf("\n "); |
452 | 411 | } |
453 | 412 | |
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 | - | |
470 | 413 | /* Display Power Management information */ |
471 | 414 | /* Note : we display only one parameter, period or timeout. If a device |
472 | 415 | * (such as HiperLan) has both, the user need to use iwlist... */ |
@@ -482,7 +425,8 @@ display_info(struct wireless_info * info, | ||
482 | 425 | if(info->power.flags & IW_POWER_TYPE) |
483 | 426 | { |
484 | 427 | 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); | |
486 | 430 | printf("%s ", buffer); |
487 | 431 | } |
488 | 432 |
@@ -558,864 +502,1403 @@ print_info(int skfd, | ||
558 | 502 | return(rc); |
559 | 503 | } |
560 | 504 | |
561 | -/************************* SETTING ROUTINES **************************/ | |
505 | +/****************** COMMAND LINE MODIFIERS PARSING ******************/ | |
506 | +/* | |
507 | + * Factor out the parsing of command line modifiers. | |
508 | + */ | |
562 | 509 | |
563 | 510 | /*------------------------------------------------------------------*/ |
564 | 511 | /* |
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... | |
569 | 513 | */ |
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; | |
594 | 519 | |
595 | 520 | /*------------------------------------------------------------------*/ |
596 | 521 | /* |
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 | |
599 | 523 | */ |
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])) | |
608 | 532 | |
609 | 533 | /*------------------------------------------------------------------*/ |
610 | 534 | /* |
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 | |
613 | 536 | */ |
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 */ | |
622 | 548 | |
623 | 549 | /*------------------------------------------------------------------*/ |
624 | 550 | /* |
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. | |
629 | 554 | */ |
630 | 555 | 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) | |
635 | 561 | { |
636 | - struct iwreq wrq; | |
637 | - int i; | |
562 | + int i = 0; | |
563 | + int k = 0; | |
564 | + __u16 result = 0; /* Default : no flag set */ | |
638 | 565 | |
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 | |
641 | 568 | { |
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 | + } | |
644 | 586 | } |
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 | + */ | |
645 | 609 | |
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"))) | |
648 | 627 | { |
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; | |
657 | 666 | |
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)) | |
670 | 675 | { |
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; | |
675 | 678 | } |
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 | + } | |
689 | 681 | |
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(); | |
695 | 684 | |
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++; | |
720 | 690 | |
721 | - iw_float2freq(freq, &(wrq.u.freq)); | |
691 | + if(iw_set_ext(skfd, ifname, SIOCSIWESSID, &wrq) < 0) | |
692 | + return(IWERR_SET_EXT); | |
722 | 693 | |
723 | - wrq.u.freq.flags = IW_FREQ_FIXED; | |
694 | + /* Var args */ | |
695 | + return(i); | |
696 | +} | |
724 | 697 | |
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 */ | |
740 | 710 | |
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; | |
745 | 748 | |
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")) | |
748 | 758 | { |
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; | |
757 | 763 | } |
758 | - | |
759 | - /* ---------- Set encryption stuff ---------- */ | |
760 | - if((!strncmp(args[i], "enc", 3)) || | |
761 | - (!strcmp(args[i], "key"))) | |
764 | + else /* Should be a numeric value */ | |
762 | 765 | { |
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; | |
767 | 768 | |
768 | - if(!strcasecmp(args[i], "on")) | |
769 | + freq = strtod(args[0], &unit); | |
770 | + if(unit == args[0]) | |
769 | 771 | { |
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); | |
777 | 774 | } |
778 | - else | |
775 | + if(unit != NULL) | |
779 | 776 | { |
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 | + } | |
817 | 781 | |
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)); | |
845 | 783 | |
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; | |
849 | 785 | |
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; | |
855 | 791 | } |
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"))) | |
873 | 793 | { |
874 | - wrq.u.essid.flags = 0; | |
875 | - essid[0] = '\0'; | |
794 | + wrq.u.freq.flags = IW_FREQ_FIXED; | |
795 | + ++i; | |
876 | 796 | } |
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 | + } | |
900 | 799 | |
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); | |
908 | 802 | |
909 | - wrq.u.essid.flags = 1; | |
910 | - strcpy(essid, args[i]); /* Size checked, all clear */ | |
803 | + /* Var args */ | |
804 | + return(i); | |
805 | +} | |
911 | 806 | |
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; | |
922 | 819 | |
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; | |
934 | 834 | } |
935 | - | |
936 | - /* ---------- Set AP address ---------- */ | |
937 | - if(!strcasecmp(args[i], "ap")) | |
835 | + else /* Should be a numeric value */ | |
938 | 836 | { |
939 | - if(++i >= count) | |
940 | - ABORT_ARG_NUM("Set AP Address", SIOCSIWAP); | |
837 | + double brate; | |
838 | + char * unit; | |
941 | 839 | |
942 | - if((!strcasecmp(args[i], "auto")) || | |
943 | - (!strcasecmp(args[i], "any"))) | |
840 | + brate = strtod(args[0], &unit); | |
841 | + if(unit == args[0]) | |
944 | 842 | { |
945 | - /* Send a broadcast address */ | |
946 | - iw_broad_ether(&(wrq.u.ap_addr)); | |
843 | + errarg = 0; | |
844 | + return(IWERR_ARG_TYPE); | |
947 | 845 | } |
948 | - else | |
846 | + if(unit != NULL) | |
949 | 847 | { |
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; | |
961 | 851 | } |
852 | + wrq.u.bitrate.value = (long) brate; | |
853 | + wrq.u.bitrate.fixed = 1; | |
962 | 854 | |
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"))) | |
997 | 857 | { |
998 | - wrq.u.bitrate.value = -1; | |
999 | 858 | wrq.u.bitrate.fixed = 0; |
859 | + ++i; | |
1000 | 860 | } |
1001 | - else | |
861 | + if((i < count) && (!strcasecmp(args[i], "fixed"))) | |
1002 | 862 | { |
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; | |
1036 | 875 | } |
1037 | - | |
1038 | - IW_SET_EXT_ERR(skfd, ifname, SIOCSIWRATE, &wrq, | |
1039 | - "Set Bit Rate"); | |
1040 | - continue; | |
1041 | 876 | } |
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]; | |
1042 | 899 | |
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 | |
1045 | 924 | { |
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 | + } | |
1070 | 939 | } |
1071 | 940 | |
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 | + } | |
1075 | 976 | } |
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; | |
1076 | 982 | |
1077 | - /* ---------- Set fragmentation threshold ---------- */ | |
1078 | - if(!strncmp(args[i], "frag", 4)) | |
983 | + /* Check if we have any invalid argument */ | |
984 | + if(!gotone) | |
1079 | 985 | { |
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 | + } | |
1091 | 1067 | else |
1092 | 1068 | { |
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 | +} | |
1107 | 1113 | |
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; | |
1112 | 1130 | |
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) | |
1115 | 1180 | { |
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 | + } | |
1117 | 1189 | |
1118 | - i++; | |
1119 | - if(i >= count) | |
1120 | - ABORT_ARG_NUM("Set Mode", SIOCSIWMODE); | |
1190 | + wrq.u.nwid.fixed = 1; | |
1121 | 1191 | |
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) | |
1123 | 1232 | { |
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); | |
1128 | 1235 | } |
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; | |
1136 | 1236 | } |
1237 | + } | |
1137 | 1238 | |
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); | |
1143 | 1241 | |
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")) | |
1148 | 1285 | { |
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; | |
1154 | 1291 | } |
1155 | - else | |
1292 | + else /* Should be a numeric value */ | |
1156 | 1293 | { |
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) | |
1165 | 1304 | { |
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); | |
1169 | 1307 | } |
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 | - } | |
1177 | 1308 | |
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) | |
1180 | 1319 | { |
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; | |
1184 | 1327 | } |
1185 | 1328 | 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 | |
1187 | 1336 | { |
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; | |
1191 | 1340 | } |
1341 | + wrq.u.txpower.value = power; | |
1192 | 1342 | |
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"))) | |
1195 | 1345 | { |
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; | |
1202 | 1347 | ++i; |
1203 | - gotone = 1; | |
1204 | 1348 | } |
1205 | - | |
1206 | - /* Now, check the mode */ | |
1207 | - if(i < count) | |
1349 | + if((i < count) && (!strcasecmp(args[i], "fixed"))) | |
1208 | 1350 | { |
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; | |
1224 | 1353 | } |
1225 | - if(!gotone) | |
1226 | - ABORT_ARG_TYPE("Set Power Management", SIOCSIWPOWER, | |
1227 | - args[i]); | |
1228 | - --i; | |
1229 | 1354 | } |
1355 | + } | |
1356 | + } | |
1357 | + | |
1358 | + if(iw_set_ext(skfd, ifname, SIOCSIWTXPOW, &wrq) < 0) | |
1359 | + return(IWERR_SET_EXT); | |
1230 | 1360 | |
1231 | - IW_SET_EXT_ERR(skfd, ifname, SIOCSIWPOWER, &wrq, | |
1232 | - "Set Power Management"); | |
1233 | - continue; | |
1234 | - } | |
1361 | + /* Var args */ | |
1362 | + return(i); | |
1363 | +} | |
1235 | 1364 | |
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) | |
1238 | 1439 | { |
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; | |
1255 | 1442 | 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; | |
1339 | 1444 | } |
1340 | - | |
1341 | - /* ---------- Set Retry limit ---------- */ | |
1342 | - if(!strncmp(args[i], "retry", 3)) | |
1445 | + else | |
1343 | 1446 | { |
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; | |
1346 | 1455 | |
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); | |
1349 | 1458 | |
1350 | - /* Default - nope */ | |
1351 | - wrq.u.retry.flags = IW_RETRY_LIMIT; | |
1352 | - wrq.u.retry.disabled = 0; | |
1459 | + /* Var args */ | |
1460 | + return(i); | |
1461 | +} | |
1353 | 1462 | |
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) | |
1363 | 1500 | { |
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); | |
1367 | 1503 | } |
1504 | + wrq.u.rts.value = temp; | |
1505 | + } | |
1506 | + } | |
1368 | 1507 | |
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) | |
1378 | 1553 | { |
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); | |
1383 | 1556 | } |
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; | |
1384 | 1598 | |
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 | |
1387 | 1603 | { |
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++) | |
1390 | 1605 | { |
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 | + } | |
1395 | 1612 | } |
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; | |
1397 | 1633 | ++i; |
1398 | - gotone = 1; | |
1399 | 1634 | } |
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 | +} | |
1400 | 1667 | |
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 | + */ | |
1404 | 1684 | |
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); | |
1408 | 1813 | } |
1409 | 1814 | |
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 */ | |
1416 | 1882 | return(0); |
1417 | 1883 | } |
1418 | 1884 | |
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 | + | |
1419 | 1902 | /******************************* MAIN ********************************/ |
1420 | 1903 | |
1421 | 1904 | /*------------------------------------------------------------------*/ |
@@ -1,12 +1,12 @@ | ||
1 | 1 | /* |
2 | 2 | * Wireless Tools |
3 | 3 | * |
4 | - * Jean II - HPLB 97->99 - HPL 99->04 | |
4 | + * Jean II - HPLB 97->99 - HPL 99->07 | |
5 | 5 | * |
6 | 6 | * Common subroutines to all the wireless tools... |
7 | 7 | * |
8 | 8 | * 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> | |
10 | 10 | */ |
11 | 11 | |
12 | 12 | /***************************** INCLUDES *****************************/ |
@@ -99,7 +99,44 @@ const char * const iw_operation_mode[] = { "Auto", | ||
99 | 99 | "Master", |
100 | 100 | "Repeater", |
101 | 101 | "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 | +}; | |
103 | 140 | |
104 | 141 | /* Disable runtime version warning in iw_get_range_info() */ |
105 | 142 | int iw_ignore_version = 0; |
@@ -407,7 +444,7 @@ iw_print_version_info(const char * toolname) | ||
407 | 444 | if(toolname != NULL) |
408 | 445 | printf("%-8.16s Wireless-Tools version %d\n", toolname, WT_VERSION); |
409 | 446 | printf(" Compatible with Wireless Extension v11 to v%d.\n\n", |
410 | - WE_VERSION); | |
447 | + WE_MAX_VERSION); | |
411 | 448 | |
412 | 449 | /* Get version from kernel */ |
413 | 450 | we_kernel_version = iw_get_kernel_we_version(); |
@@ -521,7 +558,7 @@ iw_get_range_info(int skfd, | ||
521 | 558 | if(range->we_version_compiled > WE_MAX_VERSION) |
522 | 559 | { |
523 | 560 | 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); | |
525 | 562 | fprintf(stderr, "Some things may be broken...\n\n"); |
526 | 563 | } |
527 | 564 |
@@ -681,9 +718,12 @@ iw_get_basic_config(int skfd, | ||
681 | 718 | /* Get operation mode */ |
682 | 719 | if(iw_get_ext(skfd, ifname, SIOCGIWMODE, &wrq) >= 0) |
683 | 720 | { |
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 */ | |
687 | 727 | } |
688 | 728 | |
689 | 729 | return(0); |
@@ -802,10 +842,10 @@ iw_set_basic_config(int skfd, | ||
802 | 842 | we_kernel_version = iw_get_kernel_we_version(); |
803 | 843 | |
804 | 844 | 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); | |
806 | 846 | 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++; | |
809 | 849 | |
810 | 850 | if(iw_set_ext(skfd, ifname, SIOCSIWESSID, &wrq) < 0) |
811 | 851 | { |
@@ -1320,7 +1360,9 @@ iw_print_stats(char * buffer, | ||
1320 | 1360 | * Further, on 8 bits, 0x100 == 256 == 0. |
1321 | 1361 | * |
1322 | 1362 | * 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). | |
1324 | 1366 | * |
1325 | 1367 | * How do we separate relative from absolute values ? |
1326 | 1368 | * 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, | ||
1329 | 1371 | * range struct only specify one bound of the value, we assume that |
1330 | 1372 | * the other bound is 0 (zero). |
1331 | 1373 | * 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]. | |
1333 | 1375 | * |
1334 | 1376 | * Let's take two example : |
1335 | 1377 | * 1) value is 75%. qual->value = 75 ; range->max_qual.value = 100 |
@@ -1343,7 +1385,8 @@ iw_print_stats(char * buffer, | ||
1343 | 1385 | * The old way to detect dBm require both the range and a non-null |
1344 | 1386 | * level (which confuse the test). The new way can deal with level of 0 |
1345 | 1387 | * 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)))) | |
1347 | 1390 | { |
1348 | 1391 | /* Deal with quality : always a relative value */ |
1349 | 1392 | if(!(qual->updated & IW_QUAL_QUAL_INVALID)) |
@@ -1355,16 +1398,17 @@ iw_print_stats(char * buffer, | ||
1355 | 1398 | buflen -= len; |
1356 | 1399 | } |
1357 | 1400 | |
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) | |
1361 | 1403 | { |
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 */ | |
1363 | 1406 | if(!(qual->updated & IW_QUAL_LEVEL_INVALID)) |
1364 | 1407 | { |
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 ", | |
1366 | 1410 | qual->updated & IW_QUAL_LEVEL_UPDATED ? '=' : ':', |
1367 | - qual->level - 0x100); | |
1411 | + rcpilevel); | |
1368 | 1412 | buffer += len; |
1369 | 1413 | buflen -= len; |
1370 | 1414 | } |
@@ -1372,29 +1416,63 @@ iw_print_stats(char * buffer, | ||
1372 | 1416 | /* Deal with noise level in dBm (absolute power measurement) */ |
1373 | 1417 | if(!(qual->updated & IW_QUAL_NOISE_INVALID)) |
1374 | 1418 | { |
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", | |
1376 | 1421 | qual->updated & IW_QUAL_NOISE_UPDATED ? '=' : ':', |
1377 | - qual->noise - 0x100); | |
1422 | + rcpinoise); | |
1378 | 1423 | } |
1379 | 1424 | } |
1380 | 1425 | else |
1381 | 1426 | { |
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)) | |
1384 | 1430 | { |
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 | + } | |
1391 | 1444 | |
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 | |
1394 | 1458 | { |
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 | + } | |
1398 | 1476 | } |
1399 | 1477 | } |
1400 | 1478 | } |
@@ -1644,7 +1722,8 @@ void | ||
1644 | 1722 | iw_print_pm_value(char * buffer, |
1645 | 1723 | int buflen, |
1646 | 1724 | int value, |
1647 | - int flags) | |
1725 | + int flags, | |
1726 | + int we_version) | |
1648 | 1727 | { |
1649 | 1728 | /* Check size */ |
1650 | 1729 | if(buflen < 25) |
@@ -1674,13 +1753,25 @@ iw_print_pm_value(char * buffer, | ||
1674 | 1753 | } |
1675 | 1754 | else |
1676 | 1755 | { |
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 | + } | |
1679 | 1766 | } |
1680 | 1767 | |
1681 | 1768 | /* Display value without units */ |
1682 | 1769 | 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 | + } | |
1684 | 1775 | else |
1685 | 1776 | { |
1686 | 1777 | /* Display value with units */ |
@@ -1744,15 +1835,16 @@ void | ||
1744 | 1835 | iw_print_retry_value(char * buffer, |
1745 | 1836 | int buflen, |
1746 | 1837 | int value, |
1747 | - int flags) | |
1838 | + int flags, | |
1839 | + int we_version) | |
1748 | 1840 | { |
1749 | 1841 | /* Check buffer size */ |
1750 | - if(buflen < 18) | |
1842 | + if(buflen < 20) | |
1751 | 1843 | { |
1752 | 1844 | snprintf(buffer, buflen, "<too big>"); |
1753 | 1845 | return; |
1754 | 1846 | } |
1755 | - buflen -= 18; | |
1847 | + buflen -= 20; | |
1756 | 1848 | |
1757 | 1849 | /* Modifiers */ |
1758 | 1850 | if(flags & IW_RETRY_MIN) |
@@ -1765,6 +1857,16 @@ iw_print_retry_value(char * buffer, | ||
1765 | 1857 | strcpy(buffer, " max"); /* Size checked */ |
1766 | 1858 | buffer += 4; |
1767 | 1859 | } |
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 | + } | |
1768 | 1870 | |
1769 | 1871 | /* Type lifetime of limit */ |
1770 | 1872 | if(flags & IW_RETRY_LIFETIME) |
@@ -1773,8 +1875,12 @@ iw_print_retry_value(char * buffer, | ||
1773 | 1875 | buffer += 10; |
1774 | 1876 | |
1775 | 1877 | /* 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 | + } | |
1778 | 1884 | else |
1779 | 1885 | { |
1780 | 1886 | /* Display value with units */ |
@@ -2125,7 +2231,7 @@ iw_in_addr(int skfd, | ||
2125 | 2231 | struct sockaddr *sap) |
2126 | 2232 | { |
2127 | 2233 | /* Check if it is a hardware or IP address */ |
2128 | - if(index(bufp, ':') == NULL) | |
2234 | + if(strchr(bufp, ':') == NULL) | |
2129 | 2235 | { |
2130 | 2236 | struct sockaddr if_address; |
2131 | 2237 | struct arpreq arp_query; |
@@ -2467,6 +2573,12 @@ static const struct iw_ioctl_description standard_ioctl_descr[] = { | ||
2467 | 2573 | [SIOCGIWPOWER - SIOCIWFIRST] = { |
2468 | 2574 | .header_type = IW_HEADER_TYPE_PARAM, |
2469 | 2575 | }, |
2576 | + [SIOCSIWMODUL - SIOCIWFIRST] = { | |
2577 | + .header_type = IW_HEADER_TYPE_PARAM, | |
2578 | + }, | |
2579 | + [SIOCGIWMODUL - SIOCIWFIRST] = { | |
2580 | + .header_type = IW_HEADER_TYPE_PARAM, | |
2581 | + }, | |
2470 | 2582 | [SIOCSIWGENIE - SIOCIWFIRST] = { |
2471 | 2583 | .header_type = IW_HEADER_TYPE_POINT, |
2472 | 2584 | .token_size = 1, |
@@ -2560,17 +2672,17 @@ static const unsigned int standard_event_num = (sizeof(standard_event_descr) / | ||
2560 | 2672 | |
2561 | 2673 | /* Size (in bytes) of various events */ |
2562 | 2674 | 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 */ | |
2564 | 2676 | 0, |
2565 | - IW_EV_CHAR_LEN, /* IW_HEADER_TYPE_CHAR */ | |
2677 | + IW_EV_CHAR_PK_LEN, /* IW_HEADER_TYPE_CHAR */ | |
2566 | 2678 | 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 */ | |
2570 | 2682 | 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 */ | |
2574 | 2686 | }; |
2575 | 2687 | |
2576 | 2688 | /*------------------------------------------------------------------*/ |
@@ -2607,29 +2719,26 @@ iw_extract_event_stream(struct stream_descr * stream, /* Stream of events */ | ||
2607 | 2719 | /* Don't "optimise" the following variable, it will crash */ |
2608 | 2720 | unsigned cmd_index; /* *MUST* be unsigned */ |
2609 | 2721 | |
2610 | - /* Unused for now. Will be later on... */ | |
2611 | - we_version = we_version; | |
2612 | - | |
2613 | 2722 | /* 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) | |
2615 | 2724 | return(0); |
2616 | 2725 | |
2617 | -#if DEBUG | |
2726 | +#ifdef DEBUG | |
2618 | 2727 | printf("DBG - stream->current = %p, stream->value = %p, stream->end = %p\n", |
2619 | 2728 | stream->current, stream->value, stream->end); |
2620 | 2729 | #endif |
2621 | 2730 | |
2622 | 2731 | /* Extract the event header (to get the event id). |
2623 | 2732 | * 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); | |
2625 | 2734 | |
2626 | -#if DEBUG | |
2735 | +#ifdef DEBUG | |
2627 | 2736 | printf("DBG - iwe->cmd = 0x%X, iwe->len = %d\n", |
2628 | 2737 | iwe->cmd, iwe->len); |
2629 | 2738 | #endif |
2630 | 2739 | |
2631 | 2740 | /* Check invalid events */ |
2632 | - if(iwe->len <= IW_EV_LCP_LEN) | |
2741 | + if(iwe->len <= IW_EV_LCP_PK_LEN) | |
2633 | 2742 | return(-1); |
2634 | 2743 | |
2635 | 2744 | /* Get the type and length of that event */ |
@@ -2647,28 +2756,28 @@ iw_extract_event_stream(struct stream_descr * stream, /* Stream of events */ | ||
2647 | 2756 | } |
2648 | 2757 | if(descr != NULL) |
2649 | 2758 | 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 */ | |
2651 | 2760 | event_len = event_type_size[event_type]; |
2652 | 2761 | /* Fixup for earlier version of WE */ |
2653 | 2762 | if((we_version <= 18) && (event_type == IW_HEADER_TYPE_POINT)) |
2654 | 2763 | event_len += IW_EV_POINT_OFF; |
2655 | 2764 | |
2656 | 2765 | /* Check if we know about this event */ |
2657 | - if(event_len <= IW_EV_LCP_LEN) | |
2766 | + if(event_len <= IW_EV_LCP_PK_LEN) | |
2658 | 2767 | { |
2659 | 2768 | /* Skip to next event */ |
2660 | 2769 | stream->current += iwe->len; |
2661 | 2770 | return(2); |
2662 | 2771 | } |
2663 | - event_len -= IW_EV_LCP_LEN; | |
2772 | + event_len -= IW_EV_LCP_PK_LEN; | |
2664 | 2773 | |
2665 | 2774 | /* Set pointer on data */ |
2666 | 2775 | if(stream->value != NULL) |
2667 | 2776 | pointer = stream->value; /* Next value in event */ |
2668 | 2777 | 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 */ | |
2670 | 2779 | |
2671 | -#if DEBUG | |
2780 | +#ifdef DEBUG | |
2672 | 2781 | printf("DBG - event_type = %d, event_len = %d, pointer = %p\n", |
2673 | 2782 | event_type, event_len, pointer); |
2674 | 2783 | #endif |
@@ -2681,6 +2790,7 @@ iw_extract_event_stream(struct stream_descr * stream, /* Stream of events */ | ||
2681 | 2790 | return(-2); |
2682 | 2791 | } |
2683 | 2792 | /* Fixup for WE-19 and later : pointer no longer in the stream */ |
2793 | + /* Beware of alignement. Dest has local alignement, not packed */ | |
2684 | 2794 | if((we_version > 18) && (event_type == IW_HEADER_TYPE_POINT)) |
2685 | 2795 | memcpy((char *) iwe + IW_EV_LCP_LEN + IW_EV_POINT_OFF, |
2686 | 2796 | pointer, event_len); |
@@ -2694,7 +2804,7 @@ iw_extract_event_stream(struct stream_descr * stream, /* Stream of events */ | ||
2694 | 2804 | if(event_type == IW_HEADER_TYPE_POINT) |
2695 | 2805 | { |
2696 | 2806 | /* 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); | |
2698 | 2808 | if(extra_len > 0) |
2699 | 2809 | { |
2700 | 2810 | /* Set pointer on variable part (warning : non aligned) */ |
@@ -2709,9 +2819,35 @@ iw_extract_event_stream(struct stream_descr * stream, /* Stream of events */ | ||
2709 | 2819 | /* Those checks are actually pretty hard to trigger, |
2710 | 2820 | * because of the checks done in the kernel... */ |
2711 | 2821 | |
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 | + | |
2712 | 2849 | /* Discard bogus events which advertise more tokens than |
2713 | 2850 | * what they carry... */ |
2714 | - unsigned int token_len = iwe->u.data.length * descr->token_size; | |
2715 | 2851 | if(token_len > extra_len) |
2716 | 2852 | iwe->u.data.pointer = NULL; /* Discard paylod */ |
2717 | 2853 | /* 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 */ | ||
2722 | 2858 | /* Same for underflows... */ |
2723 | 2859 | if(iwe->u.data.length < descr->min_tokens) |
2724 | 2860 | iwe->u.data.pointer = NULL; /* Discard paylod */ |
2725 | -#if DEBUG | |
2861 | +#ifdef DEBUG | |
2726 | 2862 | printf("DBG - extra_len = %d, token_len = %d, token = %d, max = %d, min = %d\n", |
2727 | 2863 | extra_len, token_len, iwe->u.data.length, descr->max_tokens, descr->min_tokens); |
2728 | 2864 | #endif |
@@ -2737,6 +2873,25 @@ iw_extract_event_stream(struct stream_descr * stream, /* Stream of events */ | ||
2737 | 2873 | } |
2738 | 2874 | else |
2739 | 2875 | { |
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 | + | |
2740 | 2895 | /* Is there more value in the event ? */ |
2741 | 2896 | if((pointer + event_len) <= (stream->current + iwe->len)) |
2742 | 2897 | /* Go to next value */ |
@@ -2847,8 +3002,14 @@ iw_process_scanning_token(struct iw_event * event, | ||
2847 | 3002 | memcpy(&wscan->stats.qual, &event->u.qual, sizeof(struct iw_quality)); |
2848 | 3003 | break; |
2849 | 3004 | 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 | + } | |
2852 | 3013 | case IWEVCUSTOM: |
2853 | 3014 | /* How can we deal with those sanely ? Jean II */ |
2854 | 3015 | default: |
@@ -2893,7 +3054,9 @@ iw_process_scan(int skfd, | ||
2893 | 3054 | wrq.u.data.pointer = NULL; /* Later */ |
2894 | 3055 | wrq.u.data.flags = 0; |
2895 | 3056 | 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)) | |
2897 | 3060 | return(-1); |
2898 | 3061 | /* Success : now, just wait for event or results */ |
2899 | 3062 | return(250); /* Wait 250 ms */ |
@@ -2959,7 +3122,7 @@ iw_process_scan(int skfd, | ||
2959 | 3122 | struct stream_descr stream; |
2960 | 3123 | struct wireless_scan * wscan = NULL; |
2961 | 3124 | int ret; |
2962 | -#if DEBUG | |
3125 | +#ifdef DEBUG | |
2963 | 3126 | /* Debugging code. In theory useless, because it's debugged ;-) */ |
2964 | 3127 | int i; |
2965 | 3128 | printf("Scan result [%02X", buffer[0]); |
@@ -1,12 +1,12 @@ | ||
1 | 1 | /* |
2 | 2 | * Wireless Tools |
3 | 3 | * |
4 | - * Jean II - HPLB 97->99 - HPL 99->04 | |
4 | + * Jean II - HPLB 97->99 - HPL 99->07 | |
5 | 5 | * |
6 | 6 | * Common header for the Wireless Extension library... |
7 | 7 | * |
8 | 8 | * 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> | |
10 | 10 | */ |
11 | 11 | |
12 | 12 | #ifndef IWLIB_H |
@@ -33,41 +33,17 @@ | ||
33 | 33 | #include <unistd.h> |
34 | 34 | |
35 | 35 | /* 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 | + */ | |
63 | 41 | |
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 */ | |
66 | 43 | #include <net/if_arp.h> /* For ARPHRD_ETHER */ |
67 | 44 | #include <sys/socket.h> /* For AF_INET & struct sockaddr */ |
68 | 45 | #include <netinet/in.h> /* For struct sockaddr_in */ |
69 | 46 | #include <netinet/if_ether.h> |
70 | -#endif /* HEADERS_GENERIC */ | |
71 | 47 | |
72 | 48 | /* Fixup to be able to include kernel includes in userspace. |
73 | 49 | * Basically, kill the sparse annotations... Jean II */ |
@@ -77,15 +53,9 @@ | ||
77 | 53 | |
78 | 54 | #include <linux/types.h> /* for "caddr_t" et al */ |
79 | 55 | |
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 */ | |
85 | 56 | /* Glibc systems headers are supposedly less problematic than kernel ones */ |
86 | 57 | #include <sys/socket.h> /* for "struct sockaddr" et al */ |
87 | 58 | #include <net/if.h> /* for IFNAMSIZ and co... */ |
88 | -#endif /* !HEADERS_KERNEL */ | |
89 | 59 | |
90 | 60 | /* Private copy of Wireless extensions (in this directoty) */ |
91 | 61 | #include "wireless.h" |
@@ -126,16 +96,17 @@ extern "C" { | ||
126 | 96 | |
127 | 97 | /****************************** DEBUG ******************************/ |
128 | 98 | |
99 | +//#define DEBUG 1 | |
129 | 100 | |
130 | 101 | /************************ CONSTANTS & MACROS ************************/ |
131 | 102 | |
132 | 103 | /* Various versions information */ |
133 | 104 | /* Recommended Wireless Extension version */ |
134 | -#define WE_VERSION 20 | |
105 | +#define WE_VERSION 21 | |
135 | 106 | /* Maximum forward compatibility built in this version of WT */ |
136 | -#define WE_MAX_VERSION 21 | |
107 | +#define WE_MAX_VERSION 22 | |
137 | 108 | /* Version of Wireless Tools */ |
138 | -#define WT_VERSION 28 | |
109 | +#define WT_VERSION 29 | |
139 | 110 | |
140 | 111 | /* Paths */ |
141 | 112 | #define PROC_NET_WIRELESS "/proc/net/wireless" |
@@ -153,6 +124,36 @@ extern "C" { | ||
153 | 124 | #define ARPHRD_IEEE80211 801 /* IEEE 802.11 */ |
154 | 125 | #endif /* ARPHRD_IEEE80211 */ |
155 | 126 | |
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 | + | |
156 | 157 | /****************************** TYPES ******************************/ |
157 | 158 | |
158 | 159 | /* Shortcuts */ |
@@ -244,6 +245,8 @@ typedef struct wireless_scan | ||
244 | 245 | struct wireless_config b; /* Basic information */ |
245 | 246 | iwstats stats; /* Signal strength */ |
246 | 247 | int has_stats; |
248 | + iwparam maxbitrate; /* Max bit rate in bps */ | |
249 | + int has_maxbitrate; | |
247 | 250 | } wireless_scan; |
248 | 251 | |
249 | 252 | /* |
@@ -271,6 +274,14 @@ typedef int (*iw_enum_handler)(int skfd, | ||
271 | 274 | char * args[], |
272 | 275 | int count); |
273 | 276 | |
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 | + | |
274 | 285 | /**************************** PROTOTYPES ****************************/ |
275 | 286 | /* |
276 | 287 | * All the functions in iwcommon.c |
@@ -379,7 +390,8 @@ void | ||
379 | 390 | iw_print_pm_value(char * buffer, |
380 | 391 | int buflen, |
381 | 392 | int value, |
382 | - int flags); | |
393 | + int flags, | |
394 | + int we_version); | |
383 | 395 | void |
384 | 396 | iw_print_pm_mode(char * buffer, |
385 | 397 | int buflen, |
@@ -389,7 +401,8 @@ void | ||
389 | 401 | iw_print_retry_value(char * buffer, |
390 | 402 | int buflen, |
391 | 403 | int value, |
392 | - int flags); | |
404 | + int flags, | |
405 | + int we_version); | |
393 | 406 | /* ----------------------- TIME SUBROUTINES ----------------------- */ |
394 | 407 | void |
395 | 408 | iw_print_timeval(char * buffer, |
@@ -469,6 +482,11 @@ int | ||
469 | 482 | /* Modes as human readable strings */ |
470 | 483 | extern const char * const iw_operation_mode[]; |
471 | 484 | #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 | |
472 | 490 | |
473 | 491 | /************************* INLINE FUNTIONS *************************/ |
474 | 492 | /* |
@@ -1,7 +1,7 @@ | ||
1 | 1 | .\" Jean II - HPLB - 96 |
2 | 2 | .\" iwlist.8 |
3 | 3 | .\" |
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" | |
5 | 5 | .\" |
6 | 6 | .\" NAME part |
7 | 7 | .\" |
@@ -11,21 +11,29 @@ iwlist \- Get more detailed wireless information from a wireless interface | ||
11 | 11 | .\" SYNOPSIS part |
12 | 12 | .\" |
13 | 13 | .SH SYNOPSIS |
14 | -.BI "iwlist " interface " scanning" | |
14 | +.BI "iwlist [" interface "] scanning" | |
15 | 15 | .br |
16 | -.BI "iwlist " interface " frequency" | |
16 | +.BI "iwlist [" interface "] frequency" | |
17 | 17 | .br |
18 | -.BI "iwlist " interface " rate" | |
18 | +.BI "iwlist [" interface "] rate" | |
19 | 19 | .br |
20 | -.BI "iwlist " interface " key" | |
20 | +.BI "iwlist [" interface "] keys" | |
21 | 21 | .br |
22 | -.BI "iwlist " interface " power" | |
22 | +.BI "iwlist [" interface "] power" | |
23 | 23 | .br |
24 | -.BI "iwlist " interface " txpower" | |
24 | +.BI "iwlist [" interface "] txpower" | |
25 | 25 | .br |
26 | -.BI "iwlist " interface " retry" | |
26 | +.BI "iwlist [" interface "] retry" | |
27 | 27 | .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" | |
29 | 37 | .br |
30 | 38 | .BI "iwlist --help" |
31 | 39 | .br |
@@ -58,10 +66,15 @@ the card supports. | ||
58 | 66 | Triggering scanning is a privileged operation |
59 | 67 | .RI ( root |
60 | 68 | 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. | |
65 | 78 | .TP |
66 | 79 | .BR freq [uency]/ channel |
67 | 80 | Give the list of available frequencies in the device and the number of |
@@ -73,9 +86,9 @@ displayed and channel numbers. | ||
73 | 86 | .BR rate / bit [rate] |
74 | 87 | List the bit-rates supported by the device. |
75 | 88 | .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. | |
79 | 92 | .TP |
80 | 93 | .B power |
81 | 94 | List the various Power Management attributes and modes of the device. |
@@ -100,10 +113,27 @@ the card. See your driver documentation for details. | ||
100 | 113 | .B event |
101 | 114 | List the wireless events supported by the device. |
102 | 115 | .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 | |
103 | 130 | .B --version |
104 | 131 | Display the version of the tools, as well as the recommended and |
105 | 132 | current Wireless Extensions version for the tool and the various |
106 | 133 | wireless interfaces. |
134 | +.TP | |
135 | +.B --help | |
136 | +Display short help message. | |
107 | 137 | .\" |
108 | 138 | .\" FILES part |
109 | 139 | .\" |
@@ -1,14 +1,14 @@ | ||
1 | 1 | /* |
2 | 2 | * Wireless Tools |
3 | 3 | * |
4 | - * Jean II - HPLB '99 - HPL 99->04 | |
4 | + * Jean II - HPLB '99 - HPL 99->07 | |
5 | 5 | * |
6 | 6 | * This tool can access various piece of information on the card |
7 | 7 | * not part of iwconfig... |
8 | 8 | * You need to link this code against "iwlist.c" and "-lm". |
9 | 9 | * |
10 | 10 | * 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> | |
12 | 12 | */ |
13 | 13 | |
14 | 14 | #include "iwlib.h" /* Header */ |
@@ -26,758 +26,412 @@ typedef struct iwscan_state | ||
26 | 26 | int val_index; /* Value in table 0->(N-1) */ |
27 | 27 | } iwscan_state; |
28 | 28 | |
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; | |
29 | 37 | |
30 | -/*********************** FREQUENCIES/CHANNELS ***********************/ | |
31 | - | |
32 | -/*------------------------------------------------------------------*/ | |
33 | 38 | /* |
34 | - * Print the number of channels and available frequency for the device | |
39 | + * Types of authentication parameters | |
35 | 40 | */ |
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 | |
41 | 42 | { |
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; | |
48 | 48 | |
49 | - /* Avoid "Unused parameter" warning */ | |
50 | - args = args; count = count; | |
49 | +/**************************** CONSTANTS ****************************/ | |
51 | 50 | |
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 | |
74 | 52 | |
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) | |
87 | 54 | |
88 | -/************************ ACCESS POINT LIST ************************/ | |
55 | +/* ------------------------ WPA CAPA NAMES ------------------------ */ | |
89 | 56 | /* |
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 ? | |
92 | 59 | */ |
93 | 60 | |
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])) | |
116 | 63 | |
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) | |
119 | 69 | |
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) | |
129 | 86 | |
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) | |
133 | 93 | |
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) | |
137 | 99 | |
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) | |
144 | 155 | |
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) | |
148 | 163 | |
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++) | |
155 | 184 | { |
156 | - if(has_qual) | |
185 | + if(mask & names[i].mask) | |
157 | 186 | { |
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; | |
162 | 191 | } |
163 | - else | |
164 | - /* Only print the address */ | |
165 | - printf(" %s\n", iw_saether_ntop(&hwa[i], temp)); | |
166 | 192 | } |
167 | - printf("\n"); | |
168 | - return(0); | |
193 | + /* If there is unconsumed bits... */ | |
194 | + if(mask != 0) | |
195 | + printf("%sUnknown", sep); | |
169 | 196 | } |
170 | 197 | |
171 | -/***************************** BITRATES *****************************/ | |
172 | - | |
173 | 198 | /*------------------------------------------------------------------*/ |
174 | 199 | /* |
175 | - * Print the number of available bitrates for the device | |
200 | + * Print the name corresponding to a value, with overflow check. | |
176 | 201 | */ |
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) | |
182 | 206 | { |
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 | +} | |
187 | 212 | |
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; | |
190 | 224 | |
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; | |
211 | 227 | |
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"); | |
221 | 232 | } |
222 | 233 | |
223 | -/************************* ENCRYPTION KEYS *************************/ | |
224 | - | |
225 | 234 | /*------------------------------------------------------------------*/ |
226 | 235 | /* |
227 | - * Print the number of available encryption key for the device | |
236 | + * Parse, and display the results of a WPA or WPA2 IE. | |
237 | + * | |
228 | 238 | */ |
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) | |
234 | 242 | { |
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; | |
240 | 251 | |
241 | - /* Avoid "Unused parameter" warning */ | |
242 | - args = args; count = count; | |
252 | + if(ielen > buflen) | |
253 | + ielen = buflen; | |
243 | 254 | |
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]) | |
249 | 264 | { |
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) | |
254 | 268 | { |
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; | |
261 | 271 | } |
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); | |
283 | 272 | |
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; | |
304 | 275 | |
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 | + } | |
328 | 288 | |
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; | |
345 | 292 | |
346 | - printf("\n\n"); | |
293 | + default: | |
294 | + return; | |
347 | 295 | } |
348 | - return(0); | |
349 | -} | |
296 | + | |
297 | + /* Pick version number (little endian) */ | |
298 | + ver = iebuf[offset] | (iebuf[offset + 1] << 8); | |
299 | + offset += 2; | |
350 | 300 | |
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); | |
352 | 305 | |
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)) | |
368 | 310 | { |
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"); | |
376 | 321 | } |
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); | |
402 | 322 | else |
403 | 323 | { |
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; | |
405 | 330 | |
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 | + } | |
455 | 338 | |
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); | |
461 | 343 | |
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; | |
468 | 346 | |
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; | |
472 | 365 | |
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); | |
477 | 370 | |
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; | |
485 | 373 | |
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; | |
506 | 392 | |
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"); | |
521 | 400 | } |
522 | - return(0); | |
523 | 401 | } |
524 | - | |
525 | -/************************** TRANSMIT POWER **************************/ | |
526 | - | |
402 | + | |
527 | 403 | /*------------------------------------------------------------------*/ |
528 | 404 | /* |
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. | |
530 | 408 | */ |
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) | |
536 | 412 | { |
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; | |
672 | 414 | |
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)) | |
679 | 417 | { |
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: "); | |
718 | 419 | |
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]) | |
722 | 422 | { |
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); | |
776 | 429 | } |
777 | - printf("\n"); | |
430 | + /* Skip over this IE to the next one in the list. */ | |
431 | + offset += buffer[offset+1] + 2; | |
778 | 432 | } |
779 | - return(0); | |
780 | 433 | } |
434 | +#endif /* WE_ESSENTIAL */ | |
781 | 435 | |
782 | 436 | /***************************** SCANNING *****************************/ |
783 | 437 | /* |
@@ -792,317 +446,53 @@ print_retry_info(int skfd, | ||
792 | 446 | |
793 | 447 | /*------------------------------------------------------------------*/ |
794 | 448 | /* |
795 | - * Parse, and display the results of a WPA or WPA2 IE. | |
796 | - * | |
449 | + * Print one element from the scanning results | |
797 | 450 | */ |
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) | |
801 | 457 | { |
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 */ | |
813 | 459 | |
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) | |
823 | 462 | { |
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++; | |
826 | 467 | 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); | |
830 | 473 | 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 | + } | |
834 | 486 | 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]); | |
838 | 493 | 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); | |
1106 | 496 | break; |
1107 | 497 | case SIOCGIWESSID: |
1108 | 498 | { |
@@ -1164,230 +554,1111 @@ print_scanning_token(struct stream_descr * stream, /* Stream of events */ | ||
1164 | 554 | /* Check for termination */ |
1165 | 555 | if(stream->value == NULL) |
1166 | 556 | { |
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); | |
1169 | 1434 | } |
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); | |
1197 | 1437 | } |
1198 | 1438 | |
1199 | 1439 | /*------------------------------------------------------------------*/ |
1200 | 1440 | /* |
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 | |
1202 | 1475 | */ |
1203 | 1476 | 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 */ | |
1208 | 1481 | { |
1209 | 1482 | struct iwreq wrq; |
1210 | - unsigned char * buffer = NULL; /* Results */ | |
1211 | - int buflen = IW_SCAN_MAX_DATA; /* Min for compat WE<17 */ | |
1212 | 1483 | struct iw_range range; |
1213 | - int has_range; | |
1214 | - struct timeval tv; /* Select timeout */ | |
1215 | - int timeout = 15000000; /* 15s */ | |
1484 | + char buffer[128]; | |
1216 | 1485 | |
1217 | 1486 | /* Avoid "Unused parameter" warning */ |
1218 | 1487 | args = args; count = count; |
1219 | 1488 | |
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 | |
1225 | 1495 | { |
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); | |
1234 | 1497 | |
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); | |
1242 | 1509 | |
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) | |
1247 | 1513 | { |
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; | |
1273 | 1515 | |
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; | |
1275 | 1524 | |
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 "); | |
1278 | 1527 | |
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 | + } | |
1287 | 1536 | |
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 | + } | |
1292 | 1560 | |
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 | + } | |
1302 | 1575 | } |
1303 | - buffer = newbuf; | |
1576 | + } | |
1577 | + printf("\n"); | |
1578 | + } | |
1579 | + return(0); | |
1580 | +} | |
1304 | 1581 | |
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 | + */ | |
1321 | 1587 | |
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; | |
1327 | 1610 | |
1328 | - /* Try again */ | |
1329 | - goto realloc; | |
1330 | - } | |
1611 | + /* Avoid "Unused parameter" warning */ | |
1612 | + args = args; count = count; | |
1331 | 1613 | |
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 | + } | |
1342 | 1623 | |
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; | |
1353 | 1627 | |
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); | |
1356 | 1637 | } |
1357 | 1638 | |
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++) | |
1359 | 1649 | { |
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) | |
1376 | 1651 | { |
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); | |
1383 | 1656 | } |
1384 | - while(ret > 0); | |
1385 | - printf("\n"); | |
1657 | + else | |
1658 | + /* Only print the address */ | |
1659 | + printf(" %s\n", iw_saether_ntop(&hwa[i], temp)); | |
1386 | 1660 | } |
1387 | - else | |
1388 | - printf("%-8.16s No scan results\n", ifname); | |
1389 | - | |
1390 | - free(buffer); | |
1661 | + printf("\n"); | |
1391 | 1662 | return(0); |
1392 | 1663 | } |
1393 | 1664 |
@@ -1419,7 +1690,7 @@ static const char * event_capa_evt[] = | ||
1419 | 1690 | |
1420 | 1691 | /*------------------------------------------------------------------*/ |
1421 | 1692 | /* |
1422 | - * Print the number of available transmit powers for the device | |
1693 | + * Print the event capability for the device | |
1423 | 1694 | */ |
1424 | 1695 | static int |
1425 | 1696 | print_event_capa_info(int skfd, |
@@ -1440,7 +1711,7 @@ print_event_capa_info(int skfd, | ||
1440 | 1711 | ifname); |
1441 | 1712 | else |
1442 | 1713 | { |
1443 | -#if 0 | |
1714 | +#ifdef DEBUG | |
1444 | 1715 | /* Debugging ;-) */ |
1445 | 1716 | for(cmd = 0x8B00; cmd < 0x8C0F; cmd++) |
1446 | 1717 | { |
@@ -1473,6 +1744,296 @@ print_event_capa_info(int skfd, | ||
1473 | 1744 | return(0); |
1474 | 1745 | } |
1475 | 1746 | |
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 | + | |
1476 | 2037 | /************************* COMMON UTILITIES *************************/ |
1477 | 2038 | /* |
1478 | 2039 | * This section was initially written by Michael Tokarev <mjt@tls.msk.ru> |
@@ -1484,27 +2045,33 @@ print_event_capa_info(int skfd, | ||
1484 | 2045 | * Map command line arguments to the proper procedure... |
1485 | 2046 | */ |
1486 | 2047 | 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 */ | |
1491 | 2052 | } iwlist_cmd; |
1492 | 2053 | |
1493 | 2054 | 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 */ | |
1508 | 2075 | { NULL, NULL, 0, 0 }, |
1509 | 2076 | }; |
1510 | 2077 |
@@ -1543,13 +2110,13 @@ find_command(const char * cmd) | ||
1543 | 2110 | |
1544 | 2111 | if(found == NULL) |
1545 | 2112 | { |
1546 | - fprintf(stderr, "iwlist: unknown command `%s'\n", cmd); | |
2113 | + fprintf(stderr, "iwlist: unknown command `%s' (check 'iwlist --help').\n", cmd); | |
1547 | 2114 | return NULL; |
1548 | 2115 | } |
1549 | 2116 | |
1550 | 2117 | if(ambig) |
1551 | 2118 | { |
1552 | - fprintf(stderr, "iwlist: command `%s' is ambiguous\n", cmd); | |
2119 | + fprintf(stderr, "iwlist: command `%s' is ambiguous (check 'iwlist --help').\n", cmd); | |
1553 | 2120 | return NULL; |
1554 | 2121 | } |
1555 | 2122 |
@@ -1562,12 +2129,17 @@ find_command(const char * cmd) | ||
1562 | 2129 | */ |
1563 | 2130 | static void iw_usage(int status) |
1564 | 2131 | { |
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 | + } | |
1567 | 2142 | |
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); | |
1571 | 2143 | exit(status); |
1572 | 2144 | } |
1573 | 2145 |
@@ -1588,7 +2160,7 @@ main(int argc, | ||
1588 | 2160 | int count; /* Number of arguments */ |
1589 | 2161 | const iwlist_cmd *iwcmd; |
1590 | 2162 | |
1591 | - if(argc == 1 || argc > 3) | |
2163 | + if(argc < 2) | |
1592 | 2164 | iw_usage(1); |
1593 | 2165 | |
1594 | 2166 | /* Those don't apply to all interfaces */ |
@@ -1618,14 +2190,10 @@ main(int argc, | ||
1618 | 2190 | return 1; |
1619 | 2191 | |
1620 | 2192 | /* 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)) | |
1627 | 2194 | { |
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); | |
1629 | 2197 | return 1; |
1630 | 2198 | } |
1631 | 2199 |
@@ -61,21 +61,27 @@ extern int | ||
61 | 61 | /* Get iwconfig in there. Mandatory. */ |
62 | 62 | #define main(args...) main_iwconfig(args) |
63 | 63 | #define iw_usage(args...) iwconfig_usage(args) |
64 | +#define find_command(args...) iwconfig_find_command(args) | |
64 | 65 | #include "iwconfig.c" |
66 | +#undef find_command | |
65 | 67 | #undef iw_usage |
66 | 68 | #undef main |
67 | 69 | |
68 | 70 | /* Get iwlist in there. Scanning support is pretty sweet. */ |
69 | 71 | #define main(args...) main_iwlist(args) |
70 | 72 | #define iw_usage(args...) iwlist_usage(args) |
73 | +#define find_command(args...) iwlist_find_command(args) | |
71 | 74 | #include "iwlist.c" |
75 | +#undef find_command | |
72 | 76 | #undef iw_usage |
73 | 77 | #undef main |
74 | 78 | |
79 | +#ifndef WE_ESSENTIAL | |
75 | 80 | /* Get iwspy in there, it's not that big. */ |
76 | 81 | #define main(args...) main_iwspy(args) |
77 | 82 | #include "iwspy.c" |
78 | 83 | #undef main |
84 | +#endif /* WE_ESSENTIAL */ | |
79 | 85 | |
80 | 86 | /* Get iwpriv in there. Mandatory for HostAP and some other drivers. */ |
81 | 87 | #define main(args...) main_iwpriv(args) |
@@ -122,8 +128,10 @@ main(int argc, | ||
122 | 128 | return(main_iwconfig(argc, argv)); |
123 | 129 | if(!strcmp(call_name, "iwlist")) |
124 | 130 | return(main_iwlist(argc, argv)); |
131 | +#ifndef WE_ESSENTIAL | |
125 | 132 | if(!strcmp(call_name, "iwspy")) |
126 | 133 | return(main_iwspy(argc, argv)); |
134 | +#endif /* WE_ESSENTIAL */ | |
127 | 135 | if(!strcmp(call_name, "iwpriv")) |
128 | 136 | return(main_iwpriv(argc, argv)); |
129 | 137 | if(!strcmp(call_name, "iwgetid")) |
@@ -16,13 +16,9 @@ network interface | ||
16 | 16 | .br |
17 | 17 | .BI "iwpriv " "interface private-command " "[" private-parameters ] |
18 | 18 | .br |
19 | -.BI "iwpriv " "interface private-command [I] " "[" private-parameters ] | |
19 | +.BI "iwpriv " "interface private-command " [ I "] [" private-parameters ] | |
20 | 20 | .br |
21 | 21 | .BI "iwpriv " interface " --all" |
22 | -.br | |
23 | -.BI "iwpriv " interface " roam " {on,off} | |
24 | -.br | |
25 | -.BI "iwpriv " interface " port " {ad-hoc,managed,N} | |
26 | 22 | .\" |
27 | 23 | .\" DESCRIPTION part |
28 | 24 | .\" |
@@ -64,7 +60,7 @@ about those parameters. | ||
64 | 60 | However you should refer to the device driver documentation for |
65 | 61 | information on how to properly use the command and the effect. |
66 | 62 | .TP |
67 | -.I "private-command [I]" "[" private-parameters ] | |
63 | +.IR "private-command " [ I "] [" private-parameters ] | |
68 | 64 | Idem, except that |
69 | 65 | .I I |
70 | 66 | (an integer) is passed to the command as a |
@@ -75,19 +71,6 @@ the driver documentation should tell you when it's needed. | ||
75 | 71 | .BR -a / --all |
76 | 72 | Execute and display all the private commands that don't take any |
77 | 73 | 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." | |
91 | 74 | .\" |
92 | 75 | .\" DISPLAY part |
93 | 76 | .\" |
@@ -1,14 +1,14 @@ | ||
1 | 1 | /* |
2 | 2 | * Wireless Tools |
3 | 3 | * |
4 | - * Jean II - HPLB 97->99 - HPL 99->04 | |
4 | + * Jean II - HPLB 97->99 - HPL 99->07 | |
5 | 5 | * |
6 | 6 | * Main code for "iwconfig". This is the generic tool for most |
7 | 7 | * manipulations... |
8 | 8 | * You need to link this code against "iwlib.c" and "-lm". |
9 | 9 | * |
10 | 10 | * 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> | |
12 | 12 | */ |
13 | 13 | |
14 | 14 | #include "iwlib.h" /* Header */ |
@@ -384,9 +384,9 @@ set_private_cmd(int skfd, /* Socket */ | ||
384 | 384 | printf("Invalid float [%s]...\n", args[i]); |
385 | 385 | return(-1); |
386 | 386 | } |
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; | |
390 | 390 | sscanf(args[i], "%i", &temp); |
391 | 391 | iw_float2freq(freq, ((struct iw_freq *) buffer) + i); |
392 | 392 | } |
@@ -690,6 +690,7 @@ print_priv_all(int skfd, | ||
690 | 690 | * Convenient access to some private ioctls of some devices |
691 | 691 | */ |
692 | 692 | |
693 | +#if 0 | |
693 | 694 | /*------------------------------------------------------------------*/ |
694 | 695 | /* |
695 | 696 | * Set roaming mode on and off |
@@ -905,6 +906,7 @@ port_type(int skfd, /* Socket */ | ||
905 | 906 | free(priv); |
906 | 907 | return(-1); |
907 | 908 | } |
909 | +#endif | |
908 | 910 | |
909 | 911 | /******************************* MAIN ********************************/ |
910 | 912 |
@@ -954,6 +956,7 @@ main(int argc, | ||
954 | 956 | (!strcmp(argv[2], "--all"))) |
955 | 957 | print_priv_all(skfd, argv[1], NULL, 0); |
956 | 958 | else |
959 | +#if 0 | |
957 | 960 | /* Roaming */ |
958 | 961 | if(!strncmp(argv[2], "roam", 4)) |
959 | 962 | goterr = set_roaming(skfd, argv + 3, argc - 3, argv[1]); |
@@ -962,6 +965,7 @@ main(int argc, | ||
962 | 965 | if(!strncmp(argv[2], "port", 4)) |
963 | 966 | goterr = port_type(skfd, argv + 3, argc - 3, argv[1]); |
964 | 967 | else |
968 | +#endif | |
965 | 969 | /*-------------*/ |
966 | 970 | /* Otherwise, it's a private ioctl */ |
967 | 971 | goterr = set_private(skfd, argv + 2, argc - 2, argv[1]); |
@@ -11,7 +11,7 @@ iwspy \- Get wireless statistics from specific nodes | ||
11 | 11 | .\" SYNOPSIS part |
12 | 12 | .\" |
13 | 13 | .SH SYNOPSIS |
14 | -.BI "iwspy " interface | |
14 | +.BI "iwspy [" interface ] | |
15 | 15 | .br |
16 | 16 | .BI "iwspy " interface " [+] " DNSNAME " | " IPADDR " | " HWADDR " [...]" |
17 | 17 | .br |
@@ -56,7 +56,10 @@ static int ioctl_set_power(struct net_device *dev, | ||
56 | 56 | /* Set period */ |
57 | 57 | if(prq->flags & IW_POWER_PERIOD) |
58 | 58 | { |
59 | - int period = prq->value/1000000; | |
59 | + int period = prq->value; | |
60 | +#if WIRELESS_EXT < 21 | |
61 | + period /= 1000000; | |
62 | +#endif | |
60 | 63 | /* Hum: check if within bounds... */ |
61 | 64 | |
62 | 65 | /* Activate PM */ |
@@ -114,12 +117,18 @@ static int ioctl_get_power(struct net_device *dev, | ||
114 | 117 | /* By default, the min */ |
115 | 118 | if(!(inc_flags & IW_POWER_MAX)) |
116 | 119 | { |
117 | - prq->value = local->pm_min_period * 1000000; | |
120 | + prq->value = local->pm_min_period; | |
121 | +#if WIRELESS_EXT < 21 | |
122 | + prq->value *= 1000000; | |
123 | +#endif | |
118 | 124 | prq->flags |= IW_POWER_MIN; |
119 | 125 | } |
120 | 126 | else |
121 | 127 | { |
122 | - prq->value = local->pm_max_period * 1000000; | |
128 | + prq->value = local->pm_max_period; | |
129 | +#if WIRELESS_EXT < 21 | |
130 | + prq->value *= 1000000; | |
131 | +#endif | |
123 | 132 | prq->flags |= IW_POWER_MAX; |
124 | 133 | } |
125 | 134 | } |
@@ -129,7 +138,12 @@ static int ioctl_get_power(struct net_device *dev, | ||
129 | 138 | if(inc_flags & (IW_POWER_MIN | IW_POWER_MAX)) |
130 | 139 | return(-EINVAL); |
131 | 140 | else |
132 | - prq->value = local->pm_period * 1000000; | |
141 | + { | |
142 | + prq->value = local->pm_period; | |
143 | +#if WIRELESS_EXT < 21 | |
144 | + prq->value *= 1000000; | |
145 | +#endif | |
146 | + } | |
133 | 147 | } |
134 | 148 | } |
135 | 149 | else |
@@ -165,8 +179,13 @@ static int ioctl_get_range(struct net_device *dev, | ||
165 | 179 | #endif /* WIRELESS_EXT > 10 */ |
166 | 180 | |
167 | 181 | #if WIRELESS_EXT > 9 |
182 | +#if WIRELESS_EXT < 21 | |
168 | 183 | range.min_pmp = 1000000; /* 1 units */ |
169 | 184 | range.max_pmp = 12000000; /* 12 units */ |
185 | +#else | |
186 | + range.min_pmp = 1; /* 1 units */ | |
187 | + range.max_pmp = 12; /* 12 units */ | |
188 | +#endif | |
170 | 189 | range.min_pmt = 1000; /* 1 ms */ |
171 | 190 | range.max_pmt = 1000000; /* 1 s */ |
172 | 191 | range.pmp_flags = IW_POWER_PERIOD | IW_POWER_RELATIVE | |
@@ -0,0 +1,39 @@ | ||
1 | +diff -u -p udev-106/udev_rules.j1.c udev-106/udev_rules.c | |
2 | +--- udev-106/udev_rules.j1.c 2007-03-15 10:07:51.000000000 -0700 | |
3 | ++++ udev-106/udev_rules.c 2007-03-15 10:09:50.000000000 -0700 | |
4 | +@@ -186,7 +186,16 @@ static int import_keys_into_env(struct u | |
5 | + linepos = line; | |
6 | + if (get_key(&linepos, &variable, &value) == 0) { | |
7 | + dbg("import '%s=%s'", variable, value); | |
8 | +- name_list_key_add(&udev->env_list, variable, value); | |
9 | ++ /* handle device, renamed by external tool, | |
10 | ++ * returning new path */ | |
11 | ++ if (strcmp(variable, "DEVPATH") == 0) { | |
12 | ++ info("updating devpath from '%s' to '%s'", | |
13 | ++ udev->dev->devpath, value); | |
14 | ++ sysfs_device_set_values(udev->dev, value, | |
15 | ++ NULL, NULL); | |
16 | ++ } else | |
17 | ++ name_list_key_add(&udev->env_list, | |
18 | ++ variable, value); | |
19 | + setenv(variable, value, 1); | |
20 | + } | |
21 | + } | |
22 | +diff -u -p udev-106/udevtest.j1.c udev-106/udevtest.c | |
23 | +--- udev-106/udevtest.j1.c 2007-03-15 10:39:16.000000000 -0700 | |
24 | ++++ udev-106/udevtest.c 2007-03-15 10:42:09.000000000 -0700 | |
25 | +@@ -59,8 +59,13 @@ int main(int argc, char *argv[], char *e | |
26 | + | |
27 | + info("version %s", UDEV_VERSION); | |
28 | + udev_config_init(); | |
29 | +- if (udev_log_priority < LOG_INFO) | |
30 | ++ if (udev_log_priority < LOG_INFO) { | |
31 | ++ char priority[32]; | |
32 | ++ | |
33 | + udev_log_priority = LOG_INFO; | |
34 | ++ sprintf(priority, "%i", udev_log_priority); | |
35 | ++ setenv("UDEV_LOG", priority, 1); | |
36 | ++ } | |
37 | + | |
38 | + for (i = 1 ; i < argc; i++) { | |
39 | + char *arg = argv[i]; |
@@ -0,0 +1,1120 @@ | ||
1 | +/* | |
2 | + * This file define a set of standard wireless extensions | |
3 | + * | |
4 | + * Version : 21 14.3.06 | |
5 | + * | |
6 | + * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> | |
7 | + * Copyright (c) 1997-2005 Jean Tourrilhes, All Rights Reserved. | |
8 | + */ | |
9 | + | |
10 | +#ifndef _LINUX_WIRELESS_H | |
11 | +#define _LINUX_WIRELESS_H | |
12 | + | |
13 | +/************************** DOCUMENTATION **************************/ | |
14 | +/* | |
15 | + * Initial APIs (1996 -> onward) : | |
16 | + * ----------------------------- | |
17 | + * Basically, the wireless extensions are for now a set of standard ioctl | |
18 | + * call + /proc/net/wireless | |
19 | + * | |
20 | + * The entry /proc/net/wireless give statistics and information on the | |
21 | + * driver. | |
22 | + * This is better than having each driver having its entry because | |
23 | + * its centralised and we may remove the driver module safely. | |
24 | + * | |
25 | + * Ioctl are used to configure the driver and issue commands. This is | |
26 | + * better than command line options of insmod because we may want to | |
27 | + * change dynamically (while the driver is running) some parameters. | |
28 | + * | |
29 | + * The ioctl mechanimsm are copied from standard devices ioctl. | |
30 | + * We have the list of command plus a structure descibing the | |
31 | + * data exchanged... | |
32 | + * Note that to add these ioctl, I was obliged to modify : | |
33 | + * # net/core/dev.c (two place + add include) | |
34 | + * # net/ipv4/af_inet.c (one place + add include) | |
35 | + * | |
36 | + * /proc/net/wireless is a copy of /proc/net/dev. | |
37 | + * We have a structure for data passed from the driver to /proc/net/wireless | |
38 | + * Too add this, I've modified : | |
39 | + * # net/core/dev.c (two other places) | |
40 | + * # include/linux/netdevice.h (one place) | |
41 | + * # include/linux/proc_fs.h (one place) | |
42 | + * | |
43 | + * New driver API (2002 -> onward) : | |
44 | + * ------------------------------- | |
45 | + * This file is only concerned with the user space API and common definitions. | |
46 | + * The new driver API is defined and documented in : | |
47 | + * # include/net/iw_handler.h | |
48 | + * | |
49 | + * Note as well that /proc/net/wireless implementation has now moved in : | |
50 | + * # net/core/wireless.c | |
51 | + * | |
52 | + * Wireless Events (2002 -> onward) : | |
53 | + * -------------------------------- | |
54 | + * Events are defined at the end of this file, and implemented in : | |
55 | + * # net/core/wireless.c | |
56 | + * | |
57 | + * Other comments : | |
58 | + * -------------- | |
59 | + * Do not add here things that are redundant with other mechanisms | |
60 | + * (drivers init, ifconfig, /proc/net/dev, ...) and with are not | |
61 | + * wireless specific. | |
62 | + * | |
63 | + * These wireless extensions are not magic : each driver has to provide | |
64 | + * support for them... | |
65 | + * | |
66 | + * IMPORTANT NOTE : As everything in the kernel, this is very much a | |
67 | + * work in progress. Contact me if you have ideas of improvements... | |
68 | + */ | |
69 | + | |
70 | +/***************************** INCLUDES *****************************/ | |
71 | + | |
72 | +/* This header is used in user-space, therefore need to be sanitised | |
73 | + * for that purpose. Those includes are usually not compatible with glibc. | |
74 | + * To know which includes to use in user-space, check iwlib.h. */ | |
75 | +#ifdef __KERNEL__ | |
76 | +#include <linux/types.h> /* for "caddr_t" et al */ | |
77 | +#include <linux/socket.h> /* for "struct sockaddr" et al */ | |
78 | +#include <linux/if.h> /* for IFNAMSIZ and co... */ | |
79 | +#endif /* __KERNEL__ */ | |
80 | + | |
81 | +/***************************** VERSION *****************************/ | |
82 | +/* | |
83 | + * This constant is used to know the availability of the wireless | |
84 | + * extensions and to know which version of wireless extensions it is | |
85 | + * (there is some stuff that will be added in the future...) | |
86 | + * I just plan to increment with each new version. | |
87 | + */ | |
88 | +#define WIRELESS_EXT 21 | |
89 | + | |
90 | +/* | |
91 | + * Changes : | |
92 | + * | |
93 | + * V2 to V3 | |
94 | + * -------- | |
95 | + * Alan Cox start some incompatibles changes. I've integrated a bit more. | |
96 | + * - Encryption renamed to Encode to avoid US regulation problems | |
97 | + * - Frequency changed from float to struct to avoid problems on old 386 | |
98 | + * | |
99 | + * V3 to V4 | |
100 | + * -------- | |
101 | + * - Add sensitivity | |
102 | + * | |
103 | + * V4 to V5 | |
104 | + * -------- | |
105 | + * - Missing encoding definitions in range | |
106 | + * - Access points stuff | |
107 | + * | |
108 | + * V5 to V6 | |
109 | + * -------- | |
110 | + * - 802.11 support (ESSID ioctls) | |
111 | + * | |
112 | + * V6 to V7 | |
113 | + * -------- | |
114 | + * - define IW_ESSID_MAX_SIZE and IW_MAX_AP | |
115 | + * | |
116 | + * V7 to V8 | |
117 | + * -------- | |
118 | + * - Changed my e-mail address | |
119 | + * - More 802.11 support (nickname, rate, rts, frag) | |
120 | + * - List index in frequencies | |
121 | + * | |
122 | + * V8 to V9 | |
123 | + * -------- | |
124 | + * - Support for 'mode of operation' (ad-hoc, managed...) | |
125 | + * - Support for unicast and multicast power saving | |
126 | + * - Change encoding to support larger tokens (>64 bits) | |
127 | + * - Updated iw_params (disable, flags) and use it for NWID | |
128 | + * - Extracted iw_point from iwreq for clarity | |
129 | + * | |
130 | + * V9 to V10 | |
131 | + * --------- | |
132 | + * - Add PM capability to range structure | |
133 | + * - Add PM modifier : MAX/MIN/RELATIVE | |
134 | + * - Add encoding option : IW_ENCODE_NOKEY | |
135 | + * - Add TxPower ioctls (work like TxRate) | |
136 | + * | |
137 | + * V10 to V11 | |
138 | + * ---------- | |
139 | + * - Add WE version in range (help backward/forward compatibility) | |
140 | + * - Add retry ioctls (work like PM) | |
141 | + * | |
142 | + * V11 to V12 | |
143 | + * ---------- | |
144 | + * - Add SIOCSIWSTATS to get /proc/net/wireless programatically | |
145 | + * - Add DEV PRIVATE IOCTL to avoid collisions in SIOCDEVPRIVATE space | |
146 | + * - Add new statistics (frag, retry, beacon) | |
147 | + * - Add average quality (for user space calibration) | |
148 | + * | |
149 | + * V12 to V13 | |
150 | + * ---------- | |
151 | + * - Document creation of new driver API. | |
152 | + * - Extract union iwreq_data from struct iwreq (for new driver API). | |
153 | + * - Rename SIOCSIWNAME as SIOCSIWCOMMIT | |
154 | + * | |
155 | + * V13 to V14 | |
156 | + * ---------- | |
157 | + * - Wireless Events support : define struct iw_event | |
158 | + * - Define additional specific event numbers | |
159 | + * - Add "addr" and "param" fields in union iwreq_data | |
160 | + * - AP scanning stuff (SIOCSIWSCAN and friends) | |
161 | + * | |
162 | + * V14 to V15 | |
163 | + * ---------- | |
164 | + * - Add IW_PRIV_TYPE_ADDR for struct sockaddr private arg | |
165 | + * - Make struct iw_freq signed (both m & e), add explicit padding | |
166 | + * - Add IWEVCUSTOM for driver specific event/scanning token | |
167 | + * - Add IW_MAX_GET_SPY for driver returning a lot of addresses | |
168 | + * - Add IW_TXPOW_RANGE for range of Tx Powers | |
169 | + * - Add IWEVREGISTERED & IWEVEXPIRED events for Access Points | |
170 | + * - Add IW_MODE_MONITOR for passive monitor | |
171 | + * | |
172 | + * V15 to V16 | |
173 | + * ---------- | |
174 | + * - Increase the number of bitrates in iw_range to 32 (for 802.11g) | |
175 | + * - Increase the number of frequencies in iw_range to 32 (for 802.11b+a) | |
176 | + * - Reshuffle struct iw_range for increases, add filler | |
177 | + * - Increase IW_MAX_AP to 64 for driver returning a lot of addresses | |
178 | + * - Remove IW_MAX_GET_SPY because conflict with enhanced spy support | |
179 | + * - Add SIOCSIWTHRSPY/SIOCGIWTHRSPY and "struct iw_thrspy" | |
180 | + * - Add IW_ENCODE_TEMP and iw_range->encoding_login_index | |
181 | + * | |
182 | + * V16 to V17 | |
183 | + * ---------- | |
184 | + * - Add flags to frequency -> auto/fixed | |
185 | + * - Document (struct iw_quality *)->updated, add new flags (INVALID) | |
186 | + * - Wireless Event capability in struct iw_range | |
187 | + * - Add support for relative TxPower (yick !) | |
188 | + * | |
189 | + * V17 to V18 (From Jouni Malinen <jkmaline@cc.hut.fi>) | |
190 | + * ---------- | |
191 | + * - Add support for WPA/WPA2 | |
192 | + * - Add extended encoding configuration (SIOCSIWENCODEEXT and | |
193 | + * SIOCGIWENCODEEXT) | |
194 | + * - Add SIOCSIWGENIE/SIOCGIWGENIE | |
195 | + * - Add SIOCSIWMLME | |
196 | + * - Add SIOCSIWPMKSA | |
197 | + * - Add struct iw_range bit field for supported encoding capabilities | |
198 | + * - Add optional scan request parameters for SIOCSIWSCAN | |
199 | + * - Add SIOCSIWAUTH/SIOCGIWAUTH for setting authentication and WPA | |
200 | + * related parameters (extensible up to 4096 parameter values) | |
201 | + * - Add wireless events: IWEVGENIE, IWEVMICHAELMICFAILURE, | |
202 | + * IWEVASSOCREQIE, IWEVASSOCRESPIE, IWEVPMKIDCAND | |
203 | + * | |
204 | + * V18 to V19 | |
205 | + * ---------- | |
206 | + * - Remove (struct iw_point *)->pointer from events and streams | |
207 | + * - Remove header includes to help user space | |
208 | + * - Increase IW_ENCODING_TOKEN_MAX from 32 to 64 | |
209 | + * - Add IW_QUAL_ALL_UPDATED and IW_QUAL_ALL_INVALID macros | |
210 | + * - Add explicit flag to tell stats are in dBm : IW_QUAL_DBM | |
211 | + * - Add IW_IOCTL_IDX() and IW_EVENT_IDX() macros | |
212 | + * | |
213 | + * V20 to V21 | |
214 | + * ---------- | |
215 | + * - Remove (struct net_device *)->get_wireless_stats() | |
216 | + * - Change length in ESSID and NICK to strlen() instead of strlen()+1 | |
217 | + * - Add SIOCSIWMODUL/SIOCGIWMODUL for modulation setting | |
218 | + * - Add IW_RETRY_SHORT/IW_RETRY_LONG retry modifiers | |
219 | + * - Add IW_POWER_SAVING power type | |
220 | + * - Power/Retry relative values no longer * 100000 | |
221 | + * - Add bitrate flags for unicast/broadcast | |
222 | + */ | |
223 | + | |
224 | +/**************************** CONSTANTS ****************************/ | |
225 | + | |
226 | +/* -------------------------- IOCTL LIST -------------------------- */ | |
227 | + | |
228 | +/* Wireless Identification */ | |
229 | +#define SIOCSIWCOMMIT 0x8B00 /* Commit pending changes to driver */ | |
230 | +#define SIOCGIWNAME 0x8B01 /* get name == wireless protocol */ | |
231 | +/* SIOCGIWNAME is used to verify the presence of Wireless Extensions. | |
232 | + * Common values : "IEEE 802.11-DS", "IEEE 802.11-FH", "IEEE 802.11b"... | |
233 | + * Don't put the name of your driver there, it's useless. */ | |
234 | + | |
235 | +/* Basic operations */ | |
236 | +#define SIOCSIWNWID 0x8B02 /* set network id (pre-802.11) */ | |
237 | +#define SIOCGIWNWID 0x8B03 /* get network id (the cell) */ | |
238 | +#define SIOCSIWFREQ 0x8B04 /* set channel/frequency (Hz) */ | |
239 | +#define SIOCGIWFREQ 0x8B05 /* get channel/frequency (Hz) */ | |
240 | +#define SIOCSIWMODE 0x8B06 /* set operation mode */ | |
241 | +#define SIOCGIWMODE 0x8B07 /* get operation mode */ | |
242 | +#define SIOCSIWSENS 0x8B08 /* set sensitivity (dBm) */ | |
243 | +#define SIOCGIWSENS 0x8B09 /* get sensitivity (dBm) */ | |
244 | + | |
245 | +/* Informative stuff */ | |
246 | +#define SIOCSIWRANGE 0x8B0A /* Unused */ | |
247 | +#define SIOCGIWRANGE 0x8B0B /* Get range of parameters */ | |
248 | +#define SIOCSIWPRIV 0x8B0C /* Unused */ | |
249 | +#define SIOCGIWPRIV 0x8B0D /* get private ioctl interface info */ | |
250 | +#define SIOCSIWSTATS 0x8B0E /* Unused */ | |
251 | +#define SIOCGIWSTATS 0x8B0F /* Get /proc/net/wireless stats */ | |
252 | +/* SIOCGIWSTATS is strictly used between user space and the kernel, and | |
253 | + * is never passed to the driver (i.e. the driver will never see it). */ | |
254 | + | |
255 | +/* Spy support (statistics per MAC address - used for Mobile IP support) */ | |
256 | +#define SIOCSIWSPY 0x8B10 /* set spy addresses */ | |
257 | +#define SIOCGIWSPY 0x8B11 /* get spy info (quality of link) */ | |
258 | +#define SIOCSIWTHRSPY 0x8B12 /* set spy threshold (spy event) */ | |
259 | +#define SIOCGIWTHRSPY 0x8B13 /* get spy threshold */ | |
260 | + | |
261 | +/* Access Point manipulation */ | |
262 | +#define SIOCSIWAP 0x8B14 /* set access point MAC addresses */ | |
263 | +#define SIOCGIWAP 0x8B15 /* get access point MAC addresses */ | |
264 | +#define SIOCGIWAPLIST 0x8B17 /* Deprecated in favor of scanning */ | |
265 | +#define SIOCSIWSCAN 0x8B18 /* trigger scanning (list cells) */ | |
266 | +#define SIOCGIWSCAN 0x8B19 /* get scanning results */ | |
267 | + | |
268 | +/* 802.11 specific support */ | |
269 | +#define SIOCSIWESSID 0x8B1A /* set ESSID (network name) */ | |
270 | +#define SIOCGIWESSID 0x8B1B /* get ESSID */ | |
271 | +#define SIOCSIWNICKN 0x8B1C /* set node name/nickname */ | |
272 | +#define SIOCGIWNICKN 0x8B1D /* get node name/nickname */ | |
273 | +/* As the ESSID and NICKN are strings up to 32 bytes long, it doesn't fit | |
274 | + * within the 'iwreq' structure, so we need to use the 'data' member to | |
275 | + * point to a string in user space, like it is done for RANGE... */ | |
276 | + | |
277 | +/* Other parameters useful in 802.11 and some other devices */ | |
278 | +#define SIOCSIWRATE 0x8B20 /* set default bit rate (bps) */ | |
279 | +#define SIOCGIWRATE 0x8B21 /* get default bit rate (bps) */ | |
280 | +#define SIOCSIWRTS 0x8B22 /* set RTS/CTS threshold (bytes) */ | |
281 | +#define SIOCGIWRTS 0x8B23 /* get RTS/CTS threshold (bytes) */ | |
282 | +#define SIOCSIWFRAG 0x8B24 /* set fragmentation thr (bytes) */ | |
283 | +#define SIOCGIWFRAG 0x8B25 /* get fragmentation thr (bytes) */ | |
284 | +#define SIOCSIWTXPOW 0x8B26 /* set transmit power (dBm) */ | |
285 | +#define SIOCGIWTXPOW 0x8B27 /* get transmit power (dBm) */ | |
286 | +#define SIOCSIWRETRY 0x8B28 /* set retry limits and lifetime */ | |
287 | +#define SIOCGIWRETRY 0x8B29 /* get retry limits and lifetime */ | |
288 | + | |
289 | +/* Encoding stuff (scrambling, hardware security, WEP...) */ | |
290 | +#define SIOCSIWENCODE 0x8B2A /* set encoding token & mode */ | |
291 | +#define SIOCGIWENCODE 0x8B2B /* get encoding token & mode */ | |
292 | +/* Power saving stuff (power management, unicast and multicast) */ | |
293 | +#define SIOCSIWPOWER 0x8B2C /* set Power Management settings */ | |
294 | +#define SIOCGIWPOWER 0x8B2D /* get Power Management settings */ | |
295 | +/* Modulation bitmask */ | |
296 | +#define SIOCSIWMODUL 0x8B2E /* set Modulations settings */ | |
297 | +#define SIOCGIWMODUL 0x8B2F /* get Modulations settings */ | |
298 | + | |
299 | +/* WPA : Generic IEEE 802.11 informatiom element (e.g., for WPA/RSN/WMM). | |
300 | + * This ioctl uses struct iw_point and data buffer that includes IE id and len | |
301 | + * fields. More than one IE may be included in the request. Setting the generic | |
302 | + * IE to empty buffer (len=0) removes the generic IE from the driver. Drivers | |
303 | + * are allowed to generate their own WPA/RSN IEs, but in these cases, drivers | |
304 | + * are required to report the used IE as a wireless event, e.g., when | |
305 | + * associating with an AP. */ | |
306 | +#define SIOCSIWGENIE 0x8B30 /* set generic IE */ | |
307 | +#define SIOCGIWGENIE 0x8B31 /* get generic IE */ | |
308 | + | |
309 | +/* WPA : IEEE 802.11 MLME requests */ | |
310 | +#define SIOCSIWMLME 0x8B16 /* request MLME operation; uses | |
311 | + * struct iw_mlme */ | |
312 | +/* WPA : Authentication mode parameters */ | |
313 | +#define SIOCSIWAUTH 0x8B32 /* set authentication mode params */ | |
314 | +#define SIOCGIWAUTH 0x8B33 /* get authentication mode params */ | |
315 | + | |
316 | +/* WPA : Extended version of encoding configuration */ | |
317 | +#define SIOCSIWENCODEEXT 0x8B34 /* set encoding token & mode */ | |
318 | +#define SIOCGIWENCODEEXT 0x8B35 /* get encoding token & mode */ | |
319 | + | |
320 | +/* WPA2 : PMKSA cache management */ | |
321 | +#define SIOCSIWPMKSA 0x8B36 /* PMKSA cache operation */ | |
322 | + | |
323 | +/* -------------------- DEV PRIVATE IOCTL LIST -------------------- */ | |
324 | + | |
325 | +/* These 32 ioctl are wireless device private, for 16 commands. | |
326 | + * Each driver is free to use them for whatever purpose it chooses, | |
327 | + * however the driver *must* export the description of those ioctls | |
328 | + * with SIOCGIWPRIV and *must* use arguments as defined below. | |
329 | + * If you don't follow those rules, DaveM is going to hate you (reason : | |
330 | + * it make mixed 32/64bit operation impossible). | |
331 | + */ | |
332 | +#define SIOCIWFIRSTPRIV 0x8BE0 | |
333 | +#define SIOCIWLASTPRIV 0x8BFF | |
334 | +/* Previously, we were using SIOCDEVPRIVATE, but we now have our | |
335 | + * separate range because of collisions with other tools such as | |
336 | + * 'mii-tool'. | |
337 | + * We now have 32 commands, so a bit more space ;-). | |
338 | + * Also, all 'odd' commands are only usable by root and don't return the | |
339 | + * content of ifr/iwr to user (but you are not obliged to use the set/get | |
340 | + * convention, just use every other two command). More details in iwpriv.c. | |
341 | + * And I repeat : you are not forced to use them with iwpriv, but you | |
342 | + * must be compliant with it. | |
343 | + */ | |
344 | + | |
345 | +/* ------------------------- IOCTL STUFF ------------------------- */ | |
346 | + | |
347 | +/* The first and the last (range) */ | |
348 | +#define SIOCIWFIRST 0x8B00 | |
349 | +#define SIOCIWLAST SIOCIWLASTPRIV /* 0x8BFF */ | |
350 | +#define IW_IOCTL_IDX(cmd) ((cmd) - SIOCIWFIRST) | |
351 | + | |
352 | +/* Even : get (world access), odd : set (root access) */ | |
353 | +#define IW_IS_SET(cmd) (!((cmd) & 0x1)) | |
354 | +#define IW_IS_GET(cmd) ((cmd) & 0x1) | |
355 | + | |
356 | +/* ----------------------- WIRELESS EVENTS ----------------------- */ | |
357 | +/* Those are *NOT* ioctls, do not issue request on them !!! */ | |
358 | +/* Most events use the same identifier as ioctl requests */ | |
359 | + | |
360 | +#define IWEVTXDROP 0x8C00 /* Packet dropped to excessive retry */ | |
361 | +#define IWEVQUAL 0x8C01 /* Quality part of statistics (scan) */ | |
362 | +#define IWEVCUSTOM 0x8C02 /* Driver specific ascii string */ | |
363 | +#define IWEVREGISTERED 0x8C03 /* Discovered a new node (AP mode) */ | |
364 | +#define IWEVEXPIRED 0x8C04 /* Expired a node (AP mode) */ | |
365 | +#define IWEVGENIE 0x8C05 /* Generic IE (WPA, RSN, WMM, ..) | |
366 | + * (scan results); This includes id and | |
367 | + * length fields. One IWEVGENIE may | |
368 | + * contain more than one IE. Scan | |
369 | + * results may contain one or more | |
370 | + * IWEVGENIE events. */ | |
371 | +#define IWEVMICHAELMICFAILURE 0x8C06 /* Michael MIC failure | |
372 | + * (struct iw_michaelmicfailure) | |
373 | + */ | |
374 | +#define IWEVASSOCREQIE 0x8C07 /* IEs used in (Re)Association Request. | |
375 | + * The data includes id and length | |
376 | + * fields and may contain more than one | |
377 | + * IE. This event is required in | |
378 | + * Managed mode if the driver | |
379 | + * generates its own WPA/RSN IE. This | |
380 | + * should be sent just before | |
381 | + * IWEVREGISTERED event for the | |
382 | + * association. */ | |
383 | +#define IWEVASSOCRESPIE 0x8C08 /* IEs used in (Re)Association | |
384 | + * Response. The data includes id and | |
385 | + * length fields and may contain more | |
386 | + * than one IE. This may be sent | |
387 | + * between IWEVASSOCREQIE and | |
388 | + * IWEVREGISTERED events for the | |
389 | + * association. */ | |
390 | +#define IWEVPMKIDCAND 0x8C09 /* PMKID candidate for RSN | |
391 | + * pre-authentication | |
392 | + * (struct iw_pmkid_cand) */ | |
393 | + | |
394 | +#define IWEVFIRST 0x8C00 | |
395 | +#define IW_EVENT_IDX(cmd) ((cmd) - IWEVFIRST) | |
396 | + | |
397 | +/* ------------------------- PRIVATE INFO ------------------------- */ | |
398 | +/* | |
399 | + * The following is used with SIOCGIWPRIV. It allow a driver to define | |
400 | + * the interface (name, type of data) for its private ioctl. | |
401 | + * Privates ioctl are SIOCIWFIRSTPRIV -> SIOCIWLASTPRIV | |
402 | + */ | |
403 | + | |
404 | +#define IW_PRIV_TYPE_MASK 0x7000 /* Type of arguments */ | |
405 | +#define IW_PRIV_TYPE_NONE 0x0000 | |
406 | +#define IW_PRIV_TYPE_BYTE 0x1000 /* Char as number */ | |
407 | +#define IW_PRIV_TYPE_CHAR 0x2000 /* Char as character */ | |
408 | +#define IW_PRIV_TYPE_INT 0x4000 /* 32 bits int */ | |
409 | +#define IW_PRIV_TYPE_FLOAT 0x5000 /* struct iw_freq */ | |
410 | +#define IW_PRIV_TYPE_ADDR 0x6000 /* struct sockaddr */ | |
411 | + | |
412 | +#define IW_PRIV_SIZE_FIXED 0x0800 /* Variable or fixed number of args */ | |
413 | + | |
414 | +#define IW_PRIV_SIZE_MASK 0x07FF /* Max number of those args */ | |
415 | + | |
416 | +/* | |
417 | + * Note : if the number of args is fixed and the size < 16 octets, | |
418 | + * instead of passing a pointer we will put args in the iwreq struct... | |
419 | + */ | |
420 | + | |
421 | +/* ----------------------- OTHER CONSTANTS ----------------------- */ | |
422 | + | |
423 | +/* Maximum frequencies in the range struct */ | |
424 | +#define IW_MAX_FREQUENCIES 32 | |
425 | +/* Note : if you have something like 80 frequencies, | |
426 | + * don't increase this constant and don't fill the frequency list. | |
427 | + * The user will be able to set by channel anyway... */ | |
428 | + | |
429 | +/* Maximum bit rates in the range struct */ | |
430 | +#define IW_MAX_BITRATES 32 | |
431 | + | |
432 | +/* Maximum tx powers in the range struct */ | |
433 | +#define IW_MAX_TXPOWER 8 | |
434 | +/* Note : if you more than 8 TXPowers, just set the max and min or | |
435 | + * a few of them in the struct iw_range. */ | |
436 | + | |
437 | +/* Maximum of address that you may set with SPY */ | |
438 | +#define IW_MAX_SPY 8 | |
439 | + | |
440 | +/* Maximum of address that you may get in the | |
441 | + list of access points in range */ | |
442 | +#define IW_MAX_AP 64 | |
443 | + | |
444 | +/* Maximum size of the ESSID and NICKN strings */ | |
445 | +#define IW_ESSID_MAX_SIZE 32 | |
446 | + | |
447 | +/* Modes of operation */ | |
448 | +#define IW_MODE_AUTO 0 /* Let the driver decides */ | |
449 | +#define IW_MODE_ADHOC 1 /* Single cell network */ | |
450 | +#define IW_MODE_INFRA 2 /* Multi cell network, roaming, ... */ | |
451 | +#define IW_MODE_MASTER 3 /* Synchronisation master or Access Point */ | |
452 | +#define IW_MODE_REPEAT 4 /* Wireless Repeater (forwarder) */ | |
453 | +#define IW_MODE_SECOND 5 /* Secondary master/repeater (backup) */ | |
454 | +#define IW_MODE_MONITOR 6 /* Passive monitor (listen only) */ | |
455 | + | |
456 | +/* Statistics flags (bitmask in updated) */ | |
457 | +#define IW_QUAL_QUAL_UPDATED 0x01 /* Value was updated since last read */ | |
458 | +#define IW_QUAL_LEVEL_UPDATED 0x02 | |
459 | +#define IW_QUAL_NOISE_UPDATED 0x04 | |
460 | +#define IW_QUAL_ALL_UPDATED 0x07 | |
461 | +#define IW_QUAL_DBM 0x08 /* Level + Noise are dBm */ | |
462 | +#define IW_QUAL_QUAL_INVALID 0x10 /* Driver doesn't provide value */ | |
463 | +#define IW_QUAL_LEVEL_INVALID 0x20 | |
464 | +#define IW_QUAL_NOISE_INVALID 0x40 | |
465 | +#define IW_QUAL_RCPI 0x80 /* Level + Noise are 802.11k RCPI */ | |
466 | +#define IW_QUAL_ALL_INVALID 0x70 | |
467 | + | |
468 | +/* Frequency flags */ | |
469 | +#define IW_FREQ_AUTO 0x00 /* Let the driver decides */ | |
470 | +#define IW_FREQ_FIXED 0x01 /* Force a specific value */ | |
471 | + | |
472 | +/* Maximum number of size of encoding token available | |
473 | + * they are listed in the range structure */ | |
474 | +#define IW_MAX_ENCODING_SIZES 8 | |
475 | + | |
476 | +/* Maximum size of the encoding token in bytes */ | |
477 | +#define IW_ENCODING_TOKEN_MAX 64 /* 512 bits (for now) */ | |
478 | + | |
479 | +/* Flags for encoding (along with the token) */ | |
480 | +#define IW_ENCODE_INDEX 0x00FF /* Token index (if needed) */ | |
481 | +#define IW_ENCODE_FLAGS 0xFF00 /* Flags defined below */ | |
482 | +#define IW_ENCODE_MODE 0xF000 /* Modes defined below */ | |
483 | +#define IW_ENCODE_DISABLED 0x8000 /* Encoding disabled */ | |
484 | +#define IW_ENCODE_ENABLED 0x0000 /* Encoding enabled */ | |
485 | +#define IW_ENCODE_RESTRICTED 0x4000 /* Refuse non-encoded packets */ | |
486 | +#define IW_ENCODE_OPEN 0x2000 /* Accept non-encoded packets */ | |
487 | +#define IW_ENCODE_NOKEY 0x0800 /* Key is write only, so not present */ | |
488 | +#define IW_ENCODE_TEMP 0x0400 /* Temporary key */ | |
489 | + | |
490 | +/* Power management flags available (along with the value, if any) */ | |
491 | +#define IW_POWER_ON 0x0000 /* No details... */ | |
492 | +#define IW_POWER_TYPE 0xF000 /* Type of parameter */ | |
493 | +#define IW_POWER_PERIOD 0x1000 /* Value is a period/duration of */ | |
494 | +#define IW_POWER_TIMEOUT 0x2000 /* Value is a timeout (to go asleep) */ | |
495 | +#define IW_POWER_SAVING 0x4000 /* Value is relative (how aggressive)*/ | |
496 | +#define IW_POWER_MODE 0x0F00 /* Power Management mode */ | |
497 | +#define IW_POWER_UNICAST_R 0x0100 /* Receive only unicast messages */ | |
498 | +#define IW_POWER_MULTICAST_R 0x0200 /* Receive only multicast messages */ | |
499 | +#define IW_POWER_ALL_R 0x0300 /* Receive all messages though PM */ | |
500 | +#define IW_POWER_FORCE_S 0x0400 /* Force PM procedure for sending unicast */ | |
501 | +#define IW_POWER_REPEATER 0x0800 /* Repeat broadcast messages in PM period */ | |
502 | +#define IW_POWER_MODIFIER 0x000F /* Modify a parameter */ | |
503 | +#define IW_POWER_MIN 0x0001 /* Value is a minimum */ | |
504 | +#define IW_POWER_MAX 0x0002 /* Value is a maximum */ | |
505 | +#define IW_POWER_RELATIVE 0x0004 /* Value is not in seconds/ms/us */ | |
506 | + | |
507 | +/* Transmit Power flags available */ | |
508 | +#define IW_TXPOW_TYPE 0x00FF /* Type of value */ | |
509 | +#define IW_TXPOW_DBM 0x0000 /* Value is in dBm */ | |
510 | +#define IW_TXPOW_MWATT 0x0001 /* Value is in mW */ | |
511 | +#define IW_TXPOW_RELATIVE 0x0002 /* Value is in arbitrary units */ | |
512 | +#define IW_TXPOW_RANGE 0x1000 /* Range of value between min/max */ | |
513 | + | |
514 | +/* Retry limits and lifetime flags available */ | |
515 | +#define IW_RETRY_ON 0x0000 /* No details... */ | |
516 | +#define IW_RETRY_TYPE 0xF000 /* Type of parameter */ | |
517 | +#define IW_RETRY_LIMIT 0x1000 /* Maximum number of retries*/ | |
518 | +#define IW_RETRY_LIFETIME 0x2000 /* Maximum duration of retries in us */ | |
519 | +#define IW_RETRY_MODIFIER 0x00FF /* Modify a parameter */ | |
520 | +#define IW_RETRY_MIN 0x0001 /* Value is a minimum */ | |
521 | +#define IW_RETRY_MAX 0x0002 /* Value is a maximum */ | |
522 | +#define IW_RETRY_RELATIVE 0x0004 /* Value is not in seconds/ms/us */ | |
523 | +#define IW_RETRY_SHORT 0x0010 /* Value is for short packets */ | |
524 | +#define IW_RETRY_LONG 0x0020 /* Value is for long packets */ | |
525 | + | |
526 | +/* Scanning request flags */ | |
527 | +#define IW_SCAN_DEFAULT 0x0000 /* Default scan of the driver */ | |
528 | +#define IW_SCAN_ALL_ESSID 0x0001 /* Scan all ESSIDs */ | |
529 | +#define IW_SCAN_THIS_ESSID 0x0002 /* Scan only this ESSID */ | |
530 | +#define IW_SCAN_ALL_FREQ 0x0004 /* Scan all Frequencies */ | |
531 | +#define IW_SCAN_THIS_FREQ 0x0008 /* Scan only this Frequency */ | |
532 | +#define IW_SCAN_ALL_MODE 0x0010 /* Scan all Modes */ | |
533 | +#define IW_SCAN_THIS_MODE 0x0020 /* Scan only this Mode */ | |
534 | +#define IW_SCAN_ALL_RATE 0x0040 /* Scan all Bit-Rates */ | |
535 | +#define IW_SCAN_THIS_RATE 0x0080 /* Scan only this Bit-Rate */ | |
536 | +/* struct iw_scan_req scan_type */ | |
537 | +#define IW_SCAN_TYPE_ACTIVE 0 | |
538 | +#define IW_SCAN_TYPE_PASSIVE 1 | |
539 | +/* Maximum size of returned data */ | |
540 | +#define IW_SCAN_MAX_DATA 4096 /* In bytes */ | |
541 | + | |
542 | +/* Max number of char in custom event - use multiple of them if needed */ | |
543 | +#define IW_CUSTOM_MAX 256 /* In bytes */ | |
544 | + | |
545 | +/* Generic information element */ | |
546 | +#define IW_GENERIC_IE_MAX 1024 | |
547 | + | |
548 | +/* MLME requests (SIOCSIWMLME / struct iw_mlme) */ | |
549 | +#define IW_MLME_DEAUTH 0 | |
550 | +#define IW_MLME_DISASSOC 1 | |
551 | + | |
552 | +/* SIOCSIWAUTH/SIOCGIWAUTH struct iw_param flags */ | |
553 | +#define IW_AUTH_INDEX 0x0FFF | |
554 | +#define IW_AUTH_FLAGS 0xF000 | |
555 | +/* SIOCSIWAUTH/SIOCGIWAUTH parameters (0 .. 4095) | |
556 | + * (IW_AUTH_INDEX mask in struct iw_param flags; this is the index of the | |
557 | + * parameter that is being set/get to; value will be read/written to | |
558 | + * struct iw_param value field) */ | |
559 | +#define IW_AUTH_WPA_VERSION 0 | |
560 | +#define IW_AUTH_CIPHER_PAIRWISE 1 | |
561 | +#define IW_AUTH_CIPHER_GROUP 2 | |
562 | +#define IW_AUTH_KEY_MGMT 3 | |
563 | +#define IW_AUTH_TKIP_COUNTERMEASURES 4 | |
564 | +#define IW_AUTH_DROP_UNENCRYPTED 5 | |
565 | +#define IW_AUTH_80211_AUTH_ALG 6 | |
566 | +#define IW_AUTH_WPA_ENABLED 7 | |
567 | +#define IW_AUTH_RX_UNENCRYPTED_EAPOL 8 | |
568 | +#define IW_AUTH_ROAMING_CONTROL 9 | |
569 | +#define IW_AUTH_PRIVACY_INVOKED 10 | |
570 | + | |
571 | +/* IW_AUTH_WPA_VERSION values (bit field) */ | |
572 | +#define IW_AUTH_WPA_VERSION_DISABLED 0x00000001 | |
573 | +#define IW_AUTH_WPA_VERSION_WPA 0x00000002 | |
574 | +#define IW_AUTH_WPA_VERSION_WPA2 0x00000004 | |
575 | + | |
576 | +/* IW_AUTH_PAIRWISE_CIPHER and IW_AUTH_GROUP_CIPHER values (bit field) */ | |
577 | +#define IW_AUTH_CIPHER_NONE 0x00000001 | |
578 | +#define IW_AUTH_CIPHER_WEP40 0x00000002 | |
579 | +#define IW_AUTH_CIPHER_TKIP 0x00000004 | |
580 | +#define IW_AUTH_CIPHER_CCMP 0x00000008 | |
581 | +#define IW_AUTH_CIPHER_WEP104 0x00000010 | |
582 | + | |
583 | +/* IW_AUTH_KEY_MGMT values (bit field) */ | |
584 | +#define IW_AUTH_KEY_MGMT_802_1X 1 | |
585 | +#define IW_AUTH_KEY_MGMT_PSK 2 | |
586 | + | |
587 | +/* IW_AUTH_80211_AUTH_ALG values (bit field) */ | |
588 | +#define IW_AUTH_ALG_OPEN_SYSTEM 0x00000001 | |
589 | +#define IW_AUTH_ALG_SHARED_KEY 0x00000002 | |
590 | +#define IW_AUTH_ALG_LEAP 0x00000004 | |
591 | + | |
592 | +/* IW_AUTH_ROAMING_CONTROL values */ | |
593 | +#define IW_AUTH_ROAMING_ENABLE 0 /* driver/firmware based roaming */ | |
594 | +#define IW_AUTH_ROAMING_DISABLE 1 /* user space program used for roaming | |
595 | + * control */ | |
596 | + | |
597 | +/* SIOCSIWENCODEEXT definitions */ | |
598 | +#define IW_ENCODE_SEQ_MAX_SIZE 8 | |
599 | +/* struct iw_encode_ext ->alg */ | |
600 | +#define IW_ENCODE_ALG_NONE 0 | |
601 | +#define IW_ENCODE_ALG_WEP 1 | |
602 | +#define IW_ENCODE_ALG_TKIP 2 | |
603 | +#define IW_ENCODE_ALG_CCMP 3 | |
604 | +/* struct iw_encode_ext ->ext_flags */ | |
605 | +#define IW_ENCODE_EXT_TX_SEQ_VALID 0x00000001 | |
606 | +#define IW_ENCODE_EXT_RX_SEQ_VALID 0x00000002 | |
607 | +#define IW_ENCODE_EXT_GROUP_KEY 0x00000004 | |
608 | +#define IW_ENCODE_EXT_SET_TX_KEY 0x00000008 | |
609 | + | |
610 | +/* IWEVMICHAELMICFAILURE : struct iw_michaelmicfailure ->flags */ | |
611 | +#define IW_MICFAILURE_KEY_ID 0x00000003 /* Key ID 0..3 */ | |
612 | +#define IW_MICFAILURE_GROUP 0x00000004 | |
613 | +#define IW_MICFAILURE_PAIRWISE 0x00000008 | |
614 | +#define IW_MICFAILURE_STAKEY 0x00000010 | |
615 | +#define IW_MICFAILURE_COUNT 0x00000060 /* 1 or 2 (0 = count not supported) | |
616 | + */ | |
617 | + | |
618 | +/* Bit field values for enc_capa in struct iw_range */ | |
619 | +#define IW_ENC_CAPA_WPA 0x00000001 | |
620 | +#define IW_ENC_CAPA_WPA2 0x00000002 | |
621 | +#define IW_ENC_CAPA_CIPHER_TKIP 0x00000004 | |
622 | +#define IW_ENC_CAPA_CIPHER_CCMP 0x00000008 | |
623 | + | |
624 | +/* Event capability macros - in (struct iw_range *)->event_capa | |
625 | + * Because we have more than 32 possible events, we use an array of | |
626 | + * 32 bit bitmasks. Note : 32 bits = 0x20 = 2^5. */ | |
627 | +#define IW_EVENT_CAPA_BASE(cmd) ((cmd >= SIOCIWFIRSTPRIV) ? \ | |
628 | + (cmd - SIOCIWFIRSTPRIV + 0x60) : \ | |
629 | + (cmd - SIOCSIWCOMMIT)) | |
630 | +#define IW_EVENT_CAPA_INDEX(cmd) (IW_EVENT_CAPA_BASE(cmd) >> 5) | |
631 | +#define IW_EVENT_CAPA_MASK(cmd) (1 << (IW_EVENT_CAPA_BASE(cmd) & 0x1F)) | |
632 | +/* Event capability constants - event autogenerated by the kernel | |
633 | + * This list is valid for most 802.11 devices, customise as needed... */ | |
634 | +#define IW_EVENT_CAPA_K_0 (IW_EVENT_CAPA_MASK(0x8B04) | \ | |
635 | + IW_EVENT_CAPA_MASK(0x8B06) | \ | |
636 | + IW_EVENT_CAPA_MASK(0x8B1A)) | |
637 | +#define IW_EVENT_CAPA_K_1 (IW_EVENT_CAPA_MASK(0x8B2A)) | |
638 | +/* "Easy" macro to set events in iw_range (less efficient) */ | |
639 | +#define IW_EVENT_CAPA_SET(event_capa, cmd) (event_capa[IW_EVENT_CAPA_INDEX(cmd)] |= IW_EVENT_CAPA_MASK(cmd)) | |
640 | +#define IW_EVENT_CAPA_SET_KERNEL(event_capa) {event_capa[0] |= IW_EVENT_CAPA_K_0; event_capa[1] |= IW_EVENT_CAPA_K_1; } | |
641 | + | |
642 | +/* Modulations bitmasks */ | |
643 | +#define IW_MODUL_ALL 0x00000000 /* Everything supported */ | |
644 | +#define IW_MODUL_FH 0x00000001 /* Frequency Hopping */ | |
645 | +#define IW_MODUL_DS 0x00000002 /* Original Direct Sequence */ | |
646 | +#define IW_MODUL_CCK 0x00000004 /* 802.11b : 5.5 + 11 Mb/s */ | |
647 | +#define IW_MODUL_11B (IW_MODUL_DS | IW_MODUL_CCK) | |
648 | +#define IW_MODUL_PBCC 0x00000008 /* TI : 5.5 + 11 + 22 Mb/s */ | |
649 | +#define IW_MODUL_OFDM_A 0x00000010 /* 802.11a : 54 Mb/s */ | |
650 | +#define IW_MODUL_11A (IW_MODUL_OFDM_A) | |
651 | +#define IW_MODUL_11AB (IW_MODUL_11B | IW_MODUL_11A) | |
652 | +#define IW_MODUL_OFDM_G 0x00000020 /* 802.11g : 54 Mb/s */ | |
653 | +#define IW_MODUL_11G (IW_MODUL_11B | IW_MODUL_OFDM_G) | |
654 | +#define IW_MODUL_11AG (IW_MODUL_11G | IW_MODUL_11A) | |
655 | +#define IW_MODUL_TURBO 0x00000040 /* ATH : bonding, 108 Mb/s */ | |
656 | +/* In here we should define MIMO stuff. Later... */ | |
657 | +#define IW_MODUL_CUSTOM 0x40000000 /* Driver specific */ | |
658 | + | |
659 | +/* Bitrate flags available */ | |
660 | +#define IW_BITRATE_TYPE 0x00FF /* Type of value */ | |
661 | +#define IW_BITRATE_UNICAST 0x0001 /* Maximum/Fixed unicast bitrate */ | |
662 | +#define IW_BITRATE_BROADCAST 0x0002 /* Fixed broadcast bitrate */ | |
663 | + | |
664 | +/****************************** TYPES ******************************/ | |
665 | + | |
666 | +/* --------------------------- SUBTYPES --------------------------- */ | |
667 | +/* | |
668 | + * Generic format for most parameters that fit in an int | |
669 | + */ | |
670 | +struct iw_param | |
671 | +{ | |
672 | + __s32 value; /* The value of the parameter itself */ | |
673 | + __u8 fixed; /* Hardware should not use auto select */ | |
674 | + __u8 disabled; /* Disable the feature */ | |
675 | + __u16 flags; /* Various specifc flags (if any) */ | |
676 | +}; | |
677 | + | |
678 | +/* | |
679 | + * For all data larger than 16 octets, we need to use a | |
680 | + * pointer to memory allocated in user space. | |
681 | + */ | |
682 | +struct iw_point | |
683 | +{ | |
684 | + void __user *pointer; /* Pointer to the data (in user space) */ | |
685 | + __u16 length; /* number of fields or size in bytes */ | |
686 | + __u16 flags; /* Optional params */ | |
687 | +}; | |
688 | + | |
689 | +/* | |
690 | + * A frequency | |
691 | + * For numbers lower than 10^9, we encode the number in 'm' and | |
692 | + * set 'e' to 0 | |
693 | + * For number greater than 10^9, we divide it by the lowest power | |
694 | + * of 10 to get 'm' lower than 10^9, with 'm'= f / (10^'e')... | |
695 | + * The power of 10 is in 'e', the result of the division is in 'm'. | |
696 | + */ | |
697 | +struct iw_freq | |
698 | +{ | |
699 | + __s32 m; /* Mantissa */ | |
700 | + __s16 e; /* Exponent */ | |
701 | + __u8 i; /* List index (when in range struct) */ | |
702 | + __u8 flags; /* Flags (fixed/auto) */ | |
703 | +}; | |
704 | + | |
705 | +/* | |
706 | + * Quality of the link | |
707 | + */ | |
708 | +struct iw_quality | |
709 | +{ | |
710 | + __u8 qual; /* link quality (%retries, SNR, | |
711 | + %missed beacons or better...) */ | |
712 | + __u8 level; /* signal level (dBm) */ | |
713 | + __u8 noise; /* noise level (dBm) */ | |
714 | + __u8 updated; /* Flags to know if updated */ | |
715 | +}; | |
716 | + | |
717 | +/* | |
718 | + * Packet discarded in the wireless adapter due to | |
719 | + * "wireless" specific problems... | |
720 | + * Note : the list of counter and statistics in net_device_stats | |
721 | + * is already pretty exhaustive, and you should use that first. | |
722 | + * This is only additional stats... | |
723 | + */ | |
724 | +struct iw_discarded | |
725 | +{ | |
726 | + __u32 nwid; /* Rx : Wrong nwid/essid */ | |
727 | + __u32 code; /* Rx : Unable to code/decode (WEP) */ | |
728 | + __u32 fragment; /* Rx : Can't perform MAC reassembly */ | |
729 | + __u32 retries; /* Tx : Max MAC retries num reached */ | |
730 | + __u32 misc; /* Others cases */ | |
731 | +}; | |
732 | + | |
733 | +/* | |
734 | + * Packet/Time period missed in the wireless adapter due to | |
735 | + * "wireless" specific problems... | |
736 | + */ | |
737 | +struct iw_missed | |
738 | +{ | |
739 | + __u32 beacon; /* Missed beacons/superframe */ | |
740 | +}; | |
741 | + | |
742 | +/* | |
743 | + * Quality range (for spy threshold) | |
744 | + */ | |
745 | +struct iw_thrspy | |
746 | +{ | |
747 | + struct sockaddr addr; /* Source address (hw/mac) */ | |
748 | + struct iw_quality qual; /* Quality of the link */ | |
749 | + struct iw_quality low; /* Low threshold */ | |
750 | + struct iw_quality high; /* High threshold */ | |
751 | +}; | |
752 | + | |
753 | +/* | |
754 | + * Optional data for scan request | |
755 | + * | |
756 | + * Note: these optional parameters are controlling parameters for the | |
757 | + * scanning behavior, these do not apply to getting scan results | |
758 | + * (SIOCGIWSCAN). Drivers are expected to keep a local BSS table and | |
759 | + * provide a merged results with all BSSes even if the previous scan | |
760 | + * request limited scanning to a subset, e.g., by specifying an SSID. | |
761 | + * Especially, scan results are required to include an entry for the | |
762 | + * current BSS if the driver is in Managed mode and associated with an AP. | |
763 | + */ | |
764 | +struct iw_scan_req | |
765 | +{ | |
766 | + __u8 scan_type; /* IW_SCAN_TYPE_{ACTIVE,PASSIVE} */ | |
767 | + __u8 essid_len; | |
768 | + __u8 num_channels; /* num entries in channel_list; | |
769 | + * 0 = scan all allowed channels */ | |
770 | + __u8 flags; /* reserved as padding; use zero, this may | |
771 | + * be used in the future for adding flags | |
772 | + * to request different scan behavior */ | |
773 | + struct sockaddr bssid; /* ff:ff:ff:ff:ff:ff for broadcast BSSID or | |
774 | + * individual address of a specific BSS */ | |
775 | + | |
776 | + /* | |
777 | + * Use this ESSID if IW_SCAN_THIS_ESSID flag is used instead of using | |
778 | + * the current ESSID. This allows scan requests for specific ESSID | |
779 | + * without having to change the current ESSID and potentially breaking | |
780 | + * the current association. | |
781 | + */ | |
782 | + __u8 essid[IW_ESSID_MAX_SIZE]; | |
783 | + | |
784 | + /* | |
785 | + * Optional parameters for changing the default scanning behavior. | |
786 | + * These are based on the MLME-SCAN.request from IEEE Std 802.11. | |
787 | + * TU is 1.024 ms. If these are set to 0, driver is expected to use | |
788 | + * reasonable default values. min_channel_time defines the time that | |
789 | + * will be used to wait for the first reply on each channel. If no | |
790 | + * replies are received, next channel will be scanned after this. If | |
791 | + * replies are received, total time waited on the channel is defined by | |
792 | + * max_channel_time. | |
793 | + */ | |
794 | + __u32 min_channel_time; /* in TU */ | |
795 | + __u32 max_channel_time; /* in TU */ | |
796 | + | |
797 | + struct iw_freq channel_list[IW_MAX_FREQUENCIES]; | |
798 | +}; | |
799 | + | |
800 | +/* ------------------------- WPA SUPPORT ------------------------- */ | |
801 | + | |
802 | +/* | |
803 | + * Extended data structure for get/set encoding (this is used with | |
804 | + * SIOCSIWENCODEEXT/SIOCGIWENCODEEXT. struct iw_point and IW_ENCODE_* | |
805 | + * flags are used in the same way as with SIOCSIWENCODE/SIOCGIWENCODE and | |
806 | + * only the data contents changes (key data -> this structure, including | |
807 | + * key data). | |
808 | + * | |
809 | + * If the new key is the first group key, it will be set as the default | |
810 | + * TX key. Otherwise, default TX key index is only changed if | |
811 | + * IW_ENCODE_EXT_SET_TX_KEY flag is set. | |
812 | + * | |
813 | + * Key will be changed with SIOCSIWENCODEEXT in all cases except for | |
814 | + * special "change TX key index" operation which is indicated by setting | |
815 | + * key_len = 0 and ext_flags |= IW_ENCODE_EXT_SET_TX_KEY. | |
816 | + * | |
817 | + * tx_seq/rx_seq are only used when respective | |
818 | + * IW_ENCODE_EXT_{TX,RX}_SEQ_VALID flag is set in ext_flags. Normal | |
819 | + * TKIP/CCMP operation is to set RX seq with SIOCSIWENCODEEXT and start | |
820 | + * TX seq from zero whenever key is changed. SIOCGIWENCODEEXT is normally | |
821 | + * used only by an Authenticator (AP or an IBSS station) to get the | |
822 | + * current TX sequence number. Using TX_SEQ_VALID for SIOCSIWENCODEEXT and | |
823 | + * RX_SEQ_VALID for SIOCGIWENCODEEXT are optional, but can be useful for | |
824 | + * debugging/testing. | |
825 | + */ | |
826 | +struct iw_encode_ext | |
827 | +{ | |
828 | + __u32 ext_flags; /* IW_ENCODE_EXT_* */ | |
829 | + __u8 tx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */ | |
830 | + __u8 rx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */ | |
831 | + struct sockaddr addr; /* ff:ff:ff:ff:ff:ff for broadcast/multicast | |
832 | + * (group) keys or unicast address for | |
833 | + * individual keys */ | |
834 | + __u16 alg; /* IW_ENCODE_ALG_* */ | |
835 | + __u16 key_len; | |
836 | + __u8 key[0]; | |
837 | +}; | |
838 | + | |
839 | +/* SIOCSIWMLME data */ | |
840 | +struct iw_mlme | |
841 | +{ | |
842 | + __u16 cmd; /* IW_MLME_* */ | |
843 | + __u16 reason_code; | |
844 | + struct sockaddr addr; | |
845 | +}; | |
846 | + | |
847 | +/* SIOCSIWPMKSA data */ | |
848 | +#define IW_PMKSA_ADD 1 | |
849 | +#define IW_PMKSA_REMOVE 2 | |
850 | +#define IW_PMKSA_FLUSH 3 | |
851 | + | |
852 | +#define IW_PMKID_LEN 16 | |
853 | + | |
854 | +struct iw_pmksa | |
855 | +{ | |
856 | + __u32 cmd; /* IW_PMKSA_* */ | |
857 | + struct sockaddr bssid; | |
858 | + __u8 pmkid[IW_PMKID_LEN]; | |
859 | +}; | |
860 | + | |
861 | +/* IWEVMICHAELMICFAILURE data */ | |
862 | +struct iw_michaelmicfailure | |
863 | +{ | |
864 | + __u32 flags; | |
865 | + struct sockaddr src_addr; | |
866 | + __u8 tsc[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */ | |
867 | +}; | |
868 | + | |
869 | +/* IWEVPMKIDCAND data */ | |
870 | +#define IW_PMKID_CAND_PREAUTH 0x00000001 /* RNS pre-authentication enabled */ | |
871 | +struct iw_pmkid_cand | |
872 | +{ | |
873 | + __u32 flags; /* IW_PMKID_CAND_* */ | |
874 | + __u32 index; /* the smaller the index, the higher the | |
875 | + * priority */ | |
876 | + struct sockaddr bssid; | |
877 | +}; | |
878 | + | |
879 | +/* ------------------------ WIRELESS STATS ------------------------ */ | |
880 | +/* | |
881 | + * Wireless statistics (used for /proc/net/wireless) | |
882 | + */ | |
883 | +struct iw_statistics | |
884 | +{ | |
885 | + __u16 status; /* Status | |
886 | + * - device dependent for now */ | |
887 | + | |
888 | + struct iw_quality qual; /* Quality of the link | |
889 | + * (instant/mean/max) */ | |
890 | + struct iw_discarded discard; /* Packet discarded counts */ | |
891 | + struct iw_missed miss; /* Packet missed counts */ | |
892 | +}; | |
893 | + | |
894 | +/* ------------------------ IOCTL REQUEST ------------------------ */ | |
895 | +/* | |
896 | + * This structure defines the payload of an ioctl, and is used | |
897 | + * below. | |
898 | + * | |
899 | + * Note that this structure should fit on the memory footprint | |
900 | + * of iwreq (which is the same as ifreq), which mean a max size of | |
901 | + * 16 octets = 128 bits. Warning, pointers might be 64 bits wide... | |
902 | + * You should check this when increasing the structures defined | |
903 | + * above in this file... | |
904 | + */ | |
905 | +union iwreq_data | |
906 | +{ | |
907 | + /* Config - generic */ | |
908 | + char name[IFNAMSIZ]; | |
909 | + /* Name : used to verify the presence of wireless extensions. | |
910 | + * Name of the protocol/provider... */ | |
911 | + | |
912 | + struct iw_point essid; /* Extended network name */ | |
913 | + struct iw_param nwid; /* network id (or domain - the cell) */ | |
914 | + struct iw_freq freq; /* frequency or channel : | |
915 | + * 0-1000 = channel | |
916 | + * > 1000 = frequency in Hz */ | |
917 | + | |
918 | + struct iw_param sens; /* signal level threshold */ | |
919 | + struct iw_param bitrate; /* default bit rate */ | |
920 | + struct iw_param txpower; /* default transmit power */ | |
921 | + struct iw_param rts; /* RTS threshold threshold */ | |
922 | + struct iw_param frag; /* Fragmentation threshold */ | |
923 | + __u32 mode; /* Operation mode */ | |
924 | + struct iw_param retry; /* Retry limits & lifetime */ | |
925 | + | |
926 | + struct iw_point encoding; /* Encoding stuff : tokens */ | |
927 | + struct iw_param power; /* PM duration/timeout */ | |
928 | + struct iw_quality qual; /* Quality part of statistics */ | |
929 | + | |
930 | + struct sockaddr ap_addr; /* Access point address */ | |
931 | + struct sockaddr addr; /* Destination address (hw/mac) */ | |
932 | + | |
933 | + struct iw_param param; /* Other small parameters */ | |
934 | + struct iw_point data; /* Other large parameters */ | |
935 | +}; | |
936 | + | |
937 | +/* | |
938 | + * The structure to exchange data for ioctl. | |
939 | + * This structure is the same as 'struct ifreq', but (re)defined for | |
940 | + * convenience... | |
941 | + * Do I need to remind you about structure size (32 octets) ? | |
942 | + */ | |
943 | +struct iwreq | |
944 | +{ | |
945 | + union | |
946 | + { | |
947 | + char ifrn_name[IFNAMSIZ]; /* if name, e.g. "eth0" */ | |
948 | + } ifr_ifrn; | |
949 | + | |
950 | + /* Data part (defined just above) */ | |
951 | + union iwreq_data u; | |
952 | +}; | |
953 | + | |
954 | +/* -------------------------- IOCTL DATA -------------------------- */ | |
955 | +/* | |
956 | + * For those ioctl which want to exchange mode data that what could | |
957 | + * fit in the above structure... | |
958 | + */ | |
959 | + | |
960 | +/* | |
961 | + * Range of parameters | |
962 | + */ | |
963 | + | |
964 | +struct iw_range | |
965 | +{ | |
966 | + /* Informative stuff (to choose between different interface) */ | |
967 | + __u32 throughput; /* To give an idea... */ | |
968 | + /* In theory this value should be the maximum benchmarked | |
969 | + * TCP/IP throughput, because with most of these devices the | |
970 | + * bit rate is meaningless (overhead an co) to estimate how | |
971 | + * fast the connection will go and pick the fastest one. | |
972 | + * I suggest people to play with Netperf or any benchmark... | |
973 | + */ | |
974 | + | |
975 | + /* NWID (or domain id) */ | |
976 | + __u32 min_nwid; /* Minimal NWID we are able to set */ | |
977 | + __u32 max_nwid; /* Maximal NWID we are able to set */ | |
978 | + | |
979 | + /* Old Frequency (backward compat - moved lower ) */ | |
980 | + __u16 old_num_channels; | |
981 | + __u8 old_num_frequency; | |
982 | + | |
983 | + /* Wireless event capability bitmasks */ | |
984 | + __u32 event_capa[6]; | |
985 | + | |
986 | + /* signal level threshold range */ | |
987 | + __s32 sensitivity; | |
988 | + | |
989 | + /* Quality of link & SNR stuff */ | |
990 | + /* Quality range (link, level, noise) | |
991 | + * If the quality is absolute, it will be in the range [0 ; max_qual], | |
992 | + * if the quality is dBm, it will be in the range [max_qual ; 0]. | |
993 | + * Don't forget that we use 8 bit arithmetics... */ | |
994 | + struct iw_quality max_qual; /* Quality of the link */ | |
995 | + /* This should contain the average/typical values of the quality | |
996 | + * indicator. This should be the threshold between a "good" and | |
997 | + * a "bad" link (example : monitor going from green to orange). | |
998 | + * Currently, user space apps like quality monitors don't have any | |
999 | + * way to calibrate the measurement. With this, they can split | |
1000 | + * the range between 0 and max_qual in different quality level | |
1001 | + * (using a geometric subdivision centered on the average). | |
1002 | + * I expect that people doing the user space apps will feedback | |
1003 | + * us on which value we need to put in each driver... */ | |
1004 | + struct iw_quality avg_qual; /* Quality of the link */ | |
1005 | + | |
1006 | + /* Rates */ | |
1007 | + __u8 num_bitrates; /* Number of entries in the list */ | |
1008 | + __s32 bitrate[IW_MAX_BITRATES]; /* list, in bps */ | |
1009 | + | |
1010 | + /* RTS threshold */ | |
1011 | + __s32 min_rts; /* Minimal RTS threshold */ | |
1012 | + __s32 max_rts; /* Maximal RTS threshold */ | |
1013 | + | |
1014 | + /* Frag threshold */ | |
1015 | + __s32 min_frag; /* Minimal frag threshold */ | |
1016 | + __s32 max_frag; /* Maximal frag threshold */ | |
1017 | + | |
1018 | + /* Power Management duration & timeout */ | |
1019 | + __s32 min_pmp; /* Minimal PM period */ | |
1020 | + __s32 max_pmp; /* Maximal PM period */ | |
1021 | + __s32 min_pmt; /* Minimal PM timeout */ | |
1022 | + __s32 max_pmt; /* Maximal PM timeout */ | |
1023 | + __u16 pmp_flags; /* How to decode max/min PM period */ | |
1024 | + __u16 pmt_flags; /* How to decode max/min PM timeout */ | |
1025 | + __u16 pm_capa; /* What PM options are supported */ | |
1026 | + | |
1027 | + /* Encoder stuff */ | |
1028 | + __u16 encoding_size[IW_MAX_ENCODING_SIZES]; /* Different token sizes */ | |
1029 | + __u8 num_encoding_sizes; /* Number of entry in the list */ | |
1030 | + __u8 max_encoding_tokens; /* Max number of tokens */ | |
1031 | + /* For drivers that need a "login/passwd" form */ | |
1032 | + __u8 encoding_login_index; /* token index for login token */ | |
1033 | + | |
1034 | + /* Transmit power */ | |
1035 | + __u16 txpower_capa; /* What options are supported */ | |
1036 | + __u8 num_txpower; /* Number of entries in the list */ | |
1037 | + __s32 txpower[IW_MAX_TXPOWER]; /* list, in bps */ | |
1038 | + | |
1039 | + /* Wireless Extension version info */ | |
1040 | + __u8 we_version_compiled; /* Must be WIRELESS_EXT */ | |
1041 | + __u8 we_version_source; /* Last update of source */ | |
1042 | + | |
1043 | + /* Retry limits and lifetime */ | |
1044 | + __u16 retry_capa; /* What retry options are supported */ | |
1045 | + __u16 retry_flags; /* How to decode max/min retry limit */ | |
1046 | + __u16 r_time_flags; /* How to decode max/min retry life */ | |
1047 | + __s32 min_retry; /* Minimal number of retries */ | |
1048 | + __s32 max_retry; /* Maximal number of retries */ | |
1049 | + __s32 min_r_time; /* Minimal retry lifetime */ | |
1050 | + __s32 max_r_time; /* Maximal retry lifetime */ | |
1051 | + | |
1052 | + /* Frequency */ | |
1053 | + __u16 num_channels; /* Number of channels [0; num - 1] */ | |
1054 | + __u8 num_frequency; /* Number of entry in the list */ | |
1055 | + struct iw_freq freq[IW_MAX_FREQUENCIES]; /* list */ | |
1056 | + /* Note : this frequency list doesn't need to fit channel numbers, | |
1057 | + * because each entry contain its channel index */ | |
1058 | + | |
1059 | + __u32 enc_capa; /* IW_ENC_CAPA_* bit field */ | |
1060 | + | |
1061 | + /* More power management stuff */ | |
1062 | + __s32 min_pms; /* Minimal PM saving */ | |
1063 | + __s32 max_pms; /* Maximal PM saving */ | |
1064 | + __u16 pms_flags; /* How to decode max/min PM saving */ | |
1065 | + | |
1066 | + /* All available modulations for driver (hw may support less) */ | |
1067 | + __s32 modul_capa; /* IW_MODUL_* bit field */ | |
1068 | + | |
1069 | + /* More bitrate stuff */ | |
1070 | + __u32 bitrate_capa; /* Types of bitrates supported */ | |
1071 | +}; | |
1072 | + | |
1073 | +/* | |
1074 | + * Private ioctl interface information | |
1075 | + */ | |
1076 | + | |
1077 | +struct iw_priv_args | |
1078 | +{ | |
1079 | + __u32 cmd; /* Number of the ioctl to issue */ | |
1080 | + __u16 set_args; /* Type and number of args */ | |
1081 | + __u16 get_args; /* Type and number of args */ | |
1082 | + char name[IFNAMSIZ]; /* Name of the extension */ | |
1083 | +}; | |
1084 | + | |
1085 | +/* ----------------------- WIRELESS EVENTS ----------------------- */ | |
1086 | +/* | |
1087 | + * Wireless events are carried through the rtnetlink socket to user | |
1088 | + * space. They are encapsulated in the IFLA_WIRELESS field of | |
1089 | + * a RTM_NEWLINK message. | |
1090 | + */ | |
1091 | + | |
1092 | +/* | |
1093 | + * A Wireless Event. Contains basically the same data as the ioctl... | |
1094 | + */ | |
1095 | +struct iw_event | |
1096 | +{ | |
1097 | + __u16 len; /* Real lenght of this stuff */ | |
1098 | + __u16 cmd; /* Wireless IOCTL */ | |
1099 | + union iwreq_data u; /* IOCTL fixed payload */ | |
1100 | +}; | |
1101 | + | |
1102 | +/* Size of the Event prefix (including padding and alignement junk) */ | |
1103 | +#define IW_EV_LCP_LEN (sizeof(struct iw_event) - sizeof(union iwreq_data)) | |
1104 | +/* Size of the various events */ | |
1105 | +#define IW_EV_CHAR_LEN (IW_EV_LCP_LEN + IFNAMSIZ) | |
1106 | +#define IW_EV_UINT_LEN (IW_EV_LCP_LEN + sizeof(__u32)) | |
1107 | +#define IW_EV_FREQ_LEN (IW_EV_LCP_LEN + sizeof(struct iw_freq)) | |
1108 | +#define IW_EV_PARAM_LEN (IW_EV_LCP_LEN + sizeof(struct iw_param)) | |
1109 | +#define IW_EV_ADDR_LEN (IW_EV_LCP_LEN + sizeof(struct sockaddr)) | |
1110 | +#define IW_EV_QUAL_LEN (IW_EV_LCP_LEN + sizeof(struct iw_quality)) | |
1111 | + | |
1112 | +/* iw_point events are special. First, the payload (extra data) come at | |
1113 | + * the end of the event, so they are bigger than IW_EV_POINT_LEN. Second, | |
1114 | + * we omit the pointer, so start at an offset. */ | |
1115 | +#define IW_EV_POINT_OFF (((char *) &(((struct iw_point *) NULL)->length)) - \ | |
1116 | + (char *) NULL) | |
1117 | +#define IW_EV_POINT_LEN (IW_EV_LCP_LEN + sizeof(struct iw_point) - \ | |
1118 | + IW_EV_POINT_OFF) | |
1119 | + | |
1120 | +#endif /* _LINUX_WIRELESS_H */ |
@@ -0,0 +1,1139 @@ | ||
1 | +/* | |
2 | + * This file define a set of standard wireless extensions | |
3 | + * | |
4 | + * Version : 22 16.3.07 | |
5 | + * | |
6 | + * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> | |
7 | + * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved. | |
8 | + */ | |
9 | + | |
10 | +#ifndef _LINUX_WIRELESS_H | |
11 | +#define _LINUX_WIRELESS_H | |
12 | + | |
13 | +/************************** DOCUMENTATION **************************/ | |
14 | +/* | |
15 | + * Initial APIs (1996 -> onward) : | |
16 | + * ----------------------------- | |
17 | + * Basically, the wireless extensions are for now a set of standard ioctl | |
18 | + * call + /proc/net/wireless | |
19 | + * | |
20 | + * The entry /proc/net/wireless give statistics and information on the | |
21 | + * driver. | |
22 | + * This is better than having each driver having its entry because | |
23 | + * its centralised and we may remove the driver module safely. | |
24 | + * | |
25 | + * Ioctl are used to configure the driver and issue commands. This is | |
26 | + * better than command line options of insmod because we may want to | |
27 | + * change dynamically (while the driver is running) some parameters. | |
28 | + * | |
29 | + * The ioctl mechanimsm are copied from standard devices ioctl. | |
30 | + * We have the list of command plus a structure descibing the | |
31 | + * data exchanged... | |
32 | + * Note that to add these ioctl, I was obliged to modify : | |
33 | + * # net/core/dev.c (two place + add include) | |
34 | + * # net/ipv4/af_inet.c (one place + add include) | |
35 | + * | |
36 | + * /proc/net/wireless is a copy of /proc/net/dev. | |
37 | + * We have a structure for data passed from the driver to /proc/net/wireless | |
38 | + * Too add this, I've modified : | |
39 | + * # net/core/dev.c (two other places) | |
40 | + * # include/linux/netdevice.h (one place) | |
41 | + * # include/linux/proc_fs.h (one place) | |
42 | + * | |
43 | + * New driver API (2002 -> onward) : | |
44 | + * ------------------------------- | |
45 | + * This file is only concerned with the user space API and common definitions. | |
46 | + * The new driver API is defined and documented in : | |
47 | + * # include/net/iw_handler.h | |
48 | + * | |
49 | + * Note as well that /proc/net/wireless implementation has now moved in : | |
50 | + * # net/core/wireless.c | |
51 | + * | |
52 | + * Wireless Events (2002 -> onward) : | |
53 | + * -------------------------------- | |
54 | + * Events are defined at the end of this file, and implemented in : | |
55 | + * # net/core/wireless.c | |
56 | + * | |
57 | + * Other comments : | |
58 | + * -------------- | |
59 | + * Do not add here things that are redundant with other mechanisms | |
60 | + * (drivers init, ifconfig, /proc/net/dev, ...) and with are not | |
61 | + * wireless specific. | |
62 | + * | |
63 | + * These wireless extensions are not magic : each driver has to provide | |
64 | + * support for them... | |
65 | + * | |
66 | + * IMPORTANT NOTE : As everything in the kernel, this is very much a | |
67 | + * work in progress. Contact me if you have ideas of improvements... | |
68 | + */ | |
69 | + | |
70 | +/***************************** INCLUDES *****************************/ | |
71 | + | |
72 | +/* This header is used in user-space, therefore need to be sanitised | |
73 | + * for that purpose. Those includes are usually not compatible with glibc. | |
74 | + * To know which includes to use in user-space, check iwlib.h. */ | |
75 | +#ifdef __KERNEL__ | |
76 | +#include <linux/types.h> /* for "caddr_t" et al */ | |
77 | +#include <linux/socket.h> /* for "struct sockaddr" et al */ | |
78 | +#include <linux/if.h> /* for IFNAMSIZ and co... */ | |
79 | +#endif /* __KERNEL__ */ | |
80 | + | |
81 | +/***************************** VERSION *****************************/ | |
82 | +/* | |
83 | + * This constant is used to know the availability of the wireless | |
84 | + * extensions and to know which version of wireless extensions it is | |
85 | + * (there is some stuff that will be added in the future...) | |
86 | + * I just plan to increment with each new version. | |
87 | + */ | |
88 | +#define WIRELESS_EXT 22 | |
89 | + | |
90 | +/* | |
91 | + * Changes : | |
92 | + * | |
93 | + * V2 to V3 | |
94 | + * -------- | |
95 | + * Alan Cox start some incompatibles changes. I've integrated a bit more. | |
96 | + * - Encryption renamed to Encode to avoid US regulation problems | |
97 | + * - Frequency changed from float to struct to avoid problems on old 386 | |
98 | + * | |
99 | + * V3 to V4 | |
100 | + * -------- | |
101 | + * - Add sensitivity | |
102 | + * | |
103 | + * V4 to V5 | |
104 | + * -------- | |
105 | + * - Missing encoding definitions in range | |
106 | + * - Access points stuff | |
107 | + * | |
108 | + * V5 to V6 | |
109 | + * -------- | |
110 | + * - 802.11 support (ESSID ioctls) | |
111 | + * | |
112 | + * V6 to V7 | |
113 | + * -------- | |
114 | + * - define IW_ESSID_MAX_SIZE and IW_MAX_AP | |
115 | + * | |
116 | + * V7 to V8 | |
117 | + * -------- | |
118 | + * - Changed my e-mail address | |
119 | + * - More 802.11 support (nickname, rate, rts, frag) | |
120 | + * - List index in frequencies | |
121 | + * | |
122 | + * V8 to V9 | |
123 | + * -------- | |
124 | + * - Support for 'mode of operation' (ad-hoc, managed...) | |
125 | + * - Support for unicast and multicast power saving | |
126 | + * - Change encoding to support larger tokens (>64 bits) | |
127 | + * - Updated iw_params (disable, flags) and use it for NWID | |
128 | + * - Extracted iw_point from iwreq for clarity | |
129 | + * | |
130 | + * V9 to V10 | |
131 | + * --------- | |
132 | + * - Add PM capability to range structure | |
133 | + * - Add PM modifier : MAX/MIN/RELATIVE | |
134 | + * - Add encoding option : IW_ENCODE_NOKEY | |
135 | + * - Add TxPower ioctls (work like TxRate) | |
136 | + * | |
137 | + * V10 to V11 | |
138 | + * ---------- | |
139 | + * - Add WE version in range (help backward/forward compatibility) | |
140 | + * - Add retry ioctls (work like PM) | |
141 | + * | |
142 | + * V11 to V12 | |
143 | + * ---------- | |
144 | + * - Add SIOCSIWSTATS to get /proc/net/wireless programatically | |
145 | + * - Add DEV PRIVATE IOCTL to avoid collisions in SIOCDEVPRIVATE space | |
146 | + * - Add new statistics (frag, retry, beacon) | |
147 | + * - Add average quality (for user space calibration) | |
148 | + * | |
149 | + * V12 to V13 | |
150 | + * ---------- | |
151 | + * - Document creation of new driver API. | |
152 | + * - Extract union iwreq_data from struct iwreq (for new driver API). | |
153 | + * - Rename SIOCSIWNAME as SIOCSIWCOMMIT | |
154 | + * | |
155 | + * V13 to V14 | |
156 | + * ---------- | |
157 | + * - Wireless Events support : define struct iw_event | |
158 | + * - Define additional specific event numbers | |
159 | + * - Add "addr" and "param" fields in union iwreq_data | |
160 | + * - AP scanning stuff (SIOCSIWSCAN and friends) | |
161 | + * | |
162 | + * V14 to V15 | |
163 | + * ---------- | |
164 | + * - Add IW_PRIV_TYPE_ADDR for struct sockaddr private arg | |
165 | + * - Make struct iw_freq signed (both m & e), add explicit padding | |
166 | + * - Add IWEVCUSTOM for driver specific event/scanning token | |
167 | + * - Add IW_MAX_GET_SPY for driver returning a lot of addresses | |
168 | + * - Add IW_TXPOW_RANGE for range of Tx Powers | |
169 | + * - Add IWEVREGISTERED & IWEVEXPIRED events for Access Points | |
170 | + * - Add IW_MODE_MONITOR for passive monitor | |
171 | + * | |
172 | + * V15 to V16 | |
173 | + * ---------- | |
174 | + * - Increase the number of bitrates in iw_range to 32 (for 802.11g) | |
175 | + * - Increase the number of frequencies in iw_range to 32 (for 802.11b+a) | |
176 | + * - Reshuffle struct iw_range for increases, add filler | |
177 | + * - Increase IW_MAX_AP to 64 for driver returning a lot of addresses | |
178 | + * - Remove IW_MAX_GET_SPY because conflict with enhanced spy support | |
179 | + * - Add SIOCSIWTHRSPY/SIOCGIWTHRSPY and "struct iw_thrspy" | |
180 | + * - Add IW_ENCODE_TEMP and iw_range->encoding_login_index | |
181 | + * | |
182 | + * V16 to V17 | |
183 | + * ---------- | |
184 | + * - Add flags to frequency -> auto/fixed | |
185 | + * - Document (struct iw_quality *)->updated, add new flags (INVALID) | |
186 | + * - Wireless Event capability in struct iw_range | |
187 | + * - Add support for relative TxPower (yick !) | |
188 | + * | |
189 | + * V17 to V18 (From Jouni Malinen <jkmaline@cc.hut.fi>) | |
190 | + * ---------- | |
191 | + * - Add support for WPA/WPA2 | |
192 | + * - Add extended encoding configuration (SIOCSIWENCODEEXT and | |
193 | + * SIOCGIWENCODEEXT) | |
194 | + * - Add SIOCSIWGENIE/SIOCGIWGENIE | |
195 | + * - Add SIOCSIWMLME | |
196 | + * - Add SIOCSIWPMKSA | |
197 | + * - Add struct iw_range bit field for supported encoding capabilities | |
198 | + * - Add optional scan request parameters for SIOCSIWSCAN | |
199 | + * - Add SIOCSIWAUTH/SIOCGIWAUTH for setting authentication and WPA | |
200 | + * related parameters (extensible up to 4096 parameter values) | |
201 | + * - Add wireless events: IWEVGENIE, IWEVMICHAELMICFAILURE, | |
202 | + * IWEVASSOCREQIE, IWEVASSOCRESPIE, IWEVPMKIDCAND | |
203 | + * | |
204 | + * V18 to V19 | |
205 | + * ---------- | |
206 | + * - Remove (struct iw_point *)->pointer from events and streams | |
207 | + * - Remove header includes to help user space | |
208 | + * - Increase IW_ENCODING_TOKEN_MAX from 32 to 64 | |
209 | + * - Add IW_QUAL_ALL_UPDATED and IW_QUAL_ALL_INVALID macros | |
210 | + * - Add explicit flag to tell stats are in dBm : IW_QUAL_DBM | |
211 | + * - Add IW_IOCTL_IDX() and IW_EVENT_IDX() macros | |
212 | + * | |
213 | + * V19 to V20 | |
214 | + * ---------- | |
215 | + * - RtNetlink requests support (SET/GET) | |
216 | + * | |
217 | + * V20 to V21 | |
218 | + * ---------- | |
219 | + * - Remove (struct net_device *)->get_wireless_stats() | |
220 | + * - Change length in ESSID and NICK to strlen() instead of strlen()+1 | |
221 | + * - Add IW_RETRY_SHORT/IW_RETRY_LONG retry modifiers | |
222 | + * - Power/Retry relative values no longer * 100000 | |
223 | + * - Add explicit flag to tell stats are in 802.11k RCPI : IW_QUAL_RCPI | |
224 | + * | |
225 | + * V21 to V22 | |
226 | + * ---------- | |
227 | + * - Prevent leaking of kernel space in stream on 64 bits. | |
228 | + */ | |
229 | + | |
230 | +/**************************** CONSTANTS ****************************/ | |
231 | + | |
232 | +/* -------------------------- IOCTL LIST -------------------------- */ | |
233 | + | |
234 | +/* Wireless Identification */ | |
235 | +#define SIOCSIWCOMMIT 0x8B00 /* Commit pending changes to driver */ | |
236 | +#define SIOCGIWNAME 0x8B01 /* get name == wireless protocol */ | |
237 | +/* SIOCGIWNAME is used to verify the presence of Wireless Extensions. | |
238 | + * Common values : "IEEE 802.11-DS", "IEEE 802.11-FH", "IEEE 802.11b"... | |
239 | + * Don't put the name of your driver there, it's useless. */ | |
240 | + | |
241 | +/* Basic operations */ | |
242 | +#define SIOCSIWNWID 0x8B02 /* set network id (pre-802.11) */ | |
243 | +#define SIOCGIWNWID 0x8B03 /* get network id (the cell) */ | |
244 | +#define SIOCSIWFREQ 0x8B04 /* set channel/frequency (Hz) */ | |
245 | +#define SIOCGIWFREQ 0x8B05 /* get channel/frequency (Hz) */ | |
246 | +#define SIOCSIWMODE 0x8B06 /* set operation mode */ | |
247 | +#define SIOCGIWMODE 0x8B07 /* get operation mode */ | |
248 | +#define SIOCSIWSENS 0x8B08 /* set sensitivity (dBm) */ | |
249 | +#define SIOCGIWSENS 0x8B09 /* get sensitivity (dBm) */ | |
250 | + | |
251 | +/* Informative stuff */ | |
252 | +#define SIOCSIWRANGE 0x8B0A /* Unused */ | |
253 | +#define SIOCGIWRANGE 0x8B0B /* Get range of parameters */ | |
254 | +#define SIOCSIWPRIV 0x8B0C /* Unused */ | |
255 | +#define SIOCGIWPRIV 0x8B0D /* get private ioctl interface info */ | |
256 | +#define SIOCSIWSTATS 0x8B0E /* Unused */ | |
257 | +#define SIOCGIWSTATS 0x8B0F /* Get /proc/net/wireless stats */ | |
258 | +/* SIOCGIWSTATS is strictly used between user space and the kernel, and | |
259 | + * is never passed to the driver (i.e. the driver will never see it). */ | |
260 | + | |
261 | +/* Spy support (statistics per MAC address - used for Mobile IP support) */ | |
262 | +#define SIOCSIWSPY 0x8B10 /* set spy addresses */ | |
263 | +#define SIOCGIWSPY 0x8B11 /* get spy info (quality of link) */ | |
264 | +#define SIOCSIWTHRSPY 0x8B12 /* set spy threshold (spy event) */ | |
265 | +#define SIOCGIWTHRSPY 0x8B13 /* get spy threshold */ | |
266 | + | |
267 | +/* Access Point manipulation */ | |
268 | +#define SIOCSIWAP 0x8B14 /* set access point MAC addresses */ | |
269 | +#define SIOCGIWAP 0x8B15 /* get access point MAC addresses */ | |
270 | +#define SIOCGIWAPLIST 0x8B17 /* Deprecated in favor of scanning */ | |
271 | +#define SIOCSIWSCAN 0x8B18 /* trigger scanning (list cells) */ | |
272 | +#define SIOCGIWSCAN 0x8B19 /* get scanning results */ | |
273 | + | |
274 | +/* 802.11 specific support */ | |
275 | +#define SIOCSIWESSID 0x8B1A /* set ESSID (network name) */ | |
276 | +#define SIOCGIWESSID 0x8B1B /* get ESSID */ | |
277 | +#define SIOCSIWNICKN 0x8B1C /* set node name/nickname */ | |
278 | +#define SIOCGIWNICKN 0x8B1D /* get node name/nickname */ | |
279 | +/* As the ESSID and NICKN are strings up to 32 bytes long, it doesn't fit | |
280 | + * within the 'iwreq' structure, so we need to use the 'data' member to | |
281 | + * point to a string in user space, like it is done for RANGE... */ | |
282 | + | |
283 | +/* Other parameters useful in 802.11 and some other devices */ | |
284 | +#define SIOCSIWRATE 0x8B20 /* set default bit rate (bps) */ | |
285 | +#define SIOCGIWRATE 0x8B21 /* get default bit rate (bps) */ | |
286 | +#define SIOCSIWRTS 0x8B22 /* set RTS/CTS threshold (bytes) */ | |
287 | +#define SIOCGIWRTS 0x8B23 /* get RTS/CTS threshold (bytes) */ | |
288 | +#define SIOCSIWFRAG 0x8B24 /* set fragmentation thr (bytes) */ | |
289 | +#define SIOCGIWFRAG 0x8B25 /* get fragmentation thr (bytes) */ | |
290 | +#define SIOCSIWTXPOW 0x8B26 /* set transmit power (dBm) */ | |
291 | +#define SIOCGIWTXPOW 0x8B27 /* get transmit power (dBm) */ | |
292 | +#define SIOCSIWRETRY 0x8B28 /* set retry limits and lifetime */ | |
293 | +#define SIOCGIWRETRY 0x8B29 /* get retry limits and lifetime */ | |
294 | + | |
295 | +/* Encoding stuff (scrambling, hardware security, WEP...) */ | |
296 | +#define SIOCSIWENCODE 0x8B2A /* set encoding token & mode */ | |
297 | +#define SIOCGIWENCODE 0x8B2B /* get encoding token & mode */ | |
298 | +/* Power saving stuff (power management, unicast and multicast) */ | |
299 | +#define SIOCSIWPOWER 0x8B2C /* set Power Management settings */ | |
300 | +#define SIOCGIWPOWER 0x8B2D /* get Power Management settings */ | |
301 | +/* Modulation bitmask */ | |
302 | +#define SIOCSIWMODUL 0x8B2E /* set Modulations settings */ | |
303 | +#define SIOCGIWMODUL 0x8B2F /* get Modulations settings */ | |
304 | + | |
305 | +/* WPA : Generic IEEE 802.11 informatiom element (e.g., for WPA/RSN/WMM). | |
306 | + * This ioctl uses struct iw_point and data buffer that includes IE id and len | |
307 | + * fields. More than one IE may be included in the request. Setting the generic | |
308 | + * IE to empty buffer (len=0) removes the generic IE from the driver. Drivers | |
309 | + * are allowed to generate their own WPA/RSN IEs, but in these cases, drivers | |
310 | + * are required to report the used IE as a wireless event, e.g., when | |
311 | + * associating with an AP. */ | |
312 | +#define SIOCSIWGENIE 0x8B30 /* set generic IE */ | |
313 | +#define SIOCGIWGENIE 0x8B31 /* get generic IE */ | |
314 | + | |
315 | +/* WPA : IEEE 802.11 MLME requests */ | |
316 | +#define SIOCSIWMLME 0x8B16 /* request MLME operation; uses | |
317 | + * struct iw_mlme */ | |
318 | +/* WPA : Authentication mode parameters */ | |
319 | +#define SIOCSIWAUTH 0x8B32 /* set authentication mode params */ | |
320 | +#define SIOCGIWAUTH 0x8B33 /* get authentication mode params */ | |
321 | + | |
322 | +/* WPA : Extended version of encoding configuration */ | |
323 | +#define SIOCSIWENCODEEXT 0x8B34 /* set encoding token & mode */ | |
324 | +#define SIOCGIWENCODEEXT 0x8B35 /* get encoding token & mode */ | |
325 | + | |
326 | +/* WPA2 : PMKSA cache management */ | |
327 | +#define SIOCSIWPMKSA 0x8B36 /* PMKSA cache operation */ | |
328 | + | |
329 | +/* -------------------- DEV PRIVATE IOCTL LIST -------------------- */ | |
330 | + | |
331 | +/* These 32 ioctl are wireless device private, for 16 commands. | |
332 | + * Each driver is free to use them for whatever purpose it chooses, | |
333 | + * however the driver *must* export the description of those ioctls | |
334 | + * with SIOCGIWPRIV and *must* use arguments as defined below. | |
335 | + * If you don't follow those rules, DaveM is going to hate you (reason : | |
336 | + * it make mixed 32/64bit operation impossible). | |
337 | + */ | |
338 | +#define SIOCIWFIRSTPRIV 0x8BE0 | |
339 | +#define SIOCIWLASTPRIV 0x8BFF | |
340 | +/* Previously, we were using SIOCDEVPRIVATE, but we now have our | |
341 | + * separate range because of collisions with other tools such as | |
342 | + * 'mii-tool'. | |
343 | + * We now have 32 commands, so a bit more space ;-). | |
344 | + * Also, all 'even' commands are only usable by root and don't return the | |
345 | + * content of ifr/iwr to user (but you are not obliged to use the set/get | |
346 | + * convention, just use every other two command). More details in iwpriv.c. | |
347 | + * And I repeat : you are not forced to use them with iwpriv, but you | |
348 | + * must be compliant with it. | |
349 | + */ | |
350 | + | |
351 | +/* ------------------------- IOCTL STUFF ------------------------- */ | |
352 | + | |
353 | +/* The first and the last (range) */ | |
354 | +#define SIOCIWFIRST 0x8B00 | |
355 | +#define SIOCIWLAST SIOCIWLASTPRIV /* 0x8BFF */ | |
356 | +#define IW_IOCTL_IDX(cmd) ((cmd) - SIOCIWFIRST) | |
357 | + | |
358 | +/* Odd : get (world access), even : set (root access) */ | |
359 | +#define IW_IS_SET(cmd) (!((cmd) & 0x1)) | |
360 | +#define IW_IS_GET(cmd) ((cmd) & 0x1) | |
361 | + | |
362 | +/* ----------------------- WIRELESS EVENTS ----------------------- */ | |
363 | +/* Those are *NOT* ioctls, do not issue request on them !!! */ | |
364 | +/* Most events use the same identifier as ioctl requests */ | |
365 | + | |
366 | +#define IWEVTXDROP 0x8C00 /* Packet dropped to excessive retry */ | |
367 | +#define IWEVQUAL 0x8C01 /* Quality part of statistics (scan) */ | |
368 | +#define IWEVCUSTOM 0x8C02 /* Driver specific ascii string */ | |
369 | +#define IWEVREGISTERED 0x8C03 /* Discovered a new node (AP mode) */ | |
370 | +#define IWEVEXPIRED 0x8C04 /* Expired a node (AP mode) */ | |
371 | +#define IWEVGENIE 0x8C05 /* Generic IE (WPA, RSN, WMM, ..) | |
372 | + * (scan results); This includes id and | |
373 | + * length fields. One IWEVGENIE may | |
374 | + * contain more than one IE. Scan | |
375 | + * results may contain one or more | |
376 | + * IWEVGENIE events. */ | |
377 | +#define IWEVMICHAELMICFAILURE 0x8C06 /* Michael MIC failure | |
378 | + * (struct iw_michaelmicfailure) | |
379 | + */ | |
380 | +#define IWEVASSOCREQIE 0x8C07 /* IEs used in (Re)Association Request. | |
381 | + * The data includes id and length | |
382 | + * fields and may contain more than one | |
383 | + * IE. This event is required in | |
384 | + * Managed mode if the driver | |
385 | + * generates its own WPA/RSN IE. This | |
386 | + * should be sent just before | |
387 | + * IWEVREGISTERED event for the | |
388 | + * association. */ | |
389 | +#define IWEVASSOCRESPIE 0x8C08 /* IEs used in (Re)Association | |
390 | + * Response. The data includes id and | |
391 | + * length fields and may contain more | |
392 | + * than one IE. This may be sent | |
393 | + * between IWEVASSOCREQIE and | |
394 | + * IWEVREGISTERED events for the | |
395 | + * association. */ | |
396 | +#define IWEVPMKIDCAND 0x8C09 /* PMKID candidate for RSN | |
397 | + * pre-authentication | |
398 | + * (struct iw_pmkid_cand) */ | |
399 | + | |
400 | +#define IWEVFIRST 0x8C00 | |
401 | +#define IW_EVENT_IDX(cmd) ((cmd) - IWEVFIRST) | |
402 | + | |
403 | +/* ------------------------- PRIVATE INFO ------------------------- */ | |
404 | +/* | |
405 | + * The following is used with SIOCGIWPRIV. It allow a driver to define | |
406 | + * the interface (name, type of data) for its private ioctl. | |
407 | + * Privates ioctl are SIOCIWFIRSTPRIV -> SIOCIWLASTPRIV | |
408 | + */ | |
409 | + | |
410 | +#define IW_PRIV_TYPE_MASK 0x7000 /* Type of arguments */ | |
411 | +#define IW_PRIV_TYPE_NONE 0x0000 | |
412 | +#define IW_PRIV_TYPE_BYTE 0x1000 /* Char as number */ | |
413 | +#define IW_PRIV_TYPE_CHAR 0x2000 /* Char as character */ | |
414 | +#define IW_PRIV_TYPE_INT 0x4000 /* 32 bits int */ | |
415 | +#define IW_PRIV_TYPE_FLOAT 0x5000 /* struct iw_freq */ | |
416 | +#define IW_PRIV_TYPE_ADDR 0x6000 /* struct sockaddr */ | |
417 | + | |
418 | +#define IW_PRIV_SIZE_FIXED 0x0800 /* Variable or fixed number of args */ | |
419 | + | |
420 | +#define IW_PRIV_SIZE_MASK 0x07FF /* Max number of those args */ | |
421 | + | |
422 | +/* | |
423 | + * Note : if the number of args is fixed and the size < 16 octets, | |
424 | + * instead of passing a pointer we will put args in the iwreq struct... | |
425 | + */ | |
426 | + | |
427 | +/* ----------------------- OTHER CONSTANTS ----------------------- */ | |
428 | + | |
429 | +/* Maximum frequencies in the range struct */ | |
430 | +#define IW_MAX_FREQUENCIES 32 | |
431 | +/* Note : if you have something like 80 frequencies, | |
432 | + * don't increase this constant and don't fill the frequency list. | |
433 | + * The user will be able to set by channel anyway... */ | |
434 | + | |
435 | +/* Maximum bit rates in the range struct */ | |
436 | +#define IW_MAX_BITRATES 32 | |
437 | + | |
438 | +/* Maximum tx powers in the range struct */ | |
439 | +#define IW_MAX_TXPOWER 8 | |
440 | +/* Note : if you more than 8 TXPowers, just set the max and min or | |
441 | + * a few of them in the struct iw_range. */ | |
442 | + | |
443 | +/* Maximum of address that you may set with SPY */ | |
444 | +#define IW_MAX_SPY 8 | |
445 | + | |
446 | +/* Maximum of address that you may get in the | |
447 | + list of access points in range */ | |
448 | +#define IW_MAX_AP 64 | |
449 | + | |
450 | +/* Maximum size of the ESSID and NICKN strings */ | |
451 | +#define IW_ESSID_MAX_SIZE 32 | |
452 | + | |
453 | +/* Modes of operation */ | |
454 | +#define IW_MODE_AUTO 0 /* Let the driver decides */ | |
455 | +#define IW_MODE_ADHOC 1 /* Single cell network */ | |
456 | +#define IW_MODE_INFRA 2 /* Multi cell network, roaming, ... */ | |
457 | +#define IW_MODE_MASTER 3 /* Synchronisation master or Access Point */ | |
458 | +#define IW_MODE_REPEAT 4 /* Wireless Repeater (forwarder) */ | |
459 | +#define IW_MODE_SECOND 5 /* Secondary master/repeater (backup) */ | |
460 | +#define IW_MODE_MONITOR 6 /* Passive monitor (listen only) */ | |
461 | + | |
462 | +/* Statistics flags (bitmask in updated) */ | |
463 | +#define IW_QUAL_QUAL_UPDATED 0x01 /* Value was updated since last read */ | |
464 | +#define IW_QUAL_LEVEL_UPDATED 0x02 | |
465 | +#define IW_QUAL_NOISE_UPDATED 0x04 | |
466 | +#define IW_QUAL_ALL_UPDATED 0x07 | |
467 | +#define IW_QUAL_DBM 0x08 /* Level + Noise are dBm */ | |
468 | +#define IW_QUAL_QUAL_INVALID 0x10 /* Driver doesn't provide value */ | |
469 | +#define IW_QUAL_LEVEL_INVALID 0x20 | |
470 | +#define IW_QUAL_NOISE_INVALID 0x40 | |
471 | +#define IW_QUAL_RCPI 0x80 /* Level + Noise are 802.11k RCPI */ | |
472 | +#define IW_QUAL_ALL_INVALID 0x70 | |
473 | + | |
474 | +/* Frequency flags */ | |
475 | +#define IW_FREQ_AUTO 0x00 /* Let the driver decides */ | |
476 | +#define IW_FREQ_FIXED 0x01 /* Force a specific value */ | |
477 | + | |
478 | +/* Maximum number of size of encoding token available | |
479 | + * they are listed in the range structure */ | |
480 | +#define IW_MAX_ENCODING_SIZES 8 | |
481 | + | |
482 | +/* Maximum size of the encoding token in bytes */ | |
483 | +#define IW_ENCODING_TOKEN_MAX 64 /* 512 bits (for now) */ | |
484 | + | |
485 | +/* Flags for encoding (along with the token) */ | |
486 | +#define IW_ENCODE_INDEX 0x00FF /* Token index (if needed) */ | |
487 | +#define IW_ENCODE_FLAGS 0xFF00 /* Flags defined below */ | |
488 | +#define IW_ENCODE_MODE 0xF000 /* Modes defined below */ | |
489 | +#define IW_ENCODE_DISABLED 0x8000 /* Encoding disabled */ | |
490 | +#define IW_ENCODE_ENABLED 0x0000 /* Encoding enabled */ | |
491 | +#define IW_ENCODE_RESTRICTED 0x4000 /* Refuse non-encoded packets */ | |
492 | +#define IW_ENCODE_OPEN 0x2000 /* Accept non-encoded packets */ | |
493 | +#define IW_ENCODE_NOKEY 0x0800 /* Key is write only, so not present */ | |
494 | +#define IW_ENCODE_TEMP 0x0400 /* Temporary key */ | |
495 | + | |
496 | +/* Power management flags available (along with the value, if any) */ | |
497 | +#define IW_POWER_ON 0x0000 /* No details... */ | |
498 | +#define IW_POWER_TYPE 0xF000 /* Type of parameter */ | |
499 | +#define IW_POWER_PERIOD 0x1000 /* Value is a period/duration of */ | |
500 | +#define IW_POWER_TIMEOUT 0x2000 /* Value is a timeout (to go asleep) */ | |
501 | +#define IW_POWER_SAVING 0x4000 /* Value is relative (how aggressive)*/ | |
502 | +#define IW_POWER_MODE 0x0F00 /* Power Management mode */ | |
503 | +#define IW_POWER_UNICAST_R 0x0100 /* Receive only unicast messages */ | |
504 | +#define IW_POWER_MULTICAST_R 0x0200 /* Receive only multicast messages */ | |
505 | +#define IW_POWER_ALL_R 0x0300 /* Receive all messages though PM */ | |
506 | +#define IW_POWER_FORCE_S 0x0400 /* Force PM procedure for sending unicast */ | |
507 | +#define IW_POWER_REPEATER 0x0800 /* Repeat broadcast messages in PM period */ | |
508 | +#define IW_POWER_MODIFIER 0x000F /* Modify a parameter */ | |
509 | +#define IW_POWER_MIN 0x0001 /* Value is a minimum */ | |
510 | +#define IW_POWER_MAX 0x0002 /* Value is a maximum */ | |
511 | +#define IW_POWER_RELATIVE 0x0004 /* Value is not in seconds/ms/us */ | |
512 | + | |
513 | +/* Transmit Power flags available */ | |
514 | +#define IW_TXPOW_TYPE 0x00FF /* Type of value */ | |
515 | +#define IW_TXPOW_DBM 0x0000 /* Value is in dBm */ | |
516 | +#define IW_TXPOW_MWATT 0x0001 /* Value is in mW */ | |
517 | +#define IW_TXPOW_RELATIVE 0x0002 /* Value is in arbitrary units */ | |
518 | +#define IW_TXPOW_RANGE 0x1000 /* Range of value between min/max */ | |
519 | + | |
520 | +/* Retry limits and lifetime flags available */ | |
521 | +#define IW_RETRY_ON 0x0000 /* No details... */ | |
522 | +#define IW_RETRY_TYPE 0xF000 /* Type of parameter */ | |
523 | +#define IW_RETRY_LIMIT 0x1000 /* Maximum number of retries*/ | |
524 | +#define IW_RETRY_LIFETIME 0x2000 /* Maximum duration of retries in us */ | |
525 | +#define IW_RETRY_MODIFIER 0x00FF /* Modify a parameter */ | |
526 | +#define IW_RETRY_MIN 0x0001 /* Value is a minimum */ | |
527 | +#define IW_RETRY_MAX 0x0002 /* Value is a maximum */ | |
528 | +#define IW_RETRY_RELATIVE 0x0004 /* Value is not in seconds/ms/us */ | |
529 | +#define IW_RETRY_SHORT 0x0010 /* Value is for short packets */ | |
530 | +#define IW_RETRY_LONG 0x0020 /* Value is for long packets */ | |
531 | + | |
532 | +/* Scanning request flags */ | |
533 | +#define IW_SCAN_DEFAULT 0x0000 /* Default scan of the driver */ | |
534 | +#define IW_SCAN_ALL_ESSID 0x0001 /* Scan all ESSIDs */ | |
535 | +#define IW_SCAN_THIS_ESSID 0x0002 /* Scan only this ESSID */ | |
536 | +#define IW_SCAN_ALL_FREQ 0x0004 /* Scan all Frequencies */ | |
537 | +#define IW_SCAN_THIS_FREQ 0x0008 /* Scan only this Frequency */ | |
538 | +#define IW_SCAN_ALL_MODE 0x0010 /* Scan all Modes */ | |
539 | +#define IW_SCAN_THIS_MODE 0x0020 /* Scan only this Mode */ | |
540 | +#define IW_SCAN_ALL_RATE 0x0040 /* Scan all Bit-Rates */ | |
541 | +#define IW_SCAN_THIS_RATE 0x0080 /* Scan only this Bit-Rate */ | |
542 | +/* struct iw_scan_req scan_type */ | |
543 | +#define IW_SCAN_TYPE_ACTIVE 0 | |
544 | +#define IW_SCAN_TYPE_PASSIVE 1 | |
545 | +/* Maximum size of returned data */ | |
546 | +#define IW_SCAN_MAX_DATA 4096 /* In bytes */ | |
547 | + | |
548 | +/* Max number of char in custom event - use multiple of them if needed */ | |
549 | +#define IW_CUSTOM_MAX 256 /* In bytes */ | |
550 | + | |
551 | +/* Generic information element */ | |
552 | +#define IW_GENERIC_IE_MAX 1024 | |
553 | + | |
554 | +/* MLME requests (SIOCSIWMLME / struct iw_mlme) */ | |
555 | +#define IW_MLME_DEAUTH 0 | |
556 | +#define IW_MLME_DISASSOC 1 | |
557 | +#define IW_MLME_AUTH 2 | |
558 | +#define IW_MLME_ASSOC 3 | |
559 | + | |
560 | +/* SIOCSIWAUTH/SIOCGIWAUTH struct iw_param flags */ | |
561 | +#define IW_AUTH_INDEX 0x0FFF | |
562 | +#define IW_AUTH_FLAGS 0xF000 | |
563 | +/* SIOCSIWAUTH/SIOCGIWAUTH parameters (0 .. 4095) | |
564 | + * (IW_AUTH_INDEX mask in struct iw_param flags; this is the index of the | |
565 | + * parameter that is being set/get to; value will be read/written to | |
566 | + * struct iw_param value field) */ | |
567 | +#define IW_AUTH_WPA_VERSION 0 | |
568 | +#define IW_AUTH_CIPHER_PAIRWISE 1 | |
569 | +#define IW_AUTH_CIPHER_GROUP 2 | |
570 | +#define IW_AUTH_KEY_MGMT 3 | |
571 | +#define IW_AUTH_TKIP_COUNTERMEASURES 4 | |
572 | +#define IW_AUTH_DROP_UNENCRYPTED 5 | |
573 | +#define IW_AUTH_80211_AUTH_ALG 6 | |
574 | +#define IW_AUTH_WPA_ENABLED 7 | |
575 | +#define IW_AUTH_RX_UNENCRYPTED_EAPOL 8 | |
576 | +#define IW_AUTH_ROAMING_CONTROL 9 | |
577 | +#define IW_AUTH_PRIVACY_INVOKED 10 | |
578 | + | |
579 | +/* IW_AUTH_WPA_VERSION values (bit field) */ | |
580 | +#define IW_AUTH_WPA_VERSION_DISABLED 0x00000001 | |
581 | +#define IW_AUTH_WPA_VERSION_WPA 0x00000002 | |
582 | +#define IW_AUTH_WPA_VERSION_WPA2 0x00000004 | |
583 | + | |
584 | +/* IW_AUTH_PAIRWISE_CIPHER and IW_AUTH_GROUP_CIPHER values (bit field) */ | |
585 | +#define IW_AUTH_CIPHER_NONE 0x00000001 | |
586 | +#define IW_AUTH_CIPHER_WEP40 0x00000002 | |
587 | +#define IW_AUTH_CIPHER_TKIP 0x00000004 | |
588 | +#define IW_AUTH_CIPHER_CCMP 0x00000008 | |
589 | +#define IW_AUTH_CIPHER_WEP104 0x00000010 | |
590 | + | |
591 | +/* IW_AUTH_KEY_MGMT values (bit field) */ | |
592 | +#define IW_AUTH_KEY_MGMT_802_1X 1 | |
593 | +#define IW_AUTH_KEY_MGMT_PSK 2 | |
594 | + | |
595 | +/* IW_AUTH_80211_AUTH_ALG values (bit field) */ | |
596 | +#define IW_AUTH_ALG_OPEN_SYSTEM 0x00000001 | |
597 | +#define IW_AUTH_ALG_SHARED_KEY 0x00000002 | |
598 | +#define IW_AUTH_ALG_LEAP 0x00000004 | |
599 | + | |
600 | +/* IW_AUTH_ROAMING_CONTROL values */ | |
601 | +#define IW_AUTH_ROAMING_ENABLE 0 /* driver/firmware based roaming */ | |
602 | +#define IW_AUTH_ROAMING_DISABLE 1 /* user space program used for roaming | |
603 | + * control */ | |
604 | + | |
605 | +/* SIOCSIWENCODEEXT definitions */ | |
606 | +#define IW_ENCODE_SEQ_MAX_SIZE 8 | |
607 | +/* struct iw_encode_ext ->alg */ | |
608 | +#define IW_ENCODE_ALG_NONE 0 | |
609 | +#define IW_ENCODE_ALG_WEP 1 | |
610 | +#define IW_ENCODE_ALG_TKIP 2 | |
611 | +#define IW_ENCODE_ALG_CCMP 3 | |
612 | +/* struct iw_encode_ext ->ext_flags */ | |
613 | +#define IW_ENCODE_EXT_TX_SEQ_VALID 0x00000001 | |
614 | +#define IW_ENCODE_EXT_RX_SEQ_VALID 0x00000002 | |
615 | +#define IW_ENCODE_EXT_GROUP_KEY 0x00000004 | |
616 | +#define IW_ENCODE_EXT_SET_TX_KEY 0x00000008 | |
617 | + | |
618 | +/* IWEVMICHAELMICFAILURE : struct iw_michaelmicfailure ->flags */ | |
619 | +#define IW_MICFAILURE_KEY_ID 0x00000003 /* Key ID 0..3 */ | |
620 | +#define IW_MICFAILURE_GROUP 0x00000004 | |
621 | +#define IW_MICFAILURE_PAIRWISE 0x00000008 | |
622 | +#define IW_MICFAILURE_STAKEY 0x00000010 | |
623 | +#define IW_MICFAILURE_COUNT 0x00000060 /* 1 or 2 (0 = count not supported) | |
624 | + */ | |
625 | + | |
626 | +/* Bit field values for enc_capa in struct iw_range */ | |
627 | +#define IW_ENC_CAPA_WPA 0x00000001 | |
628 | +#define IW_ENC_CAPA_WPA2 0x00000002 | |
629 | +#define IW_ENC_CAPA_CIPHER_TKIP 0x00000004 | |
630 | +#define IW_ENC_CAPA_CIPHER_CCMP 0x00000008 | |
631 | + | |
632 | +/* Event capability macros - in (struct iw_range *)->event_capa | |
633 | + * Because we have more than 32 possible events, we use an array of | |
634 | + * 32 bit bitmasks. Note : 32 bits = 0x20 = 2^5. */ | |
635 | +#define IW_EVENT_CAPA_BASE(cmd) ((cmd >= SIOCIWFIRSTPRIV) ? \ | |
636 | + (cmd - SIOCIWFIRSTPRIV + 0x60) : \ | |
637 | + (cmd - SIOCSIWCOMMIT)) | |
638 | +#define IW_EVENT_CAPA_INDEX(cmd) (IW_EVENT_CAPA_BASE(cmd) >> 5) | |
639 | +#define IW_EVENT_CAPA_MASK(cmd) (1 << (IW_EVENT_CAPA_BASE(cmd) & 0x1F)) | |
640 | +/* Event capability constants - event autogenerated by the kernel | |
641 | + * This list is valid for most 802.11 devices, customise as needed... */ | |
642 | +#define IW_EVENT_CAPA_K_0 (IW_EVENT_CAPA_MASK(0x8B04) | \ | |
643 | + IW_EVENT_CAPA_MASK(0x8B06) | \ | |
644 | + IW_EVENT_CAPA_MASK(0x8B1A)) | |
645 | +#define IW_EVENT_CAPA_K_1 (IW_EVENT_CAPA_MASK(0x8B2A)) | |
646 | +/* "Easy" macro to set events in iw_range (less efficient) */ | |
647 | +#define IW_EVENT_CAPA_SET(event_capa, cmd) (event_capa[IW_EVENT_CAPA_INDEX(cmd)] |= IW_EVENT_CAPA_MASK(cmd)) | |
648 | +#define IW_EVENT_CAPA_SET_KERNEL(event_capa) {event_capa[0] |= IW_EVENT_CAPA_K_0; event_capa[1] |= IW_EVENT_CAPA_K_1; } | |
649 | + | |
650 | +/* Modulations bitmasks */ | |
651 | +#define IW_MODUL_ALL 0x00000000 /* Everything supported */ | |
652 | +#define IW_MODUL_FH 0x00000001 /* Frequency Hopping */ | |
653 | +#define IW_MODUL_DS 0x00000002 /* Original Direct Sequence */ | |
654 | +#define IW_MODUL_CCK 0x00000004 /* 802.11b : 5.5 + 11 Mb/s */ | |
655 | +#define IW_MODUL_11B (IW_MODUL_DS | IW_MODUL_CCK) | |
656 | +#define IW_MODUL_PBCC 0x00000008 /* TI : 5.5 + 11 + 22 Mb/s */ | |
657 | +#define IW_MODUL_OFDM_A 0x00000010 /* 802.11a : 54 Mb/s */ | |
658 | +#define IW_MODUL_11A (IW_MODUL_OFDM_A) | |
659 | +#define IW_MODUL_11AB (IW_MODUL_11B | IW_MODUL_11A) | |
660 | +#define IW_MODUL_OFDM_G 0x00000020 /* 802.11g : 54 Mb/s */ | |
661 | +#define IW_MODUL_11G (IW_MODUL_11B | IW_MODUL_OFDM_G) | |
662 | +#define IW_MODUL_11AG (IW_MODUL_11G | IW_MODUL_11A) | |
663 | +#define IW_MODUL_TURBO 0x00000040 /* ATH : bonding, 108 Mb/s */ | |
664 | +/* In here we should define MIMO stuff. Later... */ | |
665 | +#define IW_MODUL_CUSTOM 0x40000000 /* Driver specific */ | |
666 | + | |
667 | +/* Bitrate flags available */ | |
668 | +#define IW_BITRATE_TYPE 0x00FF /* Type of value */ | |
669 | +#define IW_BITRATE_UNICAST 0x0001 /* Maximum/Fixed unicast bitrate */ | |
670 | +#define IW_BITRATE_BROADCAST 0x0002 /* Fixed broadcast bitrate */ | |
671 | + | |
672 | +/****************************** TYPES ******************************/ | |
673 | + | |
674 | +/* --------------------------- SUBTYPES --------------------------- */ | |
675 | +/* | |
676 | + * Generic format for most parameters that fit in an int | |
677 | + */ | |
678 | +struct iw_param | |
679 | +{ | |
680 | + __s32 value; /* The value of the parameter itself */ | |
681 | + __u8 fixed; /* Hardware should not use auto select */ | |
682 | + __u8 disabled; /* Disable the feature */ | |
683 | + __u16 flags; /* Various specifc flags (if any) */ | |
684 | +}; | |
685 | + | |
686 | +/* | |
687 | + * For all data larger than 16 octets, we need to use a | |
688 | + * pointer to memory allocated in user space. | |
689 | + */ | |
690 | +struct iw_point | |
691 | +{ | |
692 | + void __user *pointer; /* Pointer to the data (in user space) */ | |
693 | + __u16 length; /* number of fields or size in bytes */ | |
694 | + __u16 flags; /* Optional params */ | |
695 | +}; | |
696 | + | |
697 | +/* | |
698 | + * A frequency | |
699 | + * For numbers lower than 10^9, we encode the number in 'm' and | |
700 | + * set 'e' to 0 | |
701 | + * For number greater than 10^9, we divide it by the lowest power | |
702 | + * of 10 to get 'm' lower than 10^9, with 'm'= f / (10^'e')... | |
703 | + * The power of 10 is in 'e', the result of the division is in 'm'. | |
704 | + */ | |
705 | +struct iw_freq | |
706 | +{ | |
707 | + __s32 m; /* Mantissa */ | |
708 | + __s16 e; /* Exponent */ | |
709 | + __u8 i; /* List index (when in range struct) */ | |
710 | + __u8 flags; /* Flags (fixed/auto) */ | |
711 | +}; | |
712 | + | |
713 | +/* | |
714 | + * Quality of the link | |
715 | + */ | |
716 | +struct iw_quality | |
717 | +{ | |
718 | + __u8 qual; /* link quality (%retries, SNR, | |
719 | + %missed beacons or better...) */ | |
720 | + __u8 level; /* signal level (dBm) */ | |
721 | + __u8 noise; /* noise level (dBm) */ | |
722 | + __u8 updated; /* Flags to know if updated */ | |
723 | +}; | |
724 | + | |
725 | +/* | |
726 | + * Packet discarded in the wireless adapter due to | |
727 | + * "wireless" specific problems... | |
728 | + * Note : the list of counter and statistics in net_device_stats | |
729 | + * is already pretty exhaustive, and you should use that first. | |
730 | + * This is only additional stats... | |
731 | + */ | |
732 | +struct iw_discarded | |
733 | +{ | |
734 | + __u32 nwid; /* Rx : Wrong nwid/essid */ | |
735 | + __u32 code; /* Rx : Unable to code/decode (WEP) */ | |
736 | + __u32 fragment; /* Rx : Can't perform MAC reassembly */ | |
737 | + __u32 retries; /* Tx : Max MAC retries num reached */ | |
738 | + __u32 misc; /* Others cases */ | |
739 | +}; | |
740 | + | |
741 | +/* | |
742 | + * Packet/Time period missed in the wireless adapter due to | |
743 | + * "wireless" specific problems... | |
744 | + */ | |
745 | +struct iw_missed | |
746 | +{ | |
747 | + __u32 beacon; /* Missed beacons/superframe */ | |
748 | +}; | |
749 | + | |
750 | +/* | |
751 | + * Quality range (for spy threshold) | |
752 | + */ | |
753 | +struct iw_thrspy | |
754 | +{ | |
755 | + struct sockaddr addr; /* Source address (hw/mac) */ | |
756 | + struct iw_quality qual; /* Quality of the link */ | |
757 | + struct iw_quality low; /* Low threshold */ | |
758 | + struct iw_quality high; /* High threshold */ | |
759 | +}; | |
760 | + | |
761 | +/* | |
762 | + * Optional data for scan request | |
763 | + * | |
764 | + * Note: these optional parameters are controlling parameters for the | |
765 | + * scanning behavior, these do not apply to getting scan results | |
766 | + * (SIOCGIWSCAN). Drivers are expected to keep a local BSS table and | |
767 | + * provide a merged results with all BSSes even if the previous scan | |
768 | + * request limited scanning to a subset, e.g., by specifying an SSID. | |
769 | + * Especially, scan results are required to include an entry for the | |
770 | + * current BSS if the driver is in Managed mode and associated with an AP. | |
771 | + */ | |
772 | +struct iw_scan_req | |
773 | +{ | |
774 | + __u8 scan_type; /* IW_SCAN_TYPE_{ACTIVE,PASSIVE} */ | |
775 | + __u8 essid_len; | |
776 | + __u8 num_channels; /* num entries in channel_list; | |
777 | + * 0 = scan all allowed channels */ | |
778 | + __u8 flags; /* reserved as padding; use zero, this may | |
779 | + * be used in the future for adding flags | |
780 | + * to request different scan behavior */ | |
781 | + struct sockaddr bssid; /* ff:ff:ff:ff:ff:ff for broadcast BSSID or | |
782 | + * individual address of a specific BSS */ | |
783 | + | |
784 | + /* | |
785 | + * Use this ESSID if IW_SCAN_THIS_ESSID flag is used instead of using | |
786 | + * the current ESSID. This allows scan requests for specific ESSID | |
787 | + * without having to change the current ESSID and potentially breaking | |
788 | + * the current association. | |
789 | + */ | |
790 | + __u8 essid[IW_ESSID_MAX_SIZE]; | |
791 | + | |
792 | + /* | |
793 | + * Optional parameters for changing the default scanning behavior. | |
794 | + * These are based on the MLME-SCAN.request from IEEE Std 802.11. | |
795 | + * TU is 1.024 ms. If these are set to 0, driver is expected to use | |
796 | + * reasonable default values. min_channel_time defines the time that | |
797 | + * will be used to wait for the first reply on each channel. If no | |
798 | + * replies are received, next channel will be scanned after this. If | |
799 | + * replies are received, total time waited on the channel is defined by | |
800 | + * max_channel_time. | |
801 | + */ | |
802 | + __u32 min_channel_time; /* in TU */ | |
803 | + __u32 max_channel_time; /* in TU */ | |
804 | + | |
805 | + struct iw_freq channel_list[IW_MAX_FREQUENCIES]; | |
806 | +}; | |
807 | + | |
808 | +/* ------------------------- WPA SUPPORT ------------------------- */ | |
809 | + | |
810 | +/* | |
811 | + * Extended data structure for get/set encoding (this is used with | |
812 | + * SIOCSIWENCODEEXT/SIOCGIWENCODEEXT. struct iw_point and IW_ENCODE_* | |
813 | + * flags are used in the same way as with SIOCSIWENCODE/SIOCGIWENCODE and | |
814 | + * only the data contents changes (key data -> this structure, including | |
815 | + * key data). | |
816 | + * | |
817 | + * If the new key is the first group key, it will be set as the default | |
818 | + * TX key. Otherwise, default TX key index is only changed if | |
819 | + * IW_ENCODE_EXT_SET_TX_KEY flag is set. | |
820 | + * | |
821 | + * Key will be changed with SIOCSIWENCODEEXT in all cases except for | |
822 | + * special "change TX key index" operation which is indicated by setting | |
823 | + * key_len = 0 and ext_flags |= IW_ENCODE_EXT_SET_TX_KEY. | |
824 | + * | |
825 | + * tx_seq/rx_seq are only used when respective | |
826 | + * IW_ENCODE_EXT_{TX,RX}_SEQ_VALID flag is set in ext_flags. Normal | |
827 | + * TKIP/CCMP operation is to set RX seq with SIOCSIWENCODEEXT and start | |
828 | + * TX seq from zero whenever key is changed. SIOCGIWENCODEEXT is normally | |
829 | + * used only by an Authenticator (AP or an IBSS station) to get the | |
830 | + * current TX sequence number. Using TX_SEQ_VALID for SIOCSIWENCODEEXT and | |
831 | + * RX_SEQ_VALID for SIOCGIWENCODEEXT are optional, but can be useful for | |
832 | + * debugging/testing. | |
833 | + */ | |
834 | +struct iw_encode_ext | |
835 | +{ | |
836 | + __u32 ext_flags; /* IW_ENCODE_EXT_* */ | |
837 | + __u8 tx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */ | |
838 | + __u8 rx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */ | |
839 | + struct sockaddr addr; /* ff:ff:ff:ff:ff:ff for broadcast/multicast | |
840 | + * (group) keys or unicast address for | |
841 | + * individual keys */ | |
842 | + __u16 alg; /* IW_ENCODE_ALG_* */ | |
843 | + __u16 key_len; | |
844 | + __u8 key[0]; | |
845 | +}; | |
846 | + | |
847 | +/* SIOCSIWMLME data */ | |
848 | +struct iw_mlme | |
849 | +{ | |
850 | + __u16 cmd; /* IW_MLME_* */ | |
851 | + __u16 reason_code; | |
852 | + struct sockaddr addr; | |
853 | +}; | |
854 | + | |
855 | +/* SIOCSIWPMKSA data */ | |
856 | +#define IW_PMKSA_ADD 1 | |
857 | +#define IW_PMKSA_REMOVE 2 | |
858 | +#define IW_PMKSA_FLUSH 3 | |
859 | + | |
860 | +#define IW_PMKID_LEN 16 | |
861 | + | |
862 | +struct iw_pmksa | |
863 | +{ | |
864 | + __u32 cmd; /* IW_PMKSA_* */ | |
865 | + struct sockaddr bssid; | |
866 | + __u8 pmkid[IW_PMKID_LEN]; | |
867 | +}; | |
868 | + | |
869 | +/* IWEVMICHAELMICFAILURE data */ | |
870 | +struct iw_michaelmicfailure | |
871 | +{ | |
872 | + __u32 flags; | |
873 | + struct sockaddr src_addr; | |
874 | + __u8 tsc[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */ | |
875 | +}; | |
876 | + | |
877 | +/* IWEVPMKIDCAND data */ | |
878 | +#define IW_PMKID_CAND_PREAUTH 0x00000001 /* RNS pre-authentication enabled */ | |
879 | +struct iw_pmkid_cand | |
880 | +{ | |
881 | + __u32 flags; /* IW_PMKID_CAND_* */ | |
882 | + __u32 index; /* the smaller the index, the higher the | |
883 | + * priority */ | |
884 | + struct sockaddr bssid; | |
885 | +}; | |
886 | + | |
887 | +/* ------------------------ WIRELESS STATS ------------------------ */ | |
888 | +/* | |
889 | + * Wireless statistics (used for /proc/net/wireless) | |
890 | + */ | |
891 | +struct iw_statistics | |
892 | +{ | |
893 | + __u16 status; /* Status | |
894 | + * - device dependent for now */ | |
895 | + | |
896 | + struct iw_quality qual; /* Quality of the link | |
897 | + * (instant/mean/max) */ | |
898 | + struct iw_discarded discard; /* Packet discarded counts */ | |
899 | + struct iw_missed miss; /* Packet missed counts */ | |
900 | +}; | |
901 | + | |
902 | +/* ------------------------ IOCTL REQUEST ------------------------ */ | |
903 | +/* | |
904 | + * This structure defines the payload of an ioctl, and is used | |
905 | + * below. | |
906 | + * | |
907 | + * Note that this structure should fit on the memory footprint | |
908 | + * of iwreq (which is the same as ifreq), which mean a max size of | |
909 | + * 16 octets = 128 bits. Warning, pointers might be 64 bits wide... | |
910 | + * You should check this when increasing the structures defined | |
911 | + * above in this file... | |
912 | + */ | |
913 | +union iwreq_data | |
914 | +{ | |
915 | + /* Config - generic */ | |
916 | + char name[IFNAMSIZ]; | |
917 | + /* Name : used to verify the presence of wireless extensions. | |
918 | + * Name of the protocol/provider... */ | |
919 | + | |
920 | + struct iw_point essid; /* Extended network name */ | |
921 | + struct iw_param nwid; /* network id (or domain - the cell) */ | |
922 | + struct iw_freq freq; /* frequency or channel : | |
923 | + * 0-1000 = channel | |
924 | + * > 1000 = frequency in Hz */ | |
925 | + | |
926 | + struct iw_param sens; /* signal level threshold */ | |
927 | + struct iw_param bitrate; /* default bit rate */ | |
928 | + struct iw_param txpower; /* default transmit power */ | |
929 | + struct iw_param rts; /* RTS threshold threshold */ | |
930 | + struct iw_param frag; /* Fragmentation threshold */ | |
931 | + __u32 mode; /* Operation mode */ | |
932 | + struct iw_param retry; /* Retry limits & lifetime */ | |
933 | + | |
934 | + struct iw_point encoding; /* Encoding stuff : tokens */ | |
935 | + struct iw_param power; /* PM duration/timeout */ | |
936 | + struct iw_quality qual; /* Quality part of statistics */ | |
937 | + | |
938 | + struct sockaddr ap_addr; /* Access point address */ | |
939 | + struct sockaddr addr; /* Destination address (hw/mac) */ | |
940 | + | |
941 | + struct iw_param param; /* Other small parameters */ | |
942 | + struct iw_point data; /* Other large parameters */ | |
943 | +}; | |
944 | + | |
945 | +/* | |
946 | + * The structure to exchange data for ioctl. | |
947 | + * This structure is the same as 'struct ifreq', but (re)defined for | |
948 | + * convenience... | |
949 | + * Do I need to remind you about structure size (32 octets) ? | |
950 | + */ | |
951 | +struct iwreq | |
952 | +{ | |
953 | + union | |
954 | + { | |
955 | + char ifrn_name[IFNAMSIZ]; /* if name, e.g. "eth0" */ | |
956 | + } ifr_ifrn; | |
957 | + | |
958 | + /* Data part (defined just above) */ | |
959 | + union iwreq_data u; | |
960 | +}; | |
961 | + | |
962 | +/* -------------------------- IOCTL DATA -------------------------- */ | |
963 | +/* | |
964 | + * For those ioctl which want to exchange mode data that what could | |
965 | + * fit in the above structure... | |
966 | + */ | |
967 | + | |
968 | +/* | |
969 | + * Range of parameters | |
970 | + */ | |
971 | + | |
972 | +struct iw_range | |
973 | +{ | |
974 | + /* Informative stuff (to choose between different interface) */ | |
975 | + __u32 throughput; /* To give an idea... */ | |
976 | + /* In theory this value should be the maximum benchmarked | |
977 | + * TCP/IP throughput, because with most of these devices the | |
978 | + * bit rate is meaningless (overhead an co) to estimate how | |
979 | + * fast the connection will go and pick the fastest one. | |
980 | + * I suggest people to play with Netperf or any benchmark... | |
981 | + */ | |
982 | + | |
983 | + /* NWID (or domain id) */ | |
984 | + __u32 min_nwid; /* Minimal NWID we are able to set */ | |
985 | + __u32 max_nwid; /* Maximal NWID we are able to set */ | |
986 | + | |
987 | + /* Old Frequency (backward compat - moved lower ) */ | |
988 | + __u16 old_num_channels; | |
989 | + __u8 old_num_frequency; | |
990 | + | |
991 | + /* Wireless event capability bitmasks */ | |
992 | + __u32 event_capa[6]; | |
993 | + | |
994 | + /* signal level threshold range */ | |
995 | + __s32 sensitivity; | |
996 | + | |
997 | + /* Quality of link & SNR stuff */ | |
998 | + /* Quality range (link, level, noise) | |
999 | + * If the quality is absolute, it will be in the range [0 ; max_qual], | |
1000 | + * if the quality is dBm, it will be in the range [max_qual ; 0]. | |
1001 | + * Don't forget that we use 8 bit arithmetics... */ | |
1002 | + struct iw_quality max_qual; /* Quality of the link */ | |
1003 | + /* This should contain the average/typical values of the quality | |
1004 | + * indicator. This should be the threshold between a "good" and | |
1005 | + * a "bad" link (example : monitor going from green to orange). | |
1006 | + * Currently, user space apps like quality monitors don't have any | |
1007 | + * way to calibrate the measurement. With this, they can split | |
1008 | + * the range between 0 and max_qual in different quality level | |
1009 | + * (using a geometric subdivision centered on the average). | |
1010 | + * I expect that people doing the user space apps will feedback | |
1011 | + * us on which value we need to put in each driver... */ | |
1012 | + struct iw_quality avg_qual; /* Quality of the link */ | |
1013 | + | |
1014 | + /* Rates */ | |
1015 | + __u8 num_bitrates; /* Number of entries in the list */ | |
1016 | + __s32 bitrate[IW_MAX_BITRATES]; /* list, in bps */ | |
1017 | + | |
1018 | + /* RTS threshold */ | |
1019 | + __s32 min_rts; /* Minimal RTS threshold */ | |
1020 | + __s32 max_rts; /* Maximal RTS threshold */ | |
1021 | + | |
1022 | + /* Frag threshold */ | |
1023 | + __s32 min_frag; /* Minimal frag threshold */ | |
1024 | + __s32 max_frag; /* Maximal frag threshold */ | |
1025 | + | |
1026 | + /* Power Management duration & timeout */ | |
1027 | + __s32 min_pmp; /* Minimal PM period */ | |
1028 | + __s32 max_pmp; /* Maximal PM period */ | |
1029 | + __s32 min_pmt; /* Minimal PM timeout */ | |
1030 | + __s32 max_pmt; /* Maximal PM timeout */ | |
1031 | + __u16 pmp_flags; /* How to decode max/min PM period */ | |
1032 | + __u16 pmt_flags; /* How to decode max/min PM timeout */ | |
1033 | + __u16 pm_capa; /* What PM options are supported */ | |
1034 | + | |
1035 | + /* Encoder stuff */ | |
1036 | + __u16 encoding_size[IW_MAX_ENCODING_SIZES]; /* Different token sizes */ | |
1037 | + __u8 num_encoding_sizes; /* Number of entry in the list */ | |
1038 | + __u8 max_encoding_tokens; /* Max number of tokens */ | |
1039 | + /* For drivers that need a "login/passwd" form */ | |
1040 | + __u8 encoding_login_index; /* token index for login token */ | |
1041 | + | |
1042 | + /* Transmit power */ | |
1043 | + __u16 txpower_capa; /* What options are supported */ | |
1044 | + __u8 num_txpower; /* Number of entries in the list */ | |
1045 | + __s32 txpower[IW_MAX_TXPOWER]; /* list, in bps */ | |
1046 | + | |
1047 | + /* Wireless Extension version info */ | |
1048 | + __u8 we_version_compiled; /* Must be WIRELESS_EXT */ | |
1049 | + __u8 we_version_source; /* Last update of source */ | |
1050 | + | |
1051 | + /* Retry limits and lifetime */ | |
1052 | + __u16 retry_capa; /* What retry options are supported */ | |
1053 | + __u16 retry_flags; /* How to decode max/min retry limit */ | |
1054 | + __u16 r_time_flags; /* How to decode max/min retry life */ | |
1055 | + __s32 min_retry; /* Minimal number of retries */ | |
1056 | + __s32 max_retry; /* Maximal number of retries */ | |
1057 | + __s32 min_r_time; /* Minimal retry lifetime */ | |
1058 | + __s32 max_r_time; /* Maximal retry lifetime */ | |
1059 | + | |
1060 | + /* Frequency */ | |
1061 | + __u16 num_channels; /* Number of channels [0; num - 1] */ | |
1062 | + __u8 num_frequency; /* Number of entry in the list */ | |
1063 | + struct iw_freq freq[IW_MAX_FREQUENCIES]; /* list */ | |
1064 | + /* Note : this frequency list doesn't need to fit channel numbers, | |
1065 | + * because each entry contain its channel index */ | |
1066 | + | |
1067 | + __u32 enc_capa; /* IW_ENC_CAPA_* bit field */ | |
1068 | + | |
1069 | + /* More power management stuff */ | |
1070 | + __s32 min_pms; /* Minimal PM saving */ | |
1071 | + __s32 max_pms; /* Maximal PM saving */ | |
1072 | + __u16 pms_flags; /* How to decode max/min PM saving */ | |
1073 | + | |
1074 | + /* All available modulations for driver (hw may support less) */ | |
1075 | + __s32 modul_capa; /* IW_MODUL_* bit field */ | |
1076 | + | |
1077 | + /* More bitrate stuff */ | |
1078 | + __u32 bitrate_capa; /* Types of bitrates supported */ | |
1079 | +}; | |
1080 | + | |
1081 | +/* | |
1082 | + * Private ioctl interface information | |
1083 | + */ | |
1084 | + | |
1085 | +struct iw_priv_args | |
1086 | +{ | |
1087 | + __u32 cmd; /* Number of the ioctl to issue */ | |
1088 | + __u16 set_args; /* Type and number of args */ | |
1089 | + __u16 get_args; /* Type and number of args */ | |
1090 | + char name[IFNAMSIZ]; /* Name of the extension */ | |
1091 | +}; | |
1092 | + | |
1093 | +/* ----------------------- WIRELESS EVENTS ----------------------- */ | |
1094 | +/* | |
1095 | + * Wireless events are carried through the rtnetlink socket to user | |
1096 | + * space. They are encapsulated in the IFLA_WIRELESS field of | |
1097 | + * a RTM_NEWLINK message. | |
1098 | + */ | |
1099 | + | |
1100 | +/* | |
1101 | + * A Wireless Event. Contains basically the same data as the ioctl... | |
1102 | + */ | |
1103 | +struct iw_event | |
1104 | +{ | |
1105 | + __u16 len; /* Real lenght of this stuff */ | |
1106 | + __u16 cmd; /* Wireless IOCTL */ | |
1107 | + union iwreq_data u; /* IOCTL fixed payload */ | |
1108 | +}; | |
1109 | + | |
1110 | +/* Size of the Event prefix (including padding and alignement junk) */ | |
1111 | +#define IW_EV_LCP_LEN (sizeof(struct iw_event) - sizeof(union iwreq_data)) | |
1112 | +/* Size of the various events */ | |
1113 | +#define IW_EV_CHAR_LEN (IW_EV_LCP_LEN + IFNAMSIZ) | |
1114 | +#define IW_EV_UINT_LEN (IW_EV_LCP_LEN + sizeof(__u32)) | |
1115 | +#define IW_EV_FREQ_LEN (IW_EV_LCP_LEN + sizeof(struct iw_freq)) | |
1116 | +#define IW_EV_PARAM_LEN (IW_EV_LCP_LEN + sizeof(struct iw_param)) | |
1117 | +#define IW_EV_ADDR_LEN (IW_EV_LCP_LEN + sizeof(struct sockaddr)) | |
1118 | +#define IW_EV_QUAL_LEN (IW_EV_LCP_LEN + sizeof(struct iw_quality)) | |
1119 | + | |
1120 | +/* iw_point events are special. First, the payload (extra data) come at | |
1121 | + * the end of the event, so they are bigger than IW_EV_POINT_LEN. Second, | |
1122 | + * we omit the pointer, so start at an offset. */ | |
1123 | +#define IW_EV_POINT_OFF (((char *) &(((struct iw_point *) NULL)->length)) - \ | |
1124 | + (char *) NULL) | |
1125 | +#define IW_EV_POINT_LEN (IW_EV_LCP_LEN + sizeof(struct iw_point) - \ | |
1126 | + IW_EV_POINT_OFF) | |
1127 | + | |
1128 | +/* Size of the Event prefix when packed in stream */ | |
1129 | +#define IW_EV_LCP_PK_LEN (4) | |
1130 | +/* Size of the various events when packed in stream */ | |
1131 | +#define IW_EV_CHAR_PK_LEN (IW_EV_LCP_PK_LEN + IFNAMSIZ) | |
1132 | +#define IW_EV_UINT_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(__u32)) | |
1133 | +#define IW_EV_FREQ_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(struct iw_freq)) | |
1134 | +#define IW_EV_PARAM_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(struct iw_param)) | |
1135 | +#define IW_EV_ADDR_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(struct sockaddr)) | |
1136 | +#define IW_EV_QUAL_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(struct iw_quality)) | |
1137 | +#define IW_EV_POINT_PK_LEN (IW_EV_LCP_LEN + 4) | |
1138 | + | |
1139 | +#endif /* _LINUX_WIRELESS_H */ |