Import Debian changes 0.9.19-1
iw (0.9.19-1) unstable; urgency=low
* New upstream release.
- iw moves from /usr/bin to /usr/sbin
* Switch to source format 3.0 (quilt).
* Bump Standards-Version to 3.8.4, no other changes required.
* Remove Reinhard Tartler from uploaders as per request. Thanks for
past contributions.
* Remove uupdate command from debian/watch, bz2 orig tarballs can now
be used.
* Ensure DEB_BUILD_OPTIONS=noopt is respected by exporting default
CFLAGS in debian/rules.
* Export V=1 in debian/rules so that the upstream build system is
verbose.
* Update debian/copyright.
Kel Modderman authored 14 years ago
Paride Legovini committed 5 years ago
2 | 2 | MAKEFLAGS += --no-print-directory |
3 | 3 | |
4 | 4 | PREFIX ?= /usr |
5 | BINDIR ?= $(PREFIX)/bin | |
5 | SBINDIR ?= $(PREFIX)/sbin | |
6 | 6 | MANDIR ?= $(PREFIX)/share/man |
7 | PKG_CONFIG ?= pkg-config | |
7 | 8 | |
8 | 9 | MKDIR ?= mkdir -p |
9 | 10 | INSTALL ?= install |
12 | 13 | CFLAGS ?= -O2 -g |
13 | 14 | CFLAGS += -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -Werror-implicit-function-declaration |
14 | 15 | |
15 | OBJS = iw.o genl.o event.o info.o phy.o interface.o ibss.o station.o util.o mesh.o mpath.o scan.o reg.o version.o reason.o status.o | |
16 | OBJS = iw.o genl.o event.o info.o phy.o \ | |
17 | interface.o ibss.o station.o survey.o util.o \ | |
18 | mesh.o mpath.o scan.o reg.o version.o \ | |
19 | reason.o status.o connect.o link.o | |
20 | OBJS += sections.o | |
16 | 21 | ALL = iw |
17 | 22 | |
18 | NL1FOUND := $(shell pkg-config --atleast-version=1 libnl-1 && echo Y) | |
19 | NL2FOUND := $(shell pkg-config --atleast-version=2 libnl-2.0 && echo Y) | |
23 | NL1FOUND := $(shell $(PKG_CONFIG) --atleast-version=1 libnl-1 && echo Y) | |
24 | NL2FOUND := $(shell $(PKG_CONFIG) --atleast-version=2 libnl-2.0 && echo Y) | |
20 | 25 | |
21 | 26 | ifeq ($(NL1FOUND),Y) |
22 | 27 | NLLIBNAME = libnl-1 |
32 | 37 | $(error Cannot find development files for any supported version of libnl) |
33 | 38 | endif |
34 | 39 | |
35 | LIBS += $(shell pkg-config --libs $(NLLIBNAME)) | |
36 | CFLAGS += $(shell pkg-config --cflags $(NLLIBNAME)) | |
40 | LIBS += $(shell $(PKG_CONFIG) --libs $(NLLIBNAME)) | |
41 | CFLAGS += $(shell $(PKG_CONFIG) --cflags $(NLLIBNAME)) | |
37 | 42 | |
38 | 43 | ifeq ($(V),1) |
39 | 44 | Q= |
79 | 84 | |
80 | 85 | install: iw iw.8.gz |
81 | 86 | @$(NQ) ' INST iw' |
82 | $(Q)$(MKDIR) $(DESTDIR)$(BINDIR) | |
83 | $(Q)$(INSTALL) -m 755 -t $(DESTDIR)$(BINDIR) iw | |
87 | $(Q)$(MKDIR) $(DESTDIR)$(SBINDIR) | |
88 | $(Q)$(INSTALL) -m 755 -t $(DESTDIR)$(SBINDIR) iw | |
84 | 89 | @$(NQ) ' INST iw.8' |
85 | 90 | $(Q)$(MKDIR) $(DESTDIR)$(MANDIR)/man8/ |
86 | 91 | $(Q)$(INSTALL) -m 644 -t $(DESTDIR)$(MANDIR)/man8/ iw.8.gz |
0 | #include <errno.h> | |
1 | ||
2 | #include <netlink/genl/genl.h> | |
3 | #include <netlink/genl/family.h> | |
4 | #include <netlink/genl/ctrl.h> | |
5 | #include <netlink/msg.h> | |
6 | #include <netlink/attr.h> | |
7 | ||
8 | #include "nl80211.h" | |
9 | #include "iw.h" | |
10 | ||
11 | static int iw_conn(struct nl80211_state *state, struct nl_cb *cb, | |
12 | struct nl_msg *msg, int argc, char **argv) | |
13 | { | |
14 | char *end; | |
15 | unsigned char bssid[6]; | |
16 | int freq; | |
17 | ||
18 | if (argc < 1) | |
19 | return 1; | |
20 | ||
21 | /* SSID */ | |
22 | NLA_PUT(msg, NL80211_ATTR_SSID, strlen(argv[0]), argv[0]); | |
23 | argv++; | |
24 | argc--; | |
25 | ||
26 | /* freq */ | |
27 | if (argc) { | |
28 | freq = strtoul(argv[0], &end, 10); | |
29 | if (*end == '\0') { | |
30 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq); | |
31 | argv++; | |
32 | argc--; | |
33 | } | |
34 | } | |
35 | ||
36 | /* bssid */ | |
37 | if (argc) { | |
38 | if (mac_addr_a2n(bssid, argv[0]) == 0) { | |
39 | NLA_PUT(msg, NL80211_ATTR_MAC, 6, bssid); | |
40 | argv++; | |
41 | argc--; | |
42 | } | |
43 | } | |
44 | ||
45 | if (!argc) | |
46 | return 0; | |
47 | ||
48 | if (strcmp(*argv, "key") != 0 && strcmp(*argv, "keys") != 0) | |
49 | return 1; | |
50 | ||
51 | argv++; | |
52 | argc--; | |
53 | ||
54 | return parse_keys(msg, argv, argc); | |
55 | nla_put_failure: | |
56 | return -ENOSPC; | |
57 | } | |
58 | ||
59 | static int disconnect(struct nl80211_state *state, | |
60 | struct nl_cb *cb, | |
61 | struct nl_msg *msg, | |
62 | int argc, char **argv) | |
63 | { | |
64 | return 0; | |
65 | } | |
66 | TOPLEVEL(disconnect, NULL, | |
67 | NL80211_CMD_DISCONNECT, 0, CIB_NETDEV, disconnect, | |
68 | "Disconnect from the current network."); | |
69 | ||
70 | static int iw_connect(struct nl80211_state *state, struct nl_cb *cb, | |
71 | struct nl_msg *msg, int argc, char **argv) | |
72 | { | |
73 | char **conn_argv, *dev = argv[0]; | |
74 | static const __u32 cmds[] = { | |
75 | NL80211_CMD_CONNECT, | |
76 | }; | |
77 | struct print_event_args printargs = { }; | |
78 | int conn_argc, err; | |
79 | bool wait = false; | |
80 | int i; | |
81 | ||
82 | /* strip "wlan0 connect" */ | |
83 | argc -= 2; | |
84 | argv += 2; | |
85 | ||
86 | /* check -w */ | |
87 | if (argc && strcmp(argv[0], "-w") == 0) { | |
88 | wait = true; | |
89 | argc--; | |
90 | argv++; | |
91 | } | |
92 | ||
93 | conn_argc = 3 + argc; | |
94 | conn_argv = calloc(conn_argc, sizeof(*conn_argv)); | |
95 | if (!conn_argv) | |
96 | return -ENOMEM; | |
97 | conn_argv[0] = dev; | |
98 | conn_argv[1] = "connect"; | |
99 | conn_argv[2] = "establish"; | |
100 | for (i = 0; i < argc; i++) | |
101 | conn_argv[i + 3] = argv[i]; | |
102 | err = handle_cmd(state, II_NETDEV, conn_argc, conn_argv); | |
103 | free(conn_argv); | |
104 | if (err) | |
105 | return err; | |
106 | ||
107 | if (!wait) | |
108 | return 0; | |
109 | ||
110 | /* | |
111 | * WARNING: DO NOT COPY THIS CODE INTO YOUR APPLICATION | |
112 | * | |
113 | * This code has a bug, which requires creating a separate | |
114 | * nl80211 socket to fix: | |
115 | * It is possible for a NL80211_CMD_NEW_SCAN_RESULTS or | |
116 | * NL80211_CMD_SCAN_ABORTED message to be sent by the kernel | |
117 | * before (!) we listen to it, because we only start listening | |
118 | * after we send our scan request. | |
119 | * | |
120 | * Doing it the other way around has a race condition as well, | |
121 | * if you first open the events socket you may get a notification | |
122 | * for a previous scan. | |
123 | * | |
124 | * The only proper way to fix this would be to listen to events | |
125 | * before sending the command, and for the kernel to send the | |
126 | * connect request along with the event, so that you can match | |
127 | * up whether the connect _you_ requested was finished or aborted. | |
128 | * | |
129 | * Alas, the kernel doesn't do that (yet). | |
130 | */ | |
131 | ||
132 | __listen_events(state, ARRAY_SIZE(cmds), cmds, &printargs); | |
133 | return 0; | |
134 | } | |
135 | TOPLEVEL(connect, "[-w] <SSID> [<freq in MHz>] [<bssid>] [key 0:abcde d:1:6162636465]", | |
136 | 0, 0, CIB_NETDEV, iw_connect, | |
137 | "Join the network with the given SSID (and frequency, BSSID).\n" | |
138 | "With -w, wait for the connect to finish or fail."); | |
139 | HIDDEN(connect, establish, "", NL80211_CMD_CONNECT, 0, CIB_NETDEV, iw_conn); |
0 | iw (0.9.19-1) unstable; urgency=low | |
1 | ||
2 | * New upstream release. | |
3 | - iw moves from /usr/bin to /usr/sbin | |
4 | * Switch to source format 3.0 (quilt). | |
5 | * Bump Standards-Version to 3.8.4, no other changes required. | |
6 | * Remove Reinhard Tartler from uploaders as per request. Thanks for | |
7 | past contributions. | |
8 | * Remove uupdate command from debian/watch, bz2 orig tarballs can now | |
9 | be used. | |
10 | * Ensure DEB_BUILD_OPTIONS=noopt is respected by exporting default | |
11 | CFLAGS in debian/rules. | |
12 | * Export V=1 in debian/rules so that the upstream build system is | |
13 | verbose. | |
14 | * Update debian/copyright. | |
15 | ||
16 | -- Kel Modderman <kel@otaku42.de> Sun, 11 Apr 2010 14:25:22 +1000 | |
17 | ||
0 | 18 | iw (0.9.14-1) unstable; urgency=low |
1 | 19 | |
2 | 20 | * New upstream release. |
2 | 2 | Priority: extra |
3 | 3 | Maintainer: Debian/Ubuntu wpasupplicant Maintainers <pkg-wpa-devel@lists.alioth.debian.org> |
4 | 4 | Uploaders: Faidon Liambotis <paravoid@debian.org>, |
5 | Reinhard Tartler <siretart@tauware.de>, | |
6 | 5 | Kel Modderman <kel@otaku42.de> |
7 | 6 | Build-Depends: debhelper (>= 7), |
8 | 7 | libnl-dev (>= 1.1), |
9 | 8 | pkg-config (>= 0.22) |
10 | Standards-Version: 3.8.1 | |
9 | Standards-Version: 3.8.4 | |
11 | 10 | Vcs-Svn: svn://svn.debian.org/pkg-wpa/iw/trunk |
12 | 11 | Vcs-Browser: http://svn.debian.org/wsvn/pkg-wpa/iw/trunk/ |
13 | 12 | Homepage: http://wireless.kernel.org/en/users/Documentation/iw |
2 | 2 | Upstream-Source: http://git.sipsolutions.net/iw.git |
3 | 3 | |
4 | 4 | Files: * |
5 | Copyright: Copyright (c) 2007, 2008 Johannes Berg | |
5 | Copyright: Copyright (c) 2007-2010 Johannes Berg | |
6 | 6 | Copyright: Copyright (c) 2007 Andy Lutomirski |
7 | 7 | Copyright: Copyright (c) 2007 Mike Kershaw |
8 | Copyright: Copyright (c) 2008 Luis R. Rodriguez | |
8 | Copyright: Copyright (c) 2008-2009 Luis R. Rodriguez | |
9 | 9 | License: ISC |
10 | 10 | |
11 | 11 | Files: debian/* |
12 | Copyright: Copyright (c) 2007, 2008 Johannes Berg | |
13 | Copyright: Copyright (c) 2008 Kel Modderman | |
12 | Copyright: Copyright (c) 2007-2008 Johannes Berg | |
13 | Copyright: Copyright (c) 2008-2010 Kel Modderman | |
14 | 14 | License: ISC |
15 | 15 | |
16 | 16 | License: ISC |
0 | 0 | #!/usr/bin/make -f |
1 | export CFLAGS = -g -O$(if $(findstring noopt,$(DEB_BUILD_OPTIONS)),0,2) | |
2 | export V=1 | |
3 | ||
1 | 4 | %: |
2 | 5 | dh $@ |
0 | 3.0 (quilt) |
0 | 0 | version=3 |
1 | http://wireless.kernel.org/download/iw/iw-(.*)\.tar\.bz2 debian uupdate | |
1 | http://wireless.kernel.org/download/iw/iw-(.*)\.tar\.bz2 |
8 | 8 | return NL_OK; |
9 | 9 | } |
10 | 10 | |
11 | struct print_event_args { | |
12 | bool frame, time; | |
11 | struct ieee80211_beacon_channel { | |
12 | __u16 center_freq; | |
13 | bool passive_scan; | |
14 | bool no_ibss; | |
13 | 15 | }; |
16 | ||
17 | static int parse_beacon_hint_chan(struct nlattr *tb, | |
18 | struct ieee80211_beacon_channel *chan) | |
19 | { | |
20 | struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1]; | |
21 | static struct nla_policy beacon_freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = { | |
22 | [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 }, | |
23 | [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG }, | |
24 | [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG }, | |
25 | }; | |
26 | ||
27 | if (nla_parse_nested(tb_freq, | |
28 | NL80211_FREQUENCY_ATTR_MAX, | |
29 | tb, | |
30 | beacon_freq_policy)) | |
31 | return -EINVAL; | |
32 | ||
33 | chan->center_freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]); | |
34 | ||
35 | if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN]) | |
36 | chan->passive_scan = true; | |
37 | if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS]) | |
38 | chan->no_ibss = true; | |
39 | ||
40 | return 0; | |
41 | } | |
14 | 42 | |
15 | 43 | static void print_frame(struct print_event_args *args, struct nlattr *attr) |
16 | 44 | { |
73 | 101 | |
74 | 102 | static int print_event(struct nl_msg *msg, void *arg) |
75 | 103 | { |
104 | #define PARSE_BEACON_CHAN(_attr, _chan) do { \ | |
105 | r = parse_beacon_hint_chan(tb[_attr], \ | |
106 | &_chan); \ | |
107 | if (r) \ | |
108 | return NL_SKIP; \ | |
109 | } while (0) | |
76 | 110 | struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); |
77 | struct nlattr *tb[NL80211_ATTR_MAX + 1]; | |
111 | struct nlattr *tb[NL80211_ATTR_MAX + 1], *nst; | |
78 | 112 | struct print_event_args *args = arg; |
79 | 113 | char ifname[100]; |
80 | 114 | char macbuf[6*3]; |
81 | 115 | __u8 reg_type; |
116 | struct ieee80211_beacon_channel chan_before_beacon, chan_after_beacon; | |
117 | __u32 wiphy_idx = 0; | |
118 | int r; | |
119 | int rem_nst; | |
120 | __u16 status; | |
82 | 121 | |
83 | 122 | if (args->time) { |
84 | 123 | struct timeval tv; |
103 | 142 | case NL80211_CMD_NEW_WIPHY: |
104 | 143 | printf("renamed to %s\n", nla_get_string(tb[NL80211_ATTR_WIPHY_NAME])); |
105 | 144 | break; |
145 | case NL80211_CMD_TRIGGER_SCAN: | |
146 | printf("scan started\n"); | |
147 | break; | |
106 | 148 | case NL80211_CMD_NEW_SCAN_RESULTS: |
107 | printf("scan finished\n"); | |
108 | break; | |
149 | printf("scan finished:"); | |
109 | 150 | case NL80211_CMD_SCAN_ABORTED: |
110 | printf("scan aborted\n"); | |
151 | if (gnlh->cmd == NL80211_CMD_SCAN_ABORTED) | |
152 | printf("scan aborted:"); | |
153 | if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) { | |
154 | nla_for_each_nested(nst, tb[NL80211_ATTR_SCAN_FREQUENCIES], rem_nst) | |
155 | printf(" %d", nla_get_u32(nst)); | |
156 | printf(","); | |
157 | } | |
158 | if (tb[NL80211_ATTR_SCAN_SSIDS]) { | |
159 | nla_for_each_nested(nst, tb[NL80211_ATTR_SCAN_SSIDS], rem_nst) { | |
160 | printf(" \""); | |
161 | print_ssid_escaped(nla_len(nst), nla_data(nst)); | |
162 | printf("\""); | |
163 | } | |
164 | } | |
165 | printf("\n"); | |
111 | 166 | break; |
112 | 167 | case NL80211_CMD_REG_CHANGE: |
113 | 168 | printf("regulatory domain change: "); |
144 | 199 | |
145 | 200 | printf("\n"); |
146 | 201 | break; |
202 | case NL80211_CMD_REG_BEACON_HINT: | |
203 | ||
204 | wiphy_idx = nla_get_u32(tb[NL80211_ATTR_WIPHY]); | |
205 | ||
206 | memset(&chan_before_beacon, 0, sizeof(chan_before_beacon)); | |
207 | memset(&chan_after_beacon, 0, sizeof(chan_after_beacon)); | |
208 | ||
209 | PARSE_BEACON_CHAN(NL80211_ATTR_FREQ_BEFORE, chan_before_beacon); | |
210 | PARSE_BEACON_CHAN(NL80211_ATTR_FREQ_AFTER, chan_after_beacon); | |
211 | ||
212 | if (chan_before_beacon.center_freq != chan_after_beacon.center_freq) | |
213 | break; | |
214 | ||
215 | /* A beacon hint is sent _only_ if something _did_ change */ | |
216 | printf("beacon hint:\n"); | |
217 | ||
218 | printf("phy%d %d MHz [%d]:\n", | |
219 | wiphy_idx, | |
220 | chan_before_beacon.center_freq, | |
221 | ieee80211_frequency_to_channel(chan_before_beacon.center_freq)); | |
222 | ||
223 | if (chan_before_beacon.passive_scan && !chan_after_beacon.passive_scan) | |
224 | printf("\to active scanning enabled\n"); | |
225 | if (chan_before_beacon.no_ibss && !chan_after_beacon.no_ibss) | |
226 | printf("\to beaconing enabled\n"); | |
227 | ||
228 | break; | |
229 | case NL80211_CMD_NEW_STATION: | |
230 | mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC])); | |
231 | printf("new station %s\n", macbuf); | |
232 | break; | |
147 | 233 | case NL80211_CMD_JOIN_IBSS: |
148 | 234 | mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC])); |
149 | 235 | printf("IBSS %s joined\n", macbuf); |
150 | 236 | break; |
151 | 237 | case NL80211_CMD_AUTHENTICATE: |
152 | 238 | printf("auth"); |
153 | print_frame(args, tb[NL80211_ATTR_FRAME]); | |
239 | if (tb[NL80211_ATTR_FRAME]) | |
240 | print_frame(args, tb[NL80211_ATTR_FRAME]); | |
241 | else if (tb[NL80211_ATTR_TIMED_OUT]) | |
242 | printf(": timed out"); | |
243 | else | |
244 | printf(": unknown event"); | |
154 | 245 | printf("\n"); |
155 | 246 | break; |
156 | 247 | case NL80211_CMD_ASSOCIATE: |
157 | 248 | printf("assoc"); |
158 | print_frame(args, tb[NL80211_ATTR_FRAME]); | |
249 | if (tb[NL80211_ATTR_FRAME]) | |
250 | print_frame(args, tb[NL80211_ATTR_FRAME]); | |
251 | else if (tb[NL80211_ATTR_TIMED_OUT]) | |
252 | printf(": timed out"); | |
253 | else | |
254 | printf(": unknown event"); | |
159 | 255 | printf("\n"); |
160 | 256 | break; |
161 | 257 | case NL80211_CMD_DEAUTHENTICATE: |
168 | 264 | print_frame(args, tb[NL80211_ATTR_FRAME]); |
169 | 265 | printf("\n"); |
170 | 266 | break; |
267 | case NL80211_CMD_CONNECT: | |
268 | status = 0; | |
269 | if (!tb[NL80211_ATTR_STATUS_CODE]) | |
270 | printf("unknown connect status"); | |
271 | else if (nla_get_u16(tb[NL80211_ATTR_STATUS_CODE]) == 0) | |
272 | printf("connected"); | |
273 | else { | |
274 | status = nla_get_u16(tb[NL80211_ATTR_STATUS_CODE]); | |
275 | printf("failed to connect"); | |
276 | } | |
277 | if (tb[NL80211_ATTR_MAC]) { | |
278 | mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC])); | |
279 | printf(" to %s", macbuf); | |
280 | } | |
281 | if (status) | |
282 | printf(", status: %d: %s", status, get_status_str(status)); | |
283 | printf("\n"); | |
284 | break; | |
285 | case NL80211_CMD_ROAM: | |
286 | printf("roamed"); | |
287 | if (tb[NL80211_ATTR_MAC]) { | |
288 | mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC])); | |
289 | printf(" to %s", macbuf); | |
290 | } | |
291 | printf("\n"); | |
292 | break; | |
293 | case NL80211_CMD_DISCONNECT: | |
294 | printf("disconnected"); | |
295 | if (tb[NL80211_ATTR_DISCONNECTED_BY_AP]) | |
296 | printf(" (by AP)"); | |
297 | else | |
298 | printf(" (local request)"); | |
299 | if (tb[NL80211_ATTR_REASON_CODE]) | |
300 | printf(" reason: %d: %s", nla_get_u16(tb[NL80211_ATTR_REASON_CODE]), | |
301 | get_reason_str(nla_get_u16(tb[NL80211_ATTR_REASON_CODE]))); | |
302 | printf("\n"); | |
303 | break; | |
171 | 304 | default: |
172 | 305 | printf("unknown event %d\n", gnlh->cmd); |
173 | 306 | break; |
174 | 307 | } |
175 | 308 | |
176 | 309 | return NL_SKIP; |
310 | #undef PARSE_BEACON_CHAN | |
177 | 311 | } |
178 | 312 | |
179 | 313 | struct wait_event { |
180 | 314 | int n_cmds; |
181 | 315 | const __u32 *cmds; |
182 | 316 | __u32 cmd; |
317 | struct print_event_args *pargs; | |
183 | 318 | }; |
184 | 319 | |
185 | 320 | static int wait_event(struct nl_msg *msg, void *arg) |
191 | 326 | for (i = 0; i < wait->n_cmds; i++) { |
192 | 327 | if (gnlh->cmd == wait->cmds[i]) { |
193 | 328 | wait->cmd = gnlh->cmd; |
329 | if (wait->pargs) | |
330 | print_event(msg, wait->pargs); | |
194 | 331 | } |
195 | 332 | } |
196 | 333 | |
197 | 334 | return NL_SKIP; |
198 | 335 | } |
199 | 336 | |
200 | static __u32 __listen_events(struct nl80211_state *state, | |
201 | const int n_waits, const __u32 *waits, | |
202 | struct print_event_args *args) | |
337 | __u32 __listen_events(struct nl80211_state *state, | |
338 | const int n_waits, const __u32 *waits, | |
339 | struct print_event_args *args) | |
203 | 340 | { |
204 | 341 | int mcid, ret; |
205 | 342 | struct nl_cb *cb = nl_cb_alloc(iw_debug ? NL_CB_DEBUG : NL_CB_DEFAULT); |
249 | 386 | if (n_waits && waits) { |
250 | 387 | wait_ev.cmds = waits; |
251 | 388 | wait_ev.n_cmds = n_waits; |
389 | wait_ev.pargs = args; | |
252 | 390 | nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, wait_event, &wait_ev); |
253 | } else { | |
391 | } else | |
254 | 392 | nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_event, args); |
255 | } | |
256 | 393 | |
257 | 394 | wait_ev.cmd = 0; |
258 | 395 |
7 | 7 | |
8 | 8 | #include "nl80211.h" |
9 | 9 | #include "iw.h" |
10 | ||
11 | SECTION(ibss); | |
10 | 12 | |
11 | 13 | static int join_ibss(struct nl80211_state *state, |
12 | 14 | struct nl_cb *cb, |
39 | 41 | } |
40 | 42 | |
41 | 43 | if (argc) { |
42 | if (mac_addr_a2n(abssid, argv[0])) | |
43 | return 1; | |
44 | NLA_PUT(msg, NL80211_ATTR_MAC, 6, abssid); | |
45 | argv++; | |
46 | argc--; | |
44 | if (mac_addr_a2n(abssid, argv[0]) == 0) { | |
45 | NLA_PUT(msg, NL80211_ATTR_MAC, 6, abssid); | |
46 | argv++; | |
47 | argc--; | |
48 | } | |
47 | 49 | } |
48 | 50 | |
49 | if (argc) | |
51 | if (!argc) | |
52 | return 0; | |
53 | ||
54 | if (strcmp(*argv, "key") != 0 && strcmp(*argv, "keys") != 0) | |
50 | 55 | return 1; |
51 | 56 | |
52 | return 0; | |
57 | argv++; | |
58 | argc--; | |
59 | ||
60 | return parse_keys(msg, argv, argc); | |
53 | 61 | nla_put_failure: |
54 | 62 | return -ENOSPC; |
55 | 63 | } |
64 | 72 | COMMAND(ibss, leave, NULL, |
65 | 73 | NL80211_CMD_LEAVE_IBSS, 0, CIB_NETDEV, leave_ibss, |
66 | 74 | "Leave the current IBSS cell."); |
67 | COMMAND(ibss, join, "<SSID> <freq in MHz> [fixed-freq] [<fixed bssid>]", | |
75 | COMMAND(ibss, join, "<SSID> <freq in MHz> [fixed-freq] [<fixed bssid>] [key d:0:abcde]", | |
68 | 76 | NL80211_CMD_JOIN_IBSS, 0, CIB_NETDEV, join_ibss, |
69 | 77 | "Join the IBSS cell with the given SSID, if it doesn't exist create\n" |
70 | 78 | "it on the given frequency. When fixed frequency is requested, don't\n" |
18 | 18 | printf(", "); |
19 | 19 | printf("%s", name); |
20 | 20 | *open = 1; |
21 | } | |
22 | ||
23 | static void print_mcs_index(unsigned char *mcs) | |
24 | { | |
25 | unsigned int mcs_bit; | |
26 | ||
27 | for (mcs_bit = 0; mcs_bit <= 76; mcs_bit++) { | |
28 | unsigned int mcs_octet = mcs_bit/8; | |
29 | unsigned int MCS_RATE_BIT = 1 << mcs_bit % 8; | |
30 | bool mcs_rate_idx_set; | |
31 | ||
32 | mcs_rate_idx_set = !!(mcs[mcs_octet] & MCS_RATE_BIT); | |
33 | ||
34 | if (!mcs_rate_idx_set) | |
35 | continue; | |
36 | ||
37 | printf("\t\t\tMCS index %d\n", mcs_bit); | |
38 | } | |
39 | 21 | } |
40 | 22 | |
41 | 23 | static int print_phy_handler(struct nl_msg *msg, void *arg) |
65 | 47 | struct nlattr *nl_freq; |
66 | 48 | struct nlattr *nl_rate; |
67 | 49 | struct nlattr *nl_mode; |
50 | struct nlattr *nl_cmd; | |
68 | 51 | int bandidx = 1; |
69 | int rem_band, rem_freq, rem_rate, rem_mode; | |
52 | int rem_band, rem_freq, rem_rate, rem_mode, rem_cmd; | |
70 | 53 | int open; |
71 | 54 | |
72 | 55 | nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), |
87 | 70 | |
88 | 71 | #ifdef NL80211_BAND_ATTR_HT_CAPA |
89 | 72 | if (tb_band[NL80211_BAND_ATTR_HT_CAPA]) { |
90 | unsigned short cap = nla_get_u16(tb_band[NL80211_BAND_ATTR_HT_CAPA]); | |
91 | #define PCOM(fmt, args...) do { printf("\t\t\t* " fmt "\n", ##args); } while (0) | |
92 | #define PBCOM(bit, args...) if (cap & (bit)) PCOM(args) | |
93 | printf("\t\tHT capabilities: 0x%.4x\n", cap); | |
94 | PBCOM(0x0001, "LPDC coding"); | |
95 | if (cap & 0x0002) | |
96 | PCOM("20/40 MHz operation"); | |
97 | else | |
98 | PCOM("20 MHz operation"); | |
99 | switch ((cap & 0x000c) >> 2) { | |
100 | case 0: | |
101 | PCOM("static SM PS"); | |
102 | break; | |
103 | case 1: | |
104 | PCOM("dynamic SM PS"); | |
105 | break; | |
106 | case 2: | |
107 | PCOM("reserved SM PS"); | |
108 | break; | |
109 | case 3: | |
110 | PCOM("SM PS disabled"); | |
111 | break; | |
112 | } | |
113 | PBCOM(0x0010, "HT-greenfield"); | |
114 | PBCOM(0x0020, "20 MHz short GI"); | |
115 | PBCOM(0x0040, "40 MHz short GI"); | |
116 | PBCOM(0x0080, "TX STBC"); | |
117 | if (cap & 0x300) | |
118 | PCOM("RX STBC %d streams", (cap & 0x0300) >> 8); | |
119 | PBCOM(0x0400, "HT-delayed block-ack"); | |
120 | PCOM("max A-MSDU len %d", 0xeff + ((cap & 0x0800) << 1)); | |
121 | PBCOM(0x1000, "DSSS/CCK 40 MHz"); | |
122 | PBCOM(0x2000, "PSMP support"); | |
123 | PBCOM(0x4000, "40 MHz intolerant"); | |
124 | PBCOM(0x8000, "L-SIG TXOP protection support"); | |
73 | __u16 cap = nla_get_u16(tb_band[NL80211_BAND_ATTR_HT_CAPA]); | |
74 | print_ht_capability(cap); | |
125 | 75 | } |
126 | 76 | if (tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR]) { |
127 | unsigned char factor = nla_get_u8(tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR]); | |
128 | printf("\t\tHT A-MPDU factor: 0x%.4x (%d bytes)\n", factor, (1<<(13+factor))-1); | |
77 | __u8 exponent = nla_get_u8(tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR]); | |
78 | print_ampdu_length(exponent); | |
129 | 79 | } |
130 | 80 | if (tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY]) { |
131 | unsigned char dens = nla_get_u8(tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY]); | |
132 | printf("\t\tHT A-MPDU density: 0x%.4x (", dens); | |
133 | switch (dens) { | |
134 | case 0: | |
135 | printf("no restriction)\n"); | |
136 | break; | |
137 | case 1: | |
138 | printf("1/4 usec)\n"); | |
139 | break; | |
140 | case 2: | |
141 | printf("1/2 usec)\n"); | |
142 | break; | |
143 | default: | |
144 | printf("%d usec)\n", 1<<(dens - 3)); | |
145 | } | |
81 | __u8 spacing = nla_get_u8(tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY]); | |
82 | print_ampdu_spacing(spacing); | |
146 | 83 | } |
147 | 84 | if (tb_band[NL80211_BAND_ATTR_HT_MCS_SET] && |
148 | nla_len(tb_band[NL80211_BAND_ATTR_HT_MCS_SET]) == 16) { | |
149 | /* As defined in 7.3.2.57.4 Supported MCS Set field */ | |
150 | unsigned int tx_max_num_spatial_streams, max_rx_supp_data_rate; | |
151 | unsigned char *mcs = nla_data(tb_band[NL80211_BAND_ATTR_HT_MCS_SET]); | |
152 | bool tx_mcs_set_defined, tx_mcs_set_equal, tx_unequal_modulation; | |
153 | ||
154 | printf("\t\tHT MCS set: %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n", | |
155 | mcs[0], mcs[1], mcs[2], mcs[3], mcs[4], mcs[5], mcs[6], mcs[7], | |
156 | mcs[8], mcs[9], mcs[10], mcs[11], mcs[12], mcs[13], mcs[14], mcs[15]); | |
157 | ||
158 | max_rx_supp_data_rate = ((mcs[10] >> 8) & ((mcs[11] & 0x3) << 8)); | |
159 | tx_mcs_set_defined = !!(mcs[12] & (1 << 0)); | |
160 | tx_mcs_set_equal = !(mcs[12] & (1 << 1)); | |
161 | tx_max_num_spatial_streams = (mcs[12] | ((1 << 3) | (1 << 4))) + 1; | |
162 | tx_unequal_modulation = !!(mcs[12] & (1 << 5)); | |
163 | ||
164 | if (max_rx_supp_data_rate) | |
165 | printf("\t\tHT Max RX data rate: %d Mbps\n", max_rx_supp_data_rate); | |
166 | /* XXX: else see 9.6.0e.5.3 how to get this I think */ | |
167 | ||
168 | if (tx_mcs_set_defined) { | |
169 | if (tx_mcs_set_equal) { | |
170 | printf("\t\tHT TX/RX MCS rate indexes supported:\n"); | |
171 | print_mcs_index(&mcs[0]); | |
172 | } else { | |
173 | printf("\t\tHT RX MCS rate indexes supported:\n"); | |
174 | print_mcs_index(&mcs[0]); | |
175 | ||
176 | if (tx_unequal_modulation) | |
177 | printf("TX unequal modulation supported\n"); | |
178 | else | |
179 | printf("TX unequal modulation not supported\n"); | |
180 | ||
181 | printf("\t\tHT TX Max spatiel streams: %d\n", | |
182 | tx_max_num_spatial_streams); | |
183 | ||
184 | printf("\t\tHT TX MCS rate indexes supported may differ\n"); | |
185 | } | |
186 | } | |
187 | else { | |
188 | printf("\t\tHT RX MCS rate indexes supported:\n"); | |
189 | print_mcs_index(&mcs[0]); | |
190 | printf("\t\tHT TX MCS rates indexes are undefined\n"); | |
191 | } | |
192 | ||
193 | } | |
85 | nla_len(tb_band[NL80211_BAND_ATTR_HT_MCS_SET]) == 16) | |
86 | print_ht_mcs(nla_data(tb_band[NL80211_BAND_ATTR_HT_MCS_SET])); | |
194 | 87 | #endif |
195 | 88 | |
196 | 89 | printf("\t\tFrequencies:\n"); |
225 | 118 | printf("\n"); |
226 | 119 | } |
227 | 120 | |
228 | printf("\t\tBitrates:\n"); | |
121 | printf("\t\tBitrates (non-HT):\n"); | |
229 | 122 | |
230 | 123 | nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) { |
231 | 124 | nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate), |
246 | 139 | printf("\tmax # scan SSIDs: %d\n", |
247 | 140 | nla_get_u8(tb_msg[NL80211_ATTR_MAX_NUM_SCAN_SSIDS])); |
248 | 141 | |
142 | if (tb_msg[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]) { | |
143 | unsigned int frag; | |
144 | ||
145 | frag = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]); | |
146 | if (frag != (unsigned int)-1) | |
147 | printf("\tFragmentation threshold: %d\n", frag); | |
148 | } | |
149 | ||
150 | if (tb_msg[NL80211_ATTR_WIPHY_RTS_THRESHOLD]) { | |
151 | unsigned int rts; | |
152 | ||
153 | rts = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_RTS_THRESHOLD]); | |
154 | if (rts != (unsigned int)-1) | |
155 | printf("\tRTS threshold: %d\n", rts); | |
156 | } | |
157 | ||
249 | 158 | if (!tb_msg[NL80211_ATTR_SUPPORTED_IFTYPES]) |
250 | return NL_SKIP; | |
159 | goto commands; | |
251 | 160 | |
252 | 161 | printf("\tSupported interface modes:\n"); |
253 | 162 | nla_for_each_nested(nl_mode, tb_msg[NL80211_ATTR_SUPPORTED_IFTYPES], rem_mode) |
254 | 163 | printf("\t\t * %s\n", iftype_name(nl_mode->nla_type)); |
164 | ||
165 | commands: | |
166 | if (!tb_msg[NL80211_ATTR_SUPPORTED_COMMANDS]) | |
167 | return NL_SKIP; | |
168 | ||
169 | printf("\tSupported commands:\n"); | |
170 | nla_for_each_nested(nl_cmd, tb_msg[NL80211_ATTR_SUPPORTED_COMMANDS], rem_cmd) | |
171 | printf("\t\t * %s\n", command_name(nla_get_u32(nl_cmd))); | |
255 | 172 | |
256 | 173 | return NL_SKIP; |
257 | 174 | } |
265 | 182 | |
266 | 183 | return 0; |
267 | 184 | } |
268 | TOPLEVEL(info, NULL, NL80211_CMD_GET_WIPHY, 0, CIB_PHY, handle_info, | |
185 | __COMMAND(NULL, info, "info", NULL, NL80211_CMD_GET_WIPHY, 0, 0, CIB_PHY, handle_info, | |
269 | 186 | "Show capabilities for the specified wireless device."); |
270 | 187 | TOPLEVEL(list, NULL, NL80211_CMD_GET_WIPHY, NLM_F_DUMP, CIB_NONE, handle_info, |
271 | 188 | "List all wireless devices and their capabilities."); |
16 | 16 | "control: show control frames\n"\ |
17 | 17 | "otherbss: show frames from other BSSes\n"\ |
18 | 18 | "cook: use cooked mode" |
19 | ||
20 | SECTION(interface); | |
19 | 21 | |
20 | 22 | static char *mntr_flags[NL80211_MNTR_FLAG_MAX + 1] = { |
21 | 23 | "none", |
134 | 136 | return 2; |
135 | 137 | } |
136 | 138 | |
139 | static int parse_4addr_flag(const char *value, struct nl_msg *msg) | |
140 | { | |
141 | if (strcmp(value, "on") == 0) | |
142 | NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, 1); | |
143 | else if (strcmp(value, "off") == 0) | |
144 | NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, 0); | |
145 | else | |
146 | return 1; | |
147 | return 0; | |
148 | ||
149 | nla_put_failure: | |
150 | return 1; | |
151 | } | |
152 | ||
137 | 153 | static int handle_interface_add(struct nl80211_state *state, |
138 | 154 | struct nl_cb *cb, |
139 | 155 | struct nl_msg *msg, |
163 | 179 | if (!argc) |
164 | 180 | return 1; |
165 | 181 | mesh_id = argv[0]; |
182 | argc--; | |
183 | argv++; | |
184 | } else if (strcmp(argv[0], "4addr") == 0) { | |
185 | argc--; | |
186 | argv++; | |
187 | if (parse_4addr_flag(argv[0], msg)) { | |
188 | fprintf(stderr, "4addr error\n"); | |
189 | return 2; | |
190 | } | |
166 | 191 | argc--; |
167 | 192 | argv++; |
168 | 193 | } else if (strcmp(argv[0], "flags") == 0) { |
189 | 214 | nla_put_failure: |
190 | 215 | return -ENOBUFS; |
191 | 216 | } |
192 | COMMAND(interface, add, "<name> type <type> [mesh_id <meshid>] [flags <flag>*]", | |
217 | COMMAND(interface, add, "<name> type <type> [mesh_id <meshid>] [4addr on|off] [flags <flag>*]", | |
193 | 218 | NL80211_CMD_NEW_INTERFACE, 0, CIB_PHY, handle_interface_add, |
194 | 219 | "Add a new virtual interface with the given configuration.\n" |
195 | 220 | IFACE_TYPES "\n\n" |
196 | 221 | "The flags are only used for monitor interfaces, valid flags are:\n" |
197 | 222 | VALID_FLAGS "\n\n" |
198 | 223 | "The mesh_id is used only for mesh mode."); |
199 | COMMAND(interface, add, "<name> type <type> [mesh_id <meshid>] [flags <flag>*]", | |
224 | COMMAND(interface, add, "<name> type <type> [mesh_id <meshid>] [4addr on|off] [flags <flag>*]", | |
200 | 225 | NL80211_CMD_NEW_INTERFACE, 0, CIB_NETDEV, handle_interface_add, NULL); |
201 | 226 | |
202 | 227 | static int handle_interface_del(struct nl80211_state *state, |
93 | 93 | nl_socket_free(state->nl_sock); |
94 | 94 | } |
95 | 95 | |
96 | __COMMAND(NULL, NULL, "", NULL, 0, 0, 0, CIB_NONE, NULL, NULL); | |
97 | __COMMAND(NULL, NULL, "", NULL, 1, 0, 0, CIB_NONE, NULL, NULL); | |
98 | ||
99 | 96 | static int cmd_size; |
100 | 97 | |
101 | static void __usage_cmd(struct cmd *cmd, char *indent, bool full) | |
98 | extern struct cmd __start___cmd; | |
99 | extern struct cmd __stop___cmd; | |
100 | ||
101 | #define for_each_cmd(_cmd) \ | |
102 | for (_cmd = &__start___cmd; _cmd < &__stop___cmd; \ | |
103 | _cmd = (const struct cmd *)((char *)_cmd + cmd_size)) | |
104 | ||
105 | ||
106 | static void __usage_cmd(const struct cmd *cmd, char *indent, bool full) | |
102 | 107 | { |
103 | 108 | const char *start, *lend, *end; |
104 | 109 | |
105 | fprintf(stderr, "%s", indent); | |
110 | printf("%s", indent); | |
106 | 111 | |
107 | 112 | switch (cmd->idby) { |
108 | 113 | case CIB_NONE: |
109 | 114 | break; |
110 | 115 | case CIB_PHY: |
111 | fprintf(stderr, "phy <phyname> "); | |
116 | printf("phy <phyname> "); | |
112 | 117 | break; |
113 | 118 | case CIB_NETDEV: |
114 | fprintf(stderr, "dev <devname> "); | |
115 | break; | |
116 | } | |
117 | if (cmd->section) | |
118 | fprintf(stderr, "%s ", cmd->section); | |
119 | fprintf(stderr, "%s", cmd->name); | |
119 | printf("dev <devname> "); | |
120 | break; | |
121 | } | |
122 | if (cmd->parent && cmd->parent->name) | |
123 | printf("%s ", cmd->parent->name); | |
124 | printf("%s", cmd->name); | |
120 | 125 | if (cmd->args) |
121 | fprintf(stderr, " %s", cmd->args); | |
122 | fprintf(stderr, "\n"); | |
126 | printf(" %s", cmd->args); | |
127 | printf("\n"); | |
123 | 128 | |
124 | 129 | if (!full || !cmd->help) |
125 | 130 | return; |
128 | 133 | if (strlen(indent)) |
129 | 134 | indent = "\t\t"; |
130 | 135 | else |
131 | fprintf(stderr, "\n"); | |
136 | printf("\n"); | |
132 | 137 | |
133 | 138 | /* print line by line */ |
134 | 139 | start = cmd->help; |
137 | 142 | lend = strchr(start, '\n'); |
138 | 143 | if (!lend) |
139 | 144 | lend = end; |
140 | fprintf(stderr, "%s", indent); | |
141 | fprintf(stderr, "%.*s\n", (int)(lend - start), start); | |
145 | printf("%s", indent); | |
146 | printf("%.*s\n", (int)(lend - start), start); | |
142 | 147 | start = lend + 1; |
143 | 148 | } while (end != lend); |
144 | 149 | |
145 | fprintf(stderr, "\n"); | |
150 | printf("\n"); | |
146 | 151 | } |
147 | 152 | |
148 | 153 | static void usage_options(void) |
149 | 154 | { |
150 | fprintf(stderr, "Options:\n"); | |
151 | fprintf(stderr, "\t--debug\t\tenable netlink debugging\n"); | |
155 | printf("Options:\n"); | |
156 | printf("\t--debug\t\tenable netlink debugging\n"); | |
152 | 157 | } |
153 | 158 | |
154 | 159 | static const char *argv0; |
155 | 160 | |
156 | 161 | static void usage(bool full) |
157 | 162 | { |
158 | struct cmd *cmd; | |
159 | ||
160 | fprintf(stderr, "Usage:\t%s [options] command\n", argv0); | |
163 | const struct cmd *section, *cmd; | |
164 | ||
165 | printf("Usage:\t%s [options] command\n", argv0); | |
161 | 166 | usage_options(); |
162 | fprintf(stderr, "\t--version\tshow version (%s)\n", iw_version); | |
163 | fprintf(stderr, "Commands:\n"); | |
164 | for (cmd = &__start___cmd; cmd < &__stop___cmd; | |
165 | cmd = (struct cmd *)((char *)cmd + cmd_size)) { | |
166 | if (!cmd->handler || cmd->hidden) | |
167 | printf("\t--version\tshow version (%s)\n", iw_version); | |
168 | printf("Commands:\n"); | |
169 | for_each_cmd(section) { | |
170 | if (section->parent) | |
167 | 171 | continue; |
168 | __usage_cmd(cmd, "\t", full); | |
169 | } | |
172 | ||
173 | if (section->handler && !section->hidden) | |
174 | __usage_cmd(section, "\t", full); | |
175 | ||
176 | for_each_cmd(cmd) { | |
177 | if (section != cmd->parent) | |
178 | continue; | |
179 | if (!cmd->handler || cmd->hidden) | |
180 | continue; | |
181 | __usage_cmd(cmd, "\t", full); | |
182 | } | |
183 | } | |
184 | printf("\nYou can omit the 'phy' or 'dev' if " | |
185 | "the identification is unique,\n" | |
186 | "e.g. \"iw wlan0 info\" or \"iw phy0 info\". " | |
187 | "(Don't when scripting.)\n\n" | |
188 | "Do NOT screenscrape this tool, we don't " | |
189 | "consider its output stable.\n\n"); | |
170 | 190 | } |
171 | 191 | |
172 | 192 | static int print_help(struct nl80211_state *state, |
179 | 199 | TOPLEVEL(help, NULL, 0, 0, CIB_NONE, print_help, |
180 | 200 | "Print usage for each command."); |
181 | 201 | |
182 | static void usage_cmd(struct cmd *cmd) | |
183 | { | |
184 | fprintf(stderr, "Usage:\t%s [options] ", argv0); | |
202 | static void usage_cmd(const struct cmd *cmd) | |
203 | { | |
204 | printf("Usage:\t%s [options] ", argv0); | |
185 | 205 | __usage_cmd(cmd, "", true); |
186 | 206 | usage_options(); |
187 | 207 | } |
202 | 222 | if (fd < 0) |
203 | 223 | return -1; |
204 | 224 | pos = read(fd, buf, sizeof(buf) - 1); |
205 | if (pos < 0) | |
225 | if (pos < 0) { | |
226 | close(fd); | |
206 | 227 | return -1; |
228 | } | |
207 | 229 | buf[pos] = '\0'; |
230 | close(fd); | |
208 | 231 | return atoi(buf); |
209 | 232 | } |
210 | 233 | |
231 | 254 | } |
232 | 255 | |
233 | 256 | static int __handle_cmd(struct nl80211_state *state, enum id_input idby, |
234 | int argc, char **argv, struct cmd **cmdout) | |
235 | { | |
236 | struct cmd *cmd, *match = NULL; | |
257 | int argc, char **argv, const struct cmd **cmdout) | |
258 | { | |
259 | const struct cmd *cmd, *match = NULL, *sectcmd; | |
237 | 260 | struct nl_cb *cb; |
238 | 261 | struct nl_msg *msg; |
239 | 262 | int devidx = 0; |
278 | 301 | if (devidx < 0) |
279 | 302 | return -errno; |
280 | 303 | |
281 | section = command = *argv; | |
304 | section = *argv; | |
282 | 305 | argc--; |
283 | 306 | argv++; |
284 | 307 | |
285 | for (cmd = &__start___cmd; cmd < &__stop___cmd; | |
286 | cmd = (struct cmd *)((char *)cmd + cmd_size)) { | |
308 | for_each_cmd(sectcmd) { | |
309 | if (sectcmd->parent) | |
310 | continue; | |
311 | /* ok ... bit of a hack for the dupe 'info' section */ | |
312 | if (match && sectcmd->idby != command_idby) | |
313 | continue; | |
314 | if (strcmp(sectcmd->name, section) == 0) | |
315 | match = sectcmd; | |
316 | } | |
317 | ||
318 | sectcmd = match; | |
319 | match = NULL; | |
320 | if (!sectcmd) | |
321 | return 1; | |
322 | ||
323 | if (argc > 0) { | |
324 | command = *argv; | |
325 | ||
326 | for_each_cmd(cmd) { | |
327 | if (!cmd->handler) | |
328 | continue; | |
329 | if (cmd->parent != sectcmd) | |
330 | continue; | |
331 | if (cmd->idby != command_idby) | |
332 | continue; | |
333 | if (strcmp(cmd->name, command)) | |
334 | continue; | |
335 | if (argc > 1 && !cmd->args) | |
336 | continue; | |
337 | match = cmd; | |
338 | break; | |
339 | } | |
340 | ||
341 | if (match) { | |
342 | argc--; | |
343 | argv++; | |
344 | } | |
345 | } | |
346 | ||
347 | if (match) | |
348 | cmd = match; | |
349 | else { | |
350 | /* Use the section itself, if possible. */ | |
351 | cmd = sectcmd; | |
352 | if (argc && !cmd->args) | |
353 | return 1; | |
354 | if (cmd->idby != command_idby) | |
355 | return 1; | |
287 | 356 | if (!cmd->handler) |
288 | continue; | |
289 | if (cmd->idby != command_idby) | |
290 | continue; | |
291 | if (cmd->section) { | |
292 | if (strcmp(cmd->section, section)) | |
293 | continue; | |
294 | /* this is a bit icky ... */ | |
295 | if (command == section) { | |
296 | if (argc <= 0) { | |
297 | if (match) | |
298 | break; | |
299 | return 1; | |
300 | } | |
301 | command = *argv; | |
302 | argc--; | |
303 | argv++; | |
304 | } | |
305 | } else if (section != command) | |
306 | continue; | |
307 | if (strcmp(cmd->name, command)) | |
308 | continue; | |
309 | if (argc && !cmd->args) | |
310 | continue; | |
311 | ||
312 | match = cmd; | |
313 | } | |
314 | ||
315 | cmd = match; | |
316 | ||
317 | if (!cmd) | |
318 | return 1; | |
357 | return 1; | |
358 | } | |
319 | 359 | |
320 | 360 | if (cmdout) |
321 | 361 | *cmdout = cmd; |
389 | 429 | { |
390 | 430 | struct nl80211_state nlstate; |
391 | 431 | int err; |
392 | struct cmd *cmd = NULL; | |
432 | const struct cmd *cmd = NULL; | |
393 | 433 | |
394 | 434 | /* calculate command size including padding */ |
395 | cmd_size = abs((long)&__cmd_NULL_NULL_1_CIB_NONE_0 | |
396 | - (long)&__cmd_NULL_NULL_0_CIB_NONE_0); | |
435 | cmd_size = abs((long)&__section_set - (long)&__section_get); | |
397 | 436 | /* strip off self */ |
398 | 437 | argc--; |
399 | 438 | argv0 = *argv++; |
431 | 470 | } else if (*(*argv + 3) == '#') |
432 | 471 | err = __handle_cmd(&nlstate, II_PHY_IDX, argc, argv, &cmd); |
433 | 472 | else |
434 | err = 1; | |
435 | } else | |
436 | err = __handle_cmd(&nlstate, II_NONE, argc, argv, &cmd); | |
473 | goto detect; | |
474 | } else { | |
475 | int idx; | |
476 | enum id_input idby = II_NONE; | |
477 | detect: | |
478 | if ((idx = if_nametoindex(argv[0])) != 0) | |
479 | idby = II_NETDEV; | |
480 | else if ((idx = phy_lookup(argv[0])) >= 0) | |
481 | idby = II_PHY_NAME; | |
482 | err = __handle_cmd(&nlstate, idby, argc, argv, &cmd); | |
483 | } | |
437 | 484 | |
438 | 485 | if (err == 1) { |
439 | 486 | if (cmd) |
0 | 0 | #ifndef __IW_H |
1 | 1 | #define __IW_H |
2 | 2 | |
3 | #include <stdbool.h> | |
3 | 4 | #include <netlink/netlink.h> |
4 | 5 | #include <netlink/genl/genl.h> |
5 | 6 | #include <netlink/genl/family.h> |
33 | 34 | }; |
34 | 35 | |
35 | 36 | struct cmd { |
36 | const char *section; | |
37 | 37 | const char *name; |
38 | 38 | const char *args; |
39 | 39 | const char *help; |
50 | 50 | struct nl_cb *cb, |
51 | 51 | struct nl_msg *msg, |
52 | 52 | int argc, char **argv); |
53 | const struct cmd *parent; | |
53 | 54 | }; |
54 | 55 | |
55 | 56 | #define ARRAY_SIZE(ar) (sizeof(ar)/sizeof(ar[0])) |
56 | 57 | |
57 | 58 | #define __COMMAND(_section, _symname, _name, _args, _nlcmd, _flags, _hidden, _idby, _handler, _help)\ |
58 | static const struct cmd \ | |
59 | static struct cmd \ | |
59 | 60 | __cmd ## _ ## _symname ## _ ## _handler ## _ ## _nlcmd ## _ ## _idby ## _ ## _hidden\ |
60 | 61 | __attribute__((used)) __attribute__((section("__cmd"))) = { \ |
61 | .section = (_section), \ | |
62 | 62 | .name = (_name), \ |
63 | 63 | .args = (_args), \ |
64 | 64 | .cmd = (_nlcmd), \ |
67 | 67 | .idby = (_idby), \ |
68 | 68 | .handler = (_handler), \ |
69 | 69 | .help = (_help), \ |
70 | .parent = _section, \ | |
70 | 71 | } |
71 | 72 | #define COMMAND(section, name, args, cmd, flags, idby, handler, help) \ |
72 | __COMMAND(#section, name, #name, args, cmd, flags, 0, idby, handler, help) | |
73 | __COMMAND(&(__section ## _ ## section), name, #name, args, cmd, flags, 0, idby, handler, help) | |
73 | 74 | #define HIDDEN(section, name, args, cmd, flags, idby, handler) \ |
74 | __COMMAND(#section, name, #name, args, cmd, flags, 1, idby, handler, NULL) | |
75 | #define TOPLEVEL(name, args, cmd, flags, idby, handler, help) \ | |
76 | __COMMAND(NULL, name, #name, args, cmd, flags, 0, idby, handler, help) | |
77 | extern struct cmd __start___cmd; | |
78 | extern struct cmd __stop___cmd; | |
75 | __COMMAND(&(__section ## _ ## section), name, #name, args, cmd, flags, 1, idby, handler, NULL) | |
76 | ||
77 | #define TOPLEVEL(_name, _args, _nlcmd, _flags, _idby, _handler, _help) \ | |
78 | struct cmd \ | |
79 | __section ## _ ## _name \ | |
80 | __attribute__((used)) __attribute__((section("__cmd"))) = { \ | |
81 | .name = (#_name), \ | |
82 | .args = (_args), \ | |
83 | .cmd = (_nlcmd), \ | |
84 | .nl_msg_flags = (_flags), \ | |
85 | .idby = (_idby), \ | |
86 | .handler = (_handler), \ | |
87 | .help = (_help), \ | |
88 | } | |
89 | #define SECTION(_name) \ | |
90 | struct cmd __section ## _ ## _name \ | |
91 | __attribute__((used)) __attribute__((section("__cmd"))) = { \ | |
92 | .name = (#_name), \ | |
93 | .hidden = 1, \ | |
94 | } | |
95 | ||
96 | #define DECLARE_SECTION(_name) \ | |
97 | extern struct cmd __section ## _ ## _name; | |
79 | 98 | |
80 | 99 | extern const char iw_version[]; |
81 | 100 | |
83 | 102 | |
84 | 103 | int handle_cmd(struct nl80211_state *state, enum id_input idby, |
85 | 104 | int argc, char **argv); |
105 | ||
106 | struct print_event_args { | |
107 | bool frame, time; | |
108 | }; | |
109 | ||
86 | 110 | __u32 listen_events(struct nl80211_state *state, |
87 | 111 | const int n_waits, const __u32 *waits); |
112 | __u32 __listen_events(struct nl80211_state *state, | |
113 | const int n_waits, const __u32 *waits, | |
114 | struct print_event_args *args); | |
88 | 115 | |
89 | 116 | |
90 | 117 | int mac_addr_a2n(unsigned char *mac_addr, char *arg); |
91 | int mac_addr_n2a(char *mac_addr, unsigned char *arg); | |
118 | void mac_addr_n2a(char *mac_addr, unsigned char *arg); | |
119 | ||
120 | int parse_keys(struct nl_msg *msg, char **argv, int argc); | |
121 | ||
122 | void print_ht_mcs(const __u8 *mcs); | |
123 | void print_ampdu_length(__u8 exponent); | |
124 | void print_ampdu_spacing(__u8 spacing); | |
125 | void print_ht_capability(__u16 cap); | |
92 | 126 | |
93 | 127 | const char *iftype_name(enum nl80211_iftype iftype); |
128 | const char *command_name(enum nl80211_commands cmd); | |
94 | 129 | int ieee80211_channel_to_frequency(int chan); |
95 | 130 | int ieee80211_frequency_to_channel(int freq); |
131 | ||
132 | void print_ssid_escaped(const uint8_t len, const uint8_t *data); | |
96 | 133 | |
97 | 134 | int nl_get_multicast_id(struct nl_sock *sock, const char *family, const char *group); |
98 | 135 | |
101 | 138 | const char *get_reason_str(uint16_t reason); |
102 | 139 | const char *get_status_str(uint16_t status); |
103 | 140 | |
141 | enum print_ie_type { | |
142 | PRINT_SCAN, | |
143 | PRINT_LINK, | |
144 | }; | |
145 | ||
146 | #define BIT(x) (1ULL<<(x)) | |
147 | ||
148 | void print_ies(unsigned char *ie, int ielen, bool unknown, | |
149 | enum print_ie_type ptype); | |
150 | ||
151 | ||
152 | DECLARE_SECTION(set); | |
153 | DECLARE_SECTION(get); | |
154 | ||
104 | 155 | #endif /* __IW_H */ |
0 | #include <net/if.h> | |
1 | #include <errno.h> | |
2 | #include <string.h> | |
3 | #include <ctype.h> | |
4 | #include <stdbool.h> | |
5 | ||
6 | #include <netlink/genl/genl.h> | |
7 | #include <netlink/genl/family.h> | |
8 | #include <netlink/genl/ctrl.h> | |
9 | #include <netlink/msg.h> | |
10 | #include <netlink/attr.h> | |
11 | ||
12 | #include "nl80211.h" | |
13 | #include "iw.h" | |
14 | ||
15 | struct link_result { | |
16 | uint8_t bssid[8]; | |
17 | bool link_found; | |
18 | bool anything_found; | |
19 | }; | |
20 | ||
21 | static struct link_result lr = { .link_found = false }; | |
22 | ||
23 | static int link_bss_handler(struct nl_msg *msg, void *arg) | |
24 | { | |
25 | struct nlattr *tb[NL80211_ATTR_MAX + 1]; | |
26 | struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); | |
27 | struct nlattr *bss[NL80211_BSS_MAX + 1]; | |
28 | static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = { | |
29 | [NL80211_BSS_TSF] = { .type = NLA_U64 }, | |
30 | [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 }, | |
31 | [NL80211_BSS_BSSID] = { }, | |
32 | [NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 }, | |
33 | [NL80211_BSS_CAPABILITY] = { .type = NLA_U16 }, | |
34 | [NL80211_BSS_INFORMATION_ELEMENTS] = { }, | |
35 | [NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 }, | |
36 | [NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 }, | |
37 | [NL80211_BSS_STATUS] = { .type = NLA_U32 }, | |
38 | }; | |
39 | struct link_result *result = arg; | |
40 | char mac_addr[20], dev[20]; | |
41 | ||
42 | nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), | |
43 | genlmsg_attrlen(gnlh, 0), NULL); | |
44 | ||
45 | if (!tb[NL80211_ATTR_BSS]) { | |
46 | fprintf(stderr, "bss info missing!\n"); | |
47 | return NL_SKIP; | |
48 | } | |
49 | if (nla_parse_nested(bss, NL80211_BSS_MAX, | |
50 | tb[NL80211_ATTR_BSS], | |
51 | bss_policy)) { | |
52 | fprintf(stderr, "failed to parse nested attributes!\n"); | |
53 | return NL_SKIP; | |
54 | } | |
55 | ||
56 | if (!bss[NL80211_BSS_BSSID]) | |
57 | return NL_SKIP; | |
58 | ||
59 | if (!bss[NL80211_BSS_STATUS]) | |
60 | return NL_SKIP; | |
61 | ||
62 | mac_addr_n2a(mac_addr, nla_data(bss[NL80211_BSS_BSSID])); | |
63 | if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), dev); | |
64 | ||
65 | switch (nla_get_u32(bss[NL80211_BSS_STATUS])) { | |
66 | case NL80211_BSS_STATUS_ASSOCIATED: | |
67 | printf("Connected to %s (on %s)\n", mac_addr, dev); | |
68 | break; | |
69 | case NL80211_BSS_STATUS_AUTHENTICATED: | |
70 | printf("Authenticated with %s (on %s)\n", mac_addr, dev); | |
71 | return NL_SKIP; | |
72 | default: | |
73 | return NL_SKIP; | |
74 | } | |
75 | ||
76 | result->anything_found = true; | |
77 | ||
78 | if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) | |
79 | print_ies(nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]), | |
80 | nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]), | |
81 | false, PRINT_LINK); | |
82 | ||
83 | if (bss[NL80211_BSS_FREQUENCY]) | |
84 | printf("\tfreq: %d\n", | |
85 | nla_get_u32(bss[NL80211_BSS_FREQUENCY])); | |
86 | ||
87 | if (nla_get_u32(bss[NL80211_BSS_STATUS]) != NL80211_BSS_STATUS_ASSOCIATED) | |
88 | return NL_SKIP; | |
89 | ||
90 | /* only in the assoc case do we want more info from station get */ | |
91 | result->link_found = true; | |
92 | memcpy(result->bssid, nla_data(bss[NL80211_BSS_BSSID]), 6); | |
93 | return NL_SKIP; | |
94 | } | |
95 | ||
96 | static int handle_scan_for_link(struct nl80211_state *state, | |
97 | struct nl_cb *cb, | |
98 | struct nl_msg *msg, | |
99 | int argc, char **argv) | |
100 | { | |
101 | if (argc > 0) | |
102 | return 1; | |
103 | ||
104 | nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, link_bss_handler, &lr); | |
105 | return 0; | |
106 | } | |
107 | ||
108 | static int print_link_sta(struct nl_msg *msg, void *arg) | |
109 | { | |
110 | struct nlattr *tb[NL80211_ATTR_MAX + 1]; | |
111 | struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); | |
112 | struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1]; | |
113 | struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1]; | |
114 | static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = { | |
115 | [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 }, | |
116 | [NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 }, | |
117 | [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 }, | |
118 | [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 }, | |
119 | [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 }, | |
120 | [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 }, | |
121 | [NL80211_STA_INFO_TX_BITRATE] = { .type = NLA_NESTED }, | |
122 | [NL80211_STA_INFO_LLID] = { .type = NLA_U16 }, | |
123 | [NL80211_STA_INFO_PLID] = { .type = NLA_U16 }, | |
124 | [NL80211_STA_INFO_PLINK_STATE] = { .type = NLA_U8 }, | |
125 | }; | |
126 | ||
127 | static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = { | |
128 | [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 }, | |
129 | [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 }, | |
130 | [NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG }, | |
131 | [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG }, | |
132 | }; | |
133 | ||
134 | nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), | |
135 | genlmsg_attrlen(gnlh, 0), NULL); | |
136 | ||
137 | if (!tb[NL80211_ATTR_STA_INFO]) { | |
138 | fprintf(stderr, "sta stats missing!\n"); | |
139 | return NL_SKIP; | |
140 | } | |
141 | if (nla_parse_nested(sinfo, NL80211_STA_INFO_MAX, | |
142 | tb[NL80211_ATTR_STA_INFO], | |
143 | stats_policy)) { | |
144 | fprintf(stderr, "failed to parse nested attributes!\n"); | |
145 | return NL_SKIP; | |
146 | } | |
147 | ||
148 | if (sinfo[NL80211_STA_INFO_RX_BYTES] && sinfo[NL80211_STA_INFO_RX_PACKETS]) | |
149 | printf("\tRX: %u bytes (%u packets)\n", | |
150 | nla_get_u32(sinfo[NL80211_STA_INFO_RX_BYTES]), | |
151 | nla_get_u32(sinfo[NL80211_STA_INFO_RX_PACKETS])); | |
152 | if (sinfo[NL80211_STA_INFO_TX_BYTES] && sinfo[NL80211_STA_INFO_TX_PACKETS]) | |
153 | printf("\tTX: %u bytes (%u packets)\n", | |
154 | nla_get_u32(sinfo[NL80211_STA_INFO_TX_BYTES]), | |
155 | nla_get_u32(sinfo[NL80211_STA_INFO_TX_PACKETS])); | |
156 | if (sinfo[NL80211_STA_INFO_SIGNAL]) | |
157 | printf("\tsignal: %d dBm\n", | |
158 | (int8_t)nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL])); | |
159 | ||
160 | if (sinfo[NL80211_STA_INFO_TX_BITRATE]) { | |
161 | if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX, | |
162 | sinfo[NL80211_STA_INFO_TX_BITRATE], rate_policy)) { | |
163 | fprintf(stderr, "failed to parse nested rate attributes!\n"); | |
164 | } else { | |
165 | printf("\ttx bitrate: "); | |
166 | if (rinfo[NL80211_RATE_INFO_BITRATE]) { | |
167 | int rate = nla_get_u16(rinfo[NL80211_RATE_INFO_BITRATE]); | |
168 | printf("%d.%d MBit/s", rate / 10, rate % 10); | |
169 | } | |
170 | ||
171 | if (rinfo[NL80211_RATE_INFO_MCS]) | |
172 | printf(" MCS %d", nla_get_u8(rinfo[NL80211_RATE_INFO_MCS])); | |
173 | if (rinfo[NL80211_RATE_INFO_40_MHZ_WIDTH]) | |
174 | printf(" 40Mhz"); | |
175 | if (rinfo[NL80211_RATE_INFO_SHORT_GI]) | |
176 | printf(" short GI"); | |
177 | printf("\n"); | |
178 | } | |
179 | } | |
180 | ||
181 | return NL_SKIP; | |
182 | } | |
183 | ||
184 | static int handle_link_sta(struct nl80211_state *state, | |
185 | struct nl_cb *cb, | |
186 | struct nl_msg *msg, | |
187 | int argc, char **argv) | |
188 | { | |
189 | unsigned char mac_addr[ETH_ALEN]; | |
190 | ||
191 | if (argc < 1) | |
192 | return 1; | |
193 | ||
194 | if (mac_addr_a2n(mac_addr, argv[0])) { | |
195 | fprintf(stderr, "invalid mac address\n"); | |
196 | return 2; | |
197 | } | |
198 | ||
199 | argc--; | |
200 | argv++; | |
201 | ||
202 | if (argc) | |
203 | return 1; | |
204 | ||
205 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); | |
206 | ||
207 | nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_link_sta, NULL); | |
208 | ||
209 | return 0; | |
210 | nla_put_failure: | |
211 | return -ENOBUFS; | |
212 | } | |
213 | ||
214 | static int handle_link(struct nl80211_state *state, struct nl_cb *cb, | |
215 | struct nl_msg *msg, int argc, char **argv) | |
216 | { | |
217 | char *link_argv[] = { | |
218 | NULL, | |
219 | "link", | |
220 | "get_bss", | |
221 | NULL, | |
222 | }; | |
223 | char *station_argv[] = { | |
224 | NULL, | |
225 | "link", | |
226 | "get_sta", | |
227 | NULL, | |
228 | NULL, | |
229 | }; | |
230 | char bssid_buf[3*6]; | |
231 | int err; | |
232 | ||
233 | link_argv[0] = argv[0]; | |
234 | err = handle_cmd(state, II_NETDEV, 3, link_argv); | |
235 | if (err) | |
236 | return err; | |
237 | ||
238 | if (!lr.link_found) { | |
239 | if (!lr.anything_found) | |
240 | printf("Not connected.\n"); | |
241 | return 0; | |
242 | } | |
243 | ||
244 | mac_addr_n2a(bssid_buf, lr.bssid); | |
245 | bssid_buf[17] = '\0'; | |
246 | ||
247 | station_argv[0] = argv[0]; | |
248 | station_argv[3] = bssid_buf; | |
249 | return handle_cmd(state, II_NETDEV, 4, station_argv); | |
250 | } | |
251 | TOPLEVEL(link, NULL, 0, 0, CIB_NETDEV, handle_link, | |
252 | "Print information about the current link, if any."); | |
253 | HIDDEN(link, get_sta, "", NL80211_CMD_GET_STATION, 0, | |
254 | CIB_NETDEV, handle_link_sta); | |
255 | HIDDEN(link, get_bss, NULL, NL80211_CMD_GET_SCAN, NLM_F_DUMP, | |
256 | CIB_NETDEV, handle_scan_for_link); |
164 | 164 | {"mesh_hwmp_net_diameter_traversal_time", |
165 | 165 | NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, |
166 | 166 | _my_nla_put_u16, _parse_u16, _print_u16_in_TUs}, |
167 | {"mesh_hwmp_rootmode", NL80211_MESHCONF_HWMP_ROOTMODE, | |
168 | _my_nla_put_u8, _parse_u8, _print_u8}, | |
167 | 169 | }; |
168 | 170 | |
169 | 171 | static void print_all_mesh_param_descr(void) |
9 | 9 | |
10 | 10 | #include "nl80211.h" |
11 | 11 | #include "iw.h" |
12 | ||
13 | SECTION(mpath); | |
12 | 14 | |
13 | 15 | enum plink_state { |
14 | 16 | LISTEN, |
35 | 37 | char dst[20], next_hop[20], dev[20]; |
36 | 38 | static struct nla_policy mpath_policy[NL80211_MPATH_INFO_MAX + 1] = { |
37 | 39 | [NL80211_MPATH_INFO_FRAME_QLEN] = { .type = NLA_U32 }, |
38 | [NL80211_MPATH_INFO_DSN] = { .type = NLA_U32 }, | |
40 | [NL80211_MPATH_INFO_SN] = { .type = NLA_U32 }, | |
39 | 41 | [NL80211_MPATH_INFO_METRIC] = { .type = NLA_U32 }, |
40 | 42 | [NL80211_MPATH_INFO_EXPTIME] = { .type = NLA_U32 }, |
41 | 43 | [NL80211_MPATH_INFO_DISCOVERY_TIMEOUT] = { .type = NLA_U32 }, |
53 | 55 | */ |
54 | 56 | |
55 | 57 | if (!tb[NL80211_ATTR_MPATH_INFO]) { |
56 | fprintf(stderr, "mpath info missing!"); | |
58 | fprintf(stderr, "mpath info missing!\n"); | |
57 | 59 | return NL_SKIP; |
58 | 60 | } |
59 | 61 | if (nla_parse_nested(pinfo, NL80211_MPATH_INFO_MAX, |
60 | 62 | tb[NL80211_ATTR_MPATH_INFO], |
61 | 63 | mpath_policy)) { |
62 | fprintf(stderr, "failed to parse nested attributes!"); | |
64 | fprintf(stderr, "failed to parse nested attributes!\n"); | |
63 | 65 | return NL_SKIP; |
64 | 66 | } |
65 | 67 | |
67 | 69 | mac_addr_n2a(next_hop, nla_data(tb[NL80211_ATTR_MPATH_NEXT_HOP])); |
68 | 70 | if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), dev); |
69 | 71 | printf("%s %s %s", dst, next_hop, dev); |
70 | if (pinfo[NL80211_MPATH_INFO_DSN]) | |
72 | if (pinfo[NL80211_MPATH_INFO_SN]) | |
71 | 73 | printf("\t%u", |
72 | nla_get_u32(pinfo[NL80211_MPATH_INFO_DSN])); | |
74 | nla_get_u32(pinfo[NL80211_MPATH_INFO_SN])); | |
73 | 75 | if (pinfo[NL80211_MPATH_INFO_METRIC]) |
74 | 76 | printf("\t%u", |
75 | 77 | nla_get_u32(pinfo[NL80211_MPATH_INFO_METRIC])); |
181 | 183 | struct nl_msg *msg, |
182 | 184 | int argc, char **argv) |
183 | 185 | { |
186 | printf("DEST ADDR NEXT HOP IFACE\tSN\tMETRIC\tQLEN\t" | |
187 | "EXPTIME\t\tDTIM\tDRET\tFLAGS\n"); | |
184 | 188 | nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_mpath_handler, NULL); |
185 | 189 | return 0; |
186 | 190 | } |
23 | 23 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
24 | 24 | * |
25 | 25 | */ |
26 | ||
27 | #include <linux/types.h> | |
26 | 28 | |
27 | 29 | /** |
28 | 30 | * DOC: Station handling |
76 | 78 | * @NL80211_CMD_SET_KEY: Set key attributes %NL80211_ATTR_KEY_DEFAULT, |
77 | 79 | * %NL80211_ATTR_KEY_DEFAULT_MGMT, or %NL80211_ATTR_KEY_THRESHOLD. |
78 | 80 | * @NL80211_CMD_NEW_KEY: add a key with given %NL80211_ATTR_KEY_DATA, |
79 | * %NL80211_ATTR_KEY_IDX, %NL80211_ATTR_MAC and %NL80211_ATTR_KEY_CIPHER | |
80 | * attributes. | |
81 | * %NL80211_ATTR_KEY_IDX, %NL80211_ATTR_MAC, %NL80211_ATTR_KEY_CIPHER, | |
82 | * and %NL80211_ATTR_KEY_SEQ attributes. | |
81 | 83 | * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX |
82 | 84 | * or %NL80211_ATTR_MAC. |
83 | 85 | * |
156 | 158 | * NL80211_CMD_GET_SCAN and on the "scan" multicast group) |
157 | 159 | * @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons, |
158 | 160 | * partial scan results may be available |
161 | * | |
162 | * @NL80211_CMD_GET_SURVEY: get survey resuls, e.g. channel occupation | |
163 | * or noise level | |
164 | * @NL80211_CMD_NEW_SURVEY_RESULTS: survey data notification (as a reply to | |
165 | * NL80211_CMD_GET_SURVEY and on the "scan" multicast group) | |
159 | 166 | * |
160 | 167 | * @NL80211_CMD_REG_CHANGE: indicates to userspace the regulatory domain |
161 | 168 | * has been changed and provides details of the request information |
202 | 209 | * frame, i.e., it was for the local STA and was received in correct |
203 | 210 | * state. This is similar to MLME-AUTHENTICATE.confirm primitive in the |
204 | 211 | * MLME SAP interface (kernel providing MLME, userspace SME). The |
205 | * included NL80211_ATTR_FRAME attribute contains the management frame | |
206 | * (including both the header and frame body, but not FCS). | |
212 | * included %NL80211_ATTR_FRAME attribute contains the management frame | |
213 | * (including both the header and frame body, but not FCS). This event is | |
214 | * also used to indicate if the authentication attempt timed out. In that | |
215 | * case the %NL80211_ATTR_FRAME attribute is replaced with a | |
216 | * %NL80211_ATTR_TIMED_OUT flag (and %NL80211_ATTR_MAC to indicate which | |
217 | * pending authentication timed out). | |
207 | 218 | * @NL80211_CMD_ASSOCIATE: association request and notification; like |
208 | 219 | * NL80211_CMD_AUTHENTICATE but for Association and Reassociation |
209 | 220 | * (similar to MLME-ASSOCIATE.request, MLME-REASSOCIATE.request, |
229 | 240 | * and optionally a MAC (as BSSID) and FREQ_FIXED attribute if those |
230 | 241 | * should be fixed rather than automatically determined. Can only be |
231 | 242 | * executed on a network interface that is UP, and fixed BSSID/FREQ |
232 | * may be rejected. | |
243 | * may be rejected. Another optional parameter is the beacon interval, | |
244 | * given in the %NL80211_ATTR_BEACON_INTERVAL attribute, which if not | |
245 | * given defaults to 100 TU (102.4ms). | |
233 | 246 | * @NL80211_CMD_LEAVE_IBSS: Leave the IBSS -- no special arguments, the IBSS is |
234 | 247 | * determined by the network interface. |
248 | * | |
249 | * @NL80211_CMD_TESTMODE: testmode command, takes a wiphy (or ifindex) attribute | |
250 | * to identify the device, and the TESTDATA blob attribute to pass through | |
251 | * to the driver. | |
252 | * | |
253 | * @NL80211_CMD_CONNECT: connection request and notification; this command | |
254 | * requests to connect to a specified network but without separating | |
255 | * auth and assoc steps. For this, you need to specify the SSID in a | |
256 | * %NL80211_ATTR_SSID attribute, and can optionally specify the association | |
257 | * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_MAC, | |
258 | * %NL80211_ATTR_WIPHY_FREQ and %NL80211_ATTR_CONTROL_PORT. | |
259 | * It is also sent as an event, with the BSSID and response IEs when the | |
260 | * connection is established or failed to be established. This can be | |
261 | * determined by the STATUS_CODE attribute. | |
262 | * @NL80211_CMD_ROAM: request that the card roam (currently not implemented), | |
263 | * sent as an event when the card/driver roamed by itself. | |
264 | * @NL80211_CMD_DISCONNECT: drop a given connection; also used to notify | |
265 | * userspace that a connection was dropped by the AP or due to other | |
266 | * reasons, for this the %NL80211_ATTR_DISCONNECTED_BY_AP and | |
267 | * %NL80211_ATTR_REASON_CODE attributes are used. | |
268 | * | |
269 | * @NL80211_CMD_SET_WIPHY_NETNS: Set a wiphy's netns. Note that all devices | |
270 | * associated with this wiphy must be down and will follow. | |
235 | 271 | * |
236 | 272 | * @NL80211_CMD_MAX: highest used command number |
237 | 273 | * @__NL80211_CMD_AFTER_LAST: internal use |
300 | 336 | |
301 | 337 | NL80211_CMD_JOIN_IBSS, |
302 | 338 | NL80211_CMD_LEAVE_IBSS, |
339 | ||
340 | NL80211_CMD_TESTMODE, | |
341 | ||
342 | NL80211_CMD_CONNECT, | |
343 | NL80211_CMD_ROAM, | |
344 | NL80211_CMD_DISCONNECT, | |
345 | ||
346 | NL80211_CMD_SET_WIPHY_NETNS, | |
347 | ||
348 | NL80211_CMD_GET_SURVEY, | |
349 | NL80211_CMD_NEW_SURVEY_RESULTS, | |
303 | 350 | |
304 | 351 | /* add new commands above here */ |
305 | 352 | |
373 | 420 | * |
374 | 421 | * @NL80211_ATTR_STA_AID: Association ID for the station (u16) |
375 | 422 | * @NL80211_ATTR_STA_FLAGS: flags, nested element with NLA_FLAG attributes of |
376 | * &enum nl80211_sta_flags. | |
423 | * &enum nl80211_sta_flags (deprecated, use %NL80211_ATTR_STA_FLAGS2) | |
377 | 424 | * @NL80211_ATTR_STA_LISTEN_INTERVAL: listen interval as defined by |
378 | 425 | * IEEE 802.11 7.3.1.6 (u16). |
379 | 426 | * @NL80211_ATTR_STA_SUPPORTED_RATES: supported rates, array of supported |
440 | 487 | * @NL80211_ATTR_SCAN_FREQUENCIES: nested attribute with frequencies (in MHz) |
441 | 488 | * @NL80211_ATTR_SCAN_SSIDS: nested attribute with SSIDs, leave out for passive |
442 | 489 | * scanning and include a zero-length SSID (wildcard) for wildcard scan |
443 | * @NL80211_ATTR_SCAN_GENERATION: the scan generation increases whenever the | |
444 | * scan result list changes (BSS expired or added) so that applications | |
445 | * can verify that they got a single, consistent snapshot (when all dump | |
446 | * messages carried the same generation number) | |
447 | 490 | * @NL80211_ATTR_BSS: scan result BSS |
448 | 491 | * |
449 | 492 | * @NL80211_ATTR_REG_INITIATOR: indicates who requested the regulatory domain |
484 | 527 | * @NL80211_ATTR_FREQ_FIXED: a flag indicating the IBSS should not try to look |
485 | 528 | * for other networks on different channels |
486 | 529 | * |
530 | * @NL80211_ATTR_TIMED_OUT: a flag indicating than an operation timed out; this | |
531 | * is used, e.g., with %NL80211_CMD_AUTHENTICATE event | |
532 | * | |
533 | * @NL80211_ATTR_USE_MFP: Whether management frame protection (IEEE 802.11w) is | |
534 | * used for the association (&enum nl80211_mfp, represented as a u32); | |
535 | * this attribute can be used | |
536 | * with %NL80211_CMD_ASSOCIATE request | |
537 | * | |
538 | * @NL80211_ATTR_STA_FLAGS2: Attribute containing a | |
539 | * &struct nl80211_sta_flag_update. | |
540 | * | |
541 | * @NL80211_ATTR_CONTROL_PORT: A flag indicating whether user space controls | |
542 | * IEEE 802.1X port, i.e., sets/clears %NL80211_STA_FLAG_AUTHORIZED, in | |
543 | * station mode. If the flag is included in %NL80211_CMD_ASSOCIATE | |
544 | * request, the driver will assume that the port is unauthorized until | |
545 | * authorized by user space. Otherwise, port is marked authorized by | |
546 | * default in station mode. | |
547 | * | |
548 | * @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver. | |
549 | * We recommend using nested, driver-specific attributes within this. | |
550 | * | |
551 | * @NL80211_ATTR_DISCONNECTED_BY_AP: A flag indicating that the DISCONNECT | |
552 | * event was due to the AP disconnecting the station, and not due to | |
553 | * a local disconnect request. | |
554 | * @NL80211_ATTR_STATUS_CODE: StatusCode for the %NL80211_CMD_CONNECT | |
555 | * event (u16) | |
556 | * @NL80211_ATTR_PRIVACY: Flag attribute, used with connect(), indicating | |
557 | * that protected APs should be used. | |
558 | * | |
559 | * @NL80211_ATTR_CIPHERS_PAIRWISE: Used with CONNECT and ASSOCIATE to | |
560 | * indicate which unicast key ciphers will be used with the connection | |
561 | * (an array of u32). | |
562 | * @NL80211_ATTR_CIPHER_GROUP: Used with CONNECT and ASSOCIATE to indicate | |
563 | * which group key cipher will be used with the connection (a u32). | |
564 | * @NL80211_ATTR_WPA_VERSIONS: Used with CONNECT and ASSOCIATE to indicate | |
565 | * which WPA version(s) the AP we want to associate with is using | |
566 | * (a u32 with flags from &enum nl80211_wpa_versions). | |
567 | * @NL80211_ATTR_AKM_SUITES: Used with CONNECT and ASSOCIATE to indicate | |
568 | * which key management algorithm(s) to use (an array of u32). | |
569 | * | |
570 | * @NL80211_ATTR_REQ_IE: (Re)association request information elements as | |
571 | * sent out by the card, for ROAM and successful CONNECT events. | |
572 | * @NL80211_ATTR_RESP_IE: (Re)association response information elements as | |
573 | * sent by peer, for ROAM and successful CONNECT events. | |
574 | * | |
575 | * @NL80211_ATTR_PREV_BSSID: previous BSSID, to be used by in ASSOCIATE | |
576 | * commands to specify using a reassociate frame | |
577 | * | |
578 | * @NL80211_ATTR_KEY: key information in a nested attribute with | |
579 | * %NL80211_KEY_* sub-attributes | |
580 | * @NL80211_ATTR_KEYS: array of keys for static WEP keys for connect() | |
581 | * and join_ibss(), key information is in a nested attribute each | |
582 | * with %NL80211_KEY_* sub-attributes | |
583 | * | |
584 | * @NL80211_ATTR_PID: Process ID of a network namespace. | |
585 | * | |
586 | * @NL80211_ATTR_GENERATION: Used to indicate consistent snapshots for | |
587 | * dumps. This number increases whenever the object list being | |
588 | * dumped changes, and as such userspace can verify that it has | |
589 | * obtained a complete and consistent snapshot by verifying that | |
590 | * all dump messages contain the same generation number. If it | |
591 | * changed then the list changed and the dump should be repeated | |
592 | * completely from scratch. | |
593 | * | |
594 | * @NL80211_ATTR_4ADDR: Use 4-address frames on a virtual interface | |
595 | * | |
596 | * @NL80211_ATTR_SURVEY_INFO: survey information about a channel, part of | |
597 | * the survey response for %NL80211_CMD_GET_SURVEY, nested attribute | |
598 | * containing info as possible, see &enum survey_info. | |
599 | * | |
487 | 600 | * @NL80211_ATTR_MAX: highest attribute number currently defined |
488 | 601 | * @__NL80211_ATTR_AFTER_LAST: internal use |
489 | 602 | */ |
555 | 668 | |
556 | 669 | NL80211_ATTR_SCAN_FREQUENCIES, |
557 | 670 | NL80211_ATTR_SCAN_SSIDS, |
558 | NL80211_ATTR_SCAN_GENERATION, | |
671 | NL80211_ATTR_GENERATION, /* replaces old SCAN_GENERATION */ | |
559 | 672 | NL80211_ATTR_BSS, |
560 | 673 | |
561 | 674 | NL80211_ATTR_REG_INITIATOR, |
584 | 697 | NL80211_ATTR_WIPHY_FRAG_THRESHOLD, |
585 | 698 | NL80211_ATTR_WIPHY_RTS_THRESHOLD, |
586 | 699 | |
700 | NL80211_ATTR_TIMED_OUT, | |
701 | ||
702 | NL80211_ATTR_USE_MFP, | |
703 | ||
704 | NL80211_ATTR_STA_FLAGS2, | |
705 | ||
706 | NL80211_ATTR_CONTROL_PORT, | |
707 | ||
708 | NL80211_ATTR_TESTDATA, | |
709 | ||
710 | NL80211_ATTR_PRIVACY, | |
711 | ||
712 | NL80211_ATTR_DISCONNECTED_BY_AP, | |
713 | NL80211_ATTR_STATUS_CODE, | |
714 | ||
715 | NL80211_ATTR_CIPHER_SUITES_PAIRWISE, | |
716 | NL80211_ATTR_CIPHER_SUITE_GROUP, | |
717 | NL80211_ATTR_WPA_VERSIONS, | |
718 | NL80211_ATTR_AKM_SUITES, | |
719 | ||
720 | NL80211_ATTR_REQ_IE, | |
721 | NL80211_ATTR_RESP_IE, | |
722 | ||
723 | NL80211_ATTR_PREV_BSSID, | |
724 | ||
725 | NL80211_ATTR_KEY, | |
726 | NL80211_ATTR_KEYS, | |
727 | ||
728 | NL80211_ATTR_PID, | |
729 | ||
730 | NL80211_ATTR_4ADDR, | |
731 | ||
732 | NL80211_ATTR_SURVEY_INFO, | |
733 | ||
587 | 734 | /* add attributes here, update the policy in nl80211.c */ |
588 | 735 | |
589 | 736 | __NL80211_ATTR_AFTER_LAST, |
590 | 737 | NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1 |
591 | 738 | }; |
739 | ||
740 | /* source-level API compatibility */ | |
741 | #define NL80211_ATTR_SCAN_GENERATION NL80211_ATTR_GENERATION | |
592 | 742 | |
593 | 743 | /* |
594 | 744 | * Allow user space programs to use #ifdef on new attributes by defining them |
595 | 745 | * here |
596 | 746 | */ |
747 | #define NL80211_CMD_CONNECT NL80211_CMD_CONNECT | |
597 | 748 | #define NL80211_ATTR_HT_CAPABILITY NL80211_ATTR_HT_CAPABILITY |
598 | 749 | #define NL80211_ATTR_BSS_BASIC_RATES NL80211_ATTR_BSS_BASIC_RATES |
599 | 750 | #define NL80211_ATTR_WIPHY_TXQ_PARAMS NL80211_ATTR_WIPHY_TXQ_PARAMS |
607 | 758 | #define NL80211_ATTR_SSID NL80211_ATTR_SSID |
608 | 759 | #define NL80211_ATTR_AUTH_TYPE NL80211_ATTR_AUTH_TYPE |
609 | 760 | #define NL80211_ATTR_REASON_CODE NL80211_ATTR_REASON_CODE |
761 | #define NL80211_ATTR_CIPHER_SUITES_PAIRWISE NL80211_ATTR_CIPHER_SUITES_PAIRWISE | |
762 | #define NL80211_ATTR_CIPHER_SUITE_GROUP NL80211_ATTR_CIPHER_SUITE_GROUP | |
763 | #define NL80211_ATTR_WPA_VERSIONS NL80211_ATTR_WPA_VERSIONS | |
764 | #define NL80211_ATTR_AKM_SUITES NL80211_ATTR_AKM_SUITES | |
765 | #define NL80211_ATTR_KEY NL80211_ATTR_KEY | |
766 | #define NL80211_ATTR_KEYS NL80211_ATTR_KEYS | |
610 | 767 | |
611 | 768 | #define NL80211_MAX_SUPP_RATES 32 |
612 | 769 | #define NL80211_MAX_SUPP_REG_RULES 32 |
614 | 771 | #define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY 16 |
615 | 772 | #define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24 |
616 | 773 | #define NL80211_HT_CAPABILITY_LEN 26 |
774 | ||
775 | #define NL80211_MAX_NR_CIPHER_SUITES 5 | |
776 | #define NL80211_MAX_NR_AKM_SUITES 2 | |
617 | 777 | |
618 | 778 | /** |
619 | 779 | * enum nl80211_iftype - (virtual) interface types |
671 | 831 | __NL80211_STA_FLAG_AFTER_LAST, |
672 | 832 | NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1 |
673 | 833 | }; |
834 | ||
835 | /** | |
836 | * struct nl80211_sta_flag_update - station flags mask/set | |
837 | * @mask: mask of station flags to set | |
838 | * @set: which values to set them to | |
839 | * | |
840 | * Both mask and set contain bits as per &enum nl80211_sta_flags. | |
841 | */ | |
842 | struct nl80211_sta_flag_update { | |
843 | __u32 mask; | |
844 | __u32 set; | |
845 | } __attribute__((packed)); | |
674 | 846 | |
675 | 847 | /** |
676 | 848 | * enum nl80211_rate_info - bitrate information |
740 | 912 | * |
741 | 913 | * @NL80211_MPATH_FLAG_ACTIVE: the mesh path is active |
742 | 914 | * @NL80211_MPATH_FLAG_RESOLVING: the mesh path discovery process is running |
743 | * @NL80211_MPATH_FLAG_DSN_VALID: the mesh path contains a valid DSN | |
915 | * @NL80211_MPATH_FLAG_SN_VALID: the mesh path contains a valid SN | |
744 | 916 | * @NL80211_MPATH_FLAG_FIXED: the mesh path has been manually set |
745 | 917 | * @NL80211_MPATH_FLAG_RESOLVED: the mesh path discovery process succeeded |
746 | 918 | */ |
747 | 919 | enum nl80211_mpath_flags { |
748 | 920 | NL80211_MPATH_FLAG_ACTIVE = 1<<0, |
749 | 921 | NL80211_MPATH_FLAG_RESOLVING = 1<<1, |
750 | NL80211_MPATH_FLAG_DSN_VALID = 1<<2, | |
922 | NL80211_MPATH_FLAG_SN_VALID = 1<<2, | |
751 | 923 | NL80211_MPATH_FLAG_FIXED = 1<<3, |
752 | 924 | NL80211_MPATH_FLAG_RESOLVED = 1<<4, |
753 | 925 | }; |
760 | 932 | * |
761 | 933 | * @__NL80211_MPATH_INFO_INVALID: attribute number 0 is reserved |
762 | 934 | * @NL80211_ATTR_MPATH_FRAME_QLEN: number of queued frames for this destination |
763 | * @NL80211_ATTR_MPATH_DSN: destination sequence number | |
935 | * @NL80211_ATTR_MPATH_SN: destination sequence number | |
764 | 936 | * @NL80211_ATTR_MPATH_METRIC: metric (cost) of this mesh path |
765 | 937 | * @NL80211_ATTR_MPATH_EXPTIME: expiration time for the path, in msec from now |
766 | 938 | * @NL80211_ATTR_MPATH_FLAGS: mesh path flags, enumerated in |
771 | 943 | enum nl80211_mpath_info { |
772 | 944 | __NL80211_MPATH_INFO_INVALID, |
773 | 945 | NL80211_MPATH_INFO_FRAME_QLEN, |
774 | NL80211_MPATH_INFO_DSN, | |
946 | NL80211_MPATH_INFO_SN, | |
775 | 947 | NL80211_MPATH_INFO_METRIC, |
776 | 948 | NL80211_MPATH_INFO_EXPTIME, |
777 | 949 | NL80211_MPATH_INFO_FLAGS, |
962 | 1134 | }; |
963 | 1135 | |
964 | 1136 | /** |
1137 | * enum nl80211_survey_info - survey information | |
1138 | * | |
1139 | * These attribute types are used with %NL80211_ATTR_SURVEY_INFO | |
1140 | * when getting information about a survey. | |
1141 | * | |
1142 | * @__NL80211_SURVEY_INFO_INVALID: attribute number 0 is reserved | |
1143 | * @NL80211_SURVEY_INFO_FREQUENCY: center frequency of channel | |
1144 | * @NL80211_SURVEY_INFO_NOISE: noise level of channel (u8, dBm) | |
1145 | */ | |
1146 | enum nl80211_survey_info { | |
1147 | __NL80211_SURVEY_INFO_INVALID, | |
1148 | NL80211_SURVEY_INFO_FREQUENCY, | |
1149 | NL80211_SURVEY_INFO_NOISE, | |
1150 | ||
1151 | /* keep last */ | |
1152 | __NL80211_SURVEY_INFO_AFTER_LAST, | |
1153 | NL80211_SURVEY_INFO_MAX = __NL80211_SURVEY_INFO_AFTER_LAST - 1 | |
1154 | }; | |
1155 | ||
1156 | /** | |
965 | 1157 | * enum nl80211_mntr_flags - monitor configuration flags |
966 | 1158 | * |
967 | 1159 | * Monitor configuration flags. |
1040 | 1232 | * |
1041 | 1233 | * @NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME: The interval of time (in TUs) |
1042 | 1234 | * that it takes for an HWMP information element to propagate across the mesh |
1235 | * | |
1236 | * @NL80211_MESHCONF_ROOTMODE: whether root mode is enabled or not | |
1043 | 1237 | * |
1044 | 1238 | * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute |
1045 | 1239 | * |
1060 | 1254 | NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, |
1061 | 1255 | NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, |
1062 | 1256 | NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, |
1257 | NL80211_MESHCONF_HWMP_ROOTMODE, | |
1063 | 1258 | |
1064 | 1259 | /* keep last */ |
1065 | 1260 | __NL80211_MESHCONF_ATTR_AFTER_LAST, |
1121 | 1316 | * in mBm (100 * dBm) (s32) |
1122 | 1317 | * @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon |
1123 | 1318 | * in unspecified units, scaled to 0..100 (u8) |
1319 | * @NL80211_BSS_STATUS: status, if this BSS is "used" | |
1320 | * @NL80211_BSS_SEEN_MS_AGO: age of this BSS entry in ms | |
1124 | 1321 | * @__NL80211_BSS_AFTER_LAST: internal |
1125 | 1322 | * @NL80211_BSS_MAX: highest BSS attribute |
1126 | 1323 | */ |
1134 | 1331 | NL80211_BSS_INFORMATION_ELEMENTS, |
1135 | 1332 | NL80211_BSS_SIGNAL_MBM, |
1136 | 1333 | NL80211_BSS_SIGNAL_UNSPEC, |
1334 | NL80211_BSS_STATUS, | |
1335 | NL80211_BSS_SEEN_MS_AGO, | |
1137 | 1336 | |
1138 | 1337 | /* keep last */ |
1139 | 1338 | __NL80211_BSS_AFTER_LAST, |
1140 | 1339 | NL80211_BSS_MAX = __NL80211_BSS_AFTER_LAST - 1 |
1340 | }; | |
1341 | ||
1342 | /** | |
1343 | * enum nl80211_bss_status - BSS "status" | |
1344 | */ | |
1345 | enum nl80211_bss_status { | |
1346 | NL80211_BSS_STATUS_AUTHENTICATED, | |
1347 | NL80211_BSS_STATUS_ASSOCIATED, | |
1348 | NL80211_BSS_STATUS_IBSS_JOINED, | |
1141 | 1349 | }; |
1142 | 1350 | |
1143 | 1351 | /** |
1147 | 1355 | * @NL80211_AUTHTYPE_SHARED_KEY: Shared Key authentication (WEP only) |
1148 | 1356 | * @NL80211_AUTHTYPE_FT: Fast BSS Transition (IEEE 802.11r) |
1149 | 1357 | * @NL80211_AUTHTYPE_NETWORK_EAP: Network EAP (some Cisco APs and mainly LEAP) |
1358 | * @__NL80211_AUTHTYPE_NUM: internal | |
1359 | * @NL80211_AUTHTYPE_MAX: maximum valid auth algorithm | |
1360 | * @NL80211_AUTHTYPE_AUTOMATIC: determine automatically (if necessary by | |
1361 | * trying multiple times); this is invalid in netlink -- leave out | |
1362 | * the attribute for this on CONNECT commands. | |
1150 | 1363 | */ |
1151 | 1364 | enum nl80211_auth_type { |
1152 | 1365 | NL80211_AUTHTYPE_OPEN_SYSTEM, |
1153 | 1366 | NL80211_AUTHTYPE_SHARED_KEY, |
1154 | 1367 | NL80211_AUTHTYPE_FT, |
1155 | 1368 | NL80211_AUTHTYPE_NETWORK_EAP, |
1369 | ||
1370 | /* keep last */ | |
1371 | __NL80211_AUTHTYPE_NUM, | |
1372 | NL80211_AUTHTYPE_MAX = __NL80211_AUTHTYPE_NUM - 1, | |
1373 | NL80211_AUTHTYPE_AUTOMATIC | |
1156 | 1374 | }; |
1157 | 1375 | |
1158 | 1376 | /** |
1167 | 1385 | NL80211_KEYTYPE_PEERKEY, |
1168 | 1386 | }; |
1169 | 1387 | |
1388 | /** | |
1389 | * enum nl80211_mfp - Management frame protection state | |
1390 | * @NL80211_MFP_NO: Management frame protection not used | |
1391 | * @NL80211_MFP_REQUIRED: Management frame protection required | |
1392 | */ | |
1393 | enum nl80211_mfp { | |
1394 | NL80211_MFP_NO, | |
1395 | NL80211_MFP_REQUIRED, | |
1396 | }; | |
1397 | ||
1398 | enum nl80211_wpa_versions { | |
1399 | NL80211_WPA_VERSION_1 = 1 << 0, | |
1400 | NL80211_WPA_VERSION_2 = 1 << 1, | |
1401 | }; | |
1402 | ||
1403 | /** | |
1404 | * enum nl80211_key_attributes - key attributes | |
1405 | * @__NL80211_KEY_INVALID: invalid | |
1406 | * @NL80211_KEY_DATA: (temporal) key data; for TKIP this consists of | |
1407 | * 16 bytes encryption key followed by 8 bytes each for TX and RX MIC | |
1408 | * keys | |
1409 | * @NL80211_KEY_IDX: key ID (u8, 0-3) | |
1410 | * @NL80211_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11 | |
1411 | * section 7.3.2.25.1, e.g. 0x000FAC04) | |
1412 | * @NL80211_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and | |
1413 | * CCMP keys, each six bytes in little endian | |
1414 | * @NL80211_KEY_DEFAULT: flag indicating default key | |
1415 | * @NL80211_KEY_DEFAULT_MGMT: flag indicating default management key | |
1416 | * @__NL80211_KEY_AFTER_LAST: internal | |
1417 | * @NL80211_KEY_MAX: highest key attribute | |
1418 | */ | |
1419 | enum nl80211_key_attributes { | |
1420 | __NL80211_KEY_INVALID, | |
1421 | NL80211_KEY_DATA, | |
1422 | NL80211_KEY_IDX, | |
1423 | NL80211_KEY_CIPHER, | |
1424 | NL80211_KEY_SEQ, | |
1425 | NL80211_KEY_DEFAULT, | |
1426 | NL80211_KEY_DEFAULT_MGMT, | |
1427 | ||
1428 | /* keep last */ | |
1429 | __NL80211_KEY_AFTER_LAST, | |
1430 | NL80211_KEY_MAX = __NL80211_KEY_AFTER_LAST - 1 | |
1431 | }; | |
1432 | ||
1170 | 1433 | #endif /* __LINUX_NL80211_H */ |
91 | 91 | NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_chan, NULL); |
92 | 92 | COMMAND(set, channel, "<channel> [HT20|HT40+|HT40-]", |
93 | 93 | NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_chan, NULL); |
94 | ||
95 | static int handle_fragmentation(struct nl80211_state *state, | |
96 | struct nl_cb *cb, struct nl_msg *msg, | |
97 | int argc, char **argv) | |
98 | { | |
99 | unsigned int frag; | |
100 | ||
101 | if (argc != 1) | |
102 | return 1; | |
103 | ||
104 | if (strcmp("off", argv[0]) == 0) | |
105 | frag = -1; | |
106 | else | |
107 | frag = strtoul(argv[0], NULL, 10); | |
108 | ||
109 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, frag); | |
110 | ||
111 | return 0; | |
112 | nla_put_failure: | |
113 | return -ENOBUFS; | |
114 | } | |
115 | COMMAND(set, frag, "<fragmentation threshold|off>", | |
116 | NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_fragmentation, | |
117 | "Set fragmentation threshold."); | |
118 | ||
119 | static int handle_rts(struct nl80211_state *state, | |
120 | struct nl_cb *cb, struct nl_msg *msg, | |
121 | int argc, char **argv) | |
122 | { | |
123 | unsigned int rts; | |
124 | ||
125 | if (argc != 1) | |
126 | return 1; | |
127 | ||
128 | if (strcmp("off", argv[0]) == 0) | |
129 | rts = -1; | |
130 | else | |
131 | rts = strtoul(argv[0], NULL, 10); | |
132 | ||
133 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, rts); | |
134 | ||
135 | return 0; | |
136 | nla_put_failure: | |
137 | return -ENOBUFS; | |
138 | } | |
139 | COMMAND(set, rts, "<rts threshold|off>", | |
140 | NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_rts, | |
141 | "Set rts threshold."); | |
142 | ||
143 | static int handle_netns(struct nl80211_state *state, | |
144 | struct nl_cb *cb, | |
145 | struct nl_msg *msg, | |
146 | int argc, char **argv) | |
147 | { | |
148 | char *end; | |
149 | ||
150 | if (argc != 1) | |
151 | return 1; | |
152 | ||
153 | NLA_PUT_U32(msg, NL80211_ATTR_PID, | |
154 | strtoul(argv[0], &end, 10)); | |
155 | ||
156 | if (*end != '\0') | |
157 | return 1; | |
158 | ||
159 | return 0; | |
160 | nla_put_failure: | |
161 | return -ENOBUFS; | |
162 | } | |
163 | COMMAND(set, netns, "<pid>", | |
164 | NL80211_CMD_SET_WIPHY_NETNS, 0, CIB_PHY, handle_netns, | |
165 | "Put this wireless device into a different network namespace"); |
25 | 25 | [23] = "IEEE 802.1X authentication failed", |
26 | 26 | [24] = "Cipher Suite rejected per security policy", |
27 | 27 | [31] = "TS deleted because QoS AP lacks sufficient bandwidth for this QoS STA due to a change in BSS service characteristics or operational mode", |
28 | [32] = "Disassociated for unspecified] = QoS-related reason", | |
28 | [32] = "Disassociated for unspecified QoS-related reason", | |
29 | 29 | [33] = "Disassociated because QAP lacks sufficient bandwidth for this STA", |
30 | 30 | [34] = "Disassociated because of excessive frame losses and/or poor channel conditions", |
31 | 31 | [35] = "Disassociated because QSTA is transmitting outside the limits of its polled TXOPs", |
10 | 10 | |
11 | 11 | #include "nl80211.h" |
12 | 12 | #include "iw.h" |
13 | ||
14 | SECTION(reg); | |
13 | 15 | |
14 | 16 | #define MHZ_TO_KHZ(freq) ((freq) * 1000) |
15 | 17 | #define KHZ_TO_MHZ(freq) ((freq) / 1000) |
31 | 31 | |
32 | 32 | struct scan_params { |
33 | 33 | bool unknown; |
34 | enum print_ie_type type; | |
34 | 35 | }; |
35 | 36 | |
36 | 37 | static int handle_scan(struct nl80211_state *state, |
106 | 107 | nlmsg_free(freqs); |
107 | 108 | return err; |
108 | 109 | } |
109 | COMMAND(scan, trigger, "[freq <freq>*] [ssid <ssid>*|passive]", | |
110 | NL80211_CMD_TRIGGER_SCAN, 0, CIB_NETDEV, handle_scan, | |
111 | "Trigger a scan on the given frequencies with probing for the given\n" | |
112 | "SSIDs (or wildcard if not given) unless passive scanning is requested."); | |
113 | 110 | |
114 | 111 | static void tab_on_first(bool *first) |
115 | 112 | { |
121 | 118 | |
122 | 119 | static void print_ssid(const uint8_t type, uint8_t len, const uint8_t *data) |
123 | 120 | { |
124 | int i; | |
125 | ||
126 | 121 | printf(" "); |
127 | ||
128 | for (i = 0; i < len; i++) { | |
129 | if (isprint(data[i])) | |
130 | printf("%c", data[i]); | |
131 | else | |
132 | printf("\\x%.2x", data[i]); | |
133 | } | |
122 | print_ssid_escaped(len, data); | |
134 | 123 | printf("\n"); |
135 | 124 | } |
136 | 125 | |
429 | 418 | static void print_rsn(const uint8_t type, uint8_t len, const uint8_t *data) |
430 | 419 | { |
431 | 420 | print_rsn_ie("CCMP", "IEEE 802.1X", len, data); |
421 | } | |
422 | ||
423 | static void print_ht_capa(const uint8_t type, uint8_t len, const uint8_t *data) | |
424 | { | |
425 | if (len != 26) { | |
426 | printf("\n\t\tHT Capability IE len != expected 26 bytes, skipping parse\n"); | |
427 | return; | |
428 | } | |
429 | printf("\n"); | |
430 | print_ht_capability(data[0] | (data[1] << 8)); | |
431 | print_ampdu_length(data[2] & 3); | |
432 | print_ampdu_spacing((data[2] >> 2) & 3); | |
433 | print_ht_mcs(data + 3); | |
432 | 434 | } |
433 | 435 | |
434 | 436 | static void print_capabilities(const uint8_t type, uint8_t len, const uint8_t *data) |
485 | 487 | const char *name; |
486 | 488 | void (*print)(const uint8_t type, uint8_t len, const uint8_t *data); |
487 | 489 | uint8_t minlen, maxlen; |
490 | uint8_t flags; | |
488 | 491 | }; |
489 | 492 | |
490 | 493 | static void print_ie(const struct ie_print *p, const uint8_t type, |
520 | 523 | } |
521 | 524 | |
522 | 525 | static const struct ie_print ieprinters[] = { |
523 | [0] = { "SSID", print_ssid, 0, 32, }, | |
524 | [1] = { "Supported rates", print_supprates, 0, 255, }, | |
525 | [3] = { "DS Paramater set", print_ds, 1, 1, }, | |
526 | [0] = { "SSID", print_ssid, 0, 32, BIT(PRINT_SCAN) | BIT(PRINT_LINK), }, | |
527 | [1] = { "Supported rates", print_supprates, 0, 255, BIT(PRINT_SCAN), }, | |
528 | [3] = { "DS Parameter set", print_ds, 1, 1, BIT(PRINT_SCAN), }, | |
526 | 529 | [5] = PRINT_IGN, |
527 | [7] = { "Country", print_country, 3, 255, }, | |
528 | [32] = { "Power constraint", print_powerconstraint, 1, 1, }, | |
529 | [42] = { "ERP", print_erp, 1, 255, }, | |
530 | [48] = { "RSN", print_rsn, 2, 255, }, | |
531 | [50] = { "Extended supported rates", print_supprates, 0, 255, }, | |
532 | [127] = { "Extended capabilities", print_capabilities, 0, 255, }, | |
530 | [7] = { "Country", print_country, 3, 255, BIT(PRINT_SCAN), }, | |
531 | [32] = { "Power constraint", print_powerconstraint, 1, 1, BIT(PRINT_SCAN), }, | |
532 | [42] = { "ERP", print_erp, 1, 255, BIT(PRINT_SCAN), }, | |
533 | [45] = { "HT capabilities", print_ht_capa, 1, 255, BIT(PRINT_SCAN), }, | |
534 | [48] = { "RSN", print_rsn, 2, 255, BIT(PRINT_SCAN), }, | |
535 | [50] = { "Extended supported rates", print_supprates, 0, 255, BIT(PRINT_SCAN), }, | |
536 | [127] = { "Extended capabilities", print_capabilities, 0, 255, BIT(PRINT_SCAN), }, | |
533 | 537 | }; |
534 | 538 | |
535 | 539 | static void print_wifi_wpa(const uint8_t type, uint8_t len, const uint8_t *data) |
536 | 540 | { |
537 | 541 | print_rsn_ie("TKIP", "IEEE 802.1X", len, data); |
542 | } | |
543 | ||
544 | static bool print_wifi_wmm_param(const uint8_t *data, uint8_t len) | |
545 | { | |
546 | int i; | |
547 | static const char *aci_tbl[] = { "BE", "BK", "VI", "VO" }; | |
548 | ||
549 | if (len < 19) | |
550 | goto invalid; | |
551 | ||
552 | if (data[0] != 1) { | |
553 | printf("Parameter: not version 1: "); | |
554 | return false; | |
555 | } | |
556 | ||
557 | printf("\t * Parameter version 1"); | |
558 | ||
559 | data++; | |
560 | ||
561 | if (data[0] & 0x80) | |
562 | printf("\n\t\t * u-APSD"); | |
563 | ||
564 | data += 2; | |
565 | ||
566 | for (i = 0; i < 4; i++) { | |
567 | printf("\n\t\t * %s:", aci_tbl[(data[0] >> 5) & 3]); | |
568 | if (data[4] & 0x10) | |
569 | printf(" acm"); | |
570 | printf(" CW %d-%d", (1 << (data[1] & 0xf)) - 1, | |
571 | (1 << (data[1] >> 4)) - 1); | |
572 | printf(", AIFSN %d", data[0] & 0xf); | |
573 | if (data[2] | data[3]) | |
574 | printf(", TXOP %d usec", (data[2] + (data[3] << 8)) * 32); | |
575 | data += 4; | |
576 | } | |
577 | ||
578 | printf("\n"); | |
579 | return true; | |
580 | ||
581 | invalid: | |
582 | printf("invalid: "); | |
583 | return false; | |
538 | 584 | } |
539 | 585 | |
540 | 586 | static void print_wifi_wmm(const uint8_t type, uint8_t len, const uint8_t *data) |
546 | 592 | printf(" information:"); |
547 | 593 | break; |
548 | 594 | case 0x01: |
549 | printf(" parameter:"); | |
595 | if (print_wifi_wmm_param(data + 1, len - 1)) | |
596 | return; | |
550 | 597 | break; |
551 | 598 | default: |
552 | 599 | printf(" type %d:", data[0]); |
553 | 600 | break; |
554 | 601 | } |
555 | 602 | |
556 | for(i = 0; i < len - 1; i++) | |
557 | printf(" %.02x", data[i + 1]); | |
603 | for(i = 1; i < len; i++) | |
604 | printf(" %.02x", data[i]); | |
558 | 605 | printf("\n"); |
559 | 606 | } |
560 | 607 | |
587 | 634 | printf("\t * Model: %.*s\n", sublen, data + 4); |
588 | 635 | break; |
589 | 636 | case 0x1057: { |
590 | __u16 val = (data[4] << 8) | data[5]; | |
637 | __u8 val = data[4]; | |
591 | 638 | tab_on_first(&first); |
592 | printf("\t * AP setup locked: 0x%.4x\n", val); | |
639 | printf("\t * AP setup locked: 0x%.2x\n", val); | |
593 | 640 | break; |
594 | 641 | } |
595 | 642 | case 0x1008: { |
637 | 684 | } |
638 | 685 | |
639 | 686 | static const struct ie_print wifiprinters[] = { |
640 | [1] = { "WPA", print_wifi_wpa, 2, 255, }, | |
641 | [2] = { "WMM", print_wifi_wmm, 1, 255, }, | |
642 | [4] = { "WPS", print_wifi_wps, 0, 255, }, | |
687 | [1] = { "WPA", print_wifi_wpa, 2, 255, BIT(PRINT_SCAN), }, | |
688 | [2] = { "WMM", print_wifi_wmm, 1, 255, BIT(PRINT_SCAN), }, | |
689 | [4] = { "WPS", print_wifi_wps, 0, 255, BIT(PRINT_SCAN), }, | |
643 | 690 | }; |
644 | 691 | |
645 | 692 | static void print_vendor(unsigned char len, unsigned char *data, |
646 | struct scan_params *params) | |
693 | bool unknown, enum print_ie_type ptype) | |
647 | 694 | { |
648 | 695 | int i; |
649 | 696 | |
656 | 703 | } |
657 | 704 | |
658 | 705 | if (len >= 4 && memcmp(data, wifi_oui, 3) == 0) { |
659 | if (data[3] < ARRAY_SIZE(wifiprinters) && wifiprinters[data[3]].name) { | |
706 | if (data[3] < ARRAY_SIZE(wifiprinters) && | |
707 | wifiprinters[data[3]].name && | |
708 | wifiprinters[data[3]].flags & BIT(ptype)) { | |
660 | 709 | print_ie(&wifiprinters[data[3]], data[3], len - 4, data + 4); |
661 | 710 | return; |
662 | 711 | } |
663 | if (!params->unknown) | |
712 | if (!unknown) | |
664 | 713 | return; |
665 | 714 | printf("\tWiFi OUI %#.2x, data:", data[3]); |
666 | 715 | for(i = 0; i < len - 4; i++) |
669 | 718 | return; |
670 | 719 | } |
671 | 720 | |
672 | if (!params->unknown) | |
721 | if (!unknown) | |
673 | 722 | return; |
674 | 723 | |
675 | 724 | printf("\tVendor specific: OUI %.2x:%.2x:%.2x, data:", |
679 | 728 | printf("\n"); |
680 | 729 | } |
681 | 730 | |
682 | static void print_ies(unsigned char *ie, int ielen, struct scan_params *params) | |
731 | void print_ies(unsigned char *ie, int ielen, bool unknown, | |
732 | enum print_ie_type ptype) | |
683 | 733 | { |
684 | 734 | while (ielen >= 2 && ielen >= ie[1]) { |
685 | if (ie[0] < ARRAY_SIZE(ieprinters) && ieprinters[ie[0]].name) { | |
735 | if (ie[0] < ARRAY_SIZE(ieprinters) && | |
736 | ieprinters[ie[0]].name && | |
737 | ieprinters[ie[0]].flags & BIT(ptype)) { | |
686 | 738 | print_ie(&ieprinters[ie[0]], ie[0], ie[1], ie + 2); |
687 | 739 | } else if (ie[0] == 221 /* vendor */) { |
688 | print_vendor(ie[1], ie + 2, params); | |
689 | } else if (params->unknown) { | |
740 | print_vendor(ie[1], ie + 2, unknown, ptype); | |
741 | } else if (unknown) { | |
690 | 742 | int i; |
691 | 743 | |
692 | 744 | printf("\tUnknown IE (%d):", ie[0]); |
714 | 766 | [NL80211_BSS_INFORMATION_ELEMENTS] = { }, |
715 | 767 | [NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 }, |
716 | 768 | [NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 }, |
769 | [NL80211_BSS_STATUS] = { .type = NLA_U32 }, | |
770 | [NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 }, | |
717 | 771 | }; |
772 | struct scan_params *params = arg; | |
718 | 773 | |
719 | 774 | nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), |
720 | 775 | genlmsg_attrlen(gnlh, 0), NULL); |
721 | 776 | |
722 | 777 | if (!tb[NL80211_ATTR_BSS]) { |
723 | fprintf(stderr, "bss info missing!"); | |
778 | fprintf(stderr, "bss info missing!\n"); | |
724 | 779 | return NL_SKIP; |
725 | 780 | } |
726 | 781 | if (nla_parse_nested(bss, NL80211_BSS_MAX, |
727 | 782 | tb[NL80211_ATTR_BSS], |
728 | 783 | bss_policy)) { |
729 | fprintf(stderr, "failed to parse nested attributes!"); | |
784 | fprintf(stderr, "failed to parse nested attributes!\n"); | |
730 | 785 | return NL_SKIP; |
731 | 786 | } |
732 | 787 | |
735 | 790 | |
736 | 791 | mac_addr_n2a(mac_addr, nla_data(bss[NL80211_BSS_BSSID])); |
737 | 792 | if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), dev); |
738 | printf("BSS %s (on %s)\n", mac_addr, dev); | |
793 | printf("BSS %s (on %s)", mac_addr, dev); | |
794 | ||
795 | if (bss[NL80211_BSS_STATUS]) { | |
796 | switch (nla_get_u32(bss[NL80211_BSS_STATUS])) { | |
797 | case NL80211_BSS_STATUS_AUTHENTICATED: | |
798 | printf(" -- authenticated"); | |
799 | break; | |
800 | case NL80211_BSS_STATUS_ASSOCIATED: | |
801 | printf(" -- associated"); | |
802 | break; | |
803 | case NL80211_BSS_STATUS_IBSS_JOINED: | |
804 | printf(" -- joined"); | |
805 | break; | |
806 | default: | |
807 | printf(" -- unknown status: %d", | |
808 | nla_get_u32(bss[NL80211_BSS_STATUS])); | |
809 | break; | |
810 | } | |
811 | } | |
812 | printf("\n"); | |
739 | 813 | |
740 | 814 | if (bss[NL80211_BSS_TSF]) { |
741 | 815 | unsigned long long tsf; |
785 | 859 | unsigned char s = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]); |
786 | 860 | printf("\tsignal: %d/100\n", s); |
787 | 861 | } |
862 | if (bss[NL80211_BSS_SEEN_MS_AGO]) { | |
863 | int age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]); | |
864 | printf("\tlast seen: %d ms ago\n", age); | |
865 | } | |
788 | 866 | if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) |
789 | 867 | print_ies(nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]), |
790 | 868 | nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]), |
791 | arg); | |
869 | params->unknown, params->type); | |
792 | 870 | |
793 | 871 | return NL_SKIP; |
794 | 872 | } |
807 | 885 | if (argc == 1 && !strcmp(argv[0], "-u")) |
808 | 886 | scan_params.unknown = true; |
809 | 887 | |
888 | scan_params.type = PRINT_SCAN; | |
889 | ||
810 | 890 | nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_bss_handler, |
811 | 891 | &scan_params); |
812 | 892 | return 0; |
813 | 893 | } |
814 | COMMAND(scan, dump, "[-u]", | |
815 | NL80211_CMD_GET_SCAN, NLM_F_DUMP, CIB_NETDEV, handle_scan_dump, | |
816 | "Dump the current scan results. If -u is specified, print unknown\n" | |
817 | "data in scan results."); | |
818 | 894 | |
819 | 895 | static int handle_scan_combined(struct nl80211_state *state, |
820 | 896 | struct nl_cb *cb, |
893 | 969 | "Scan on the given frequencies and probe for the given SSIDs\n" |
894 | 970 | "(or wildcard if not given) unless passive scanning is requested.\n" |
895 | 971 | "If -u is specified print unknown data in the scan results."); |
972 | COMMAND(scan, dump, "[-u]", | |
973 | NL80211_CMD_GET_SCAN, NLM_F_DUMP, CIB_NETDEV, handle_scan_dump, | |
974 | "Dump the current scan results. If -u is specified, print unknown\n" | |
975 | "data in scan results."); | |
976 | COMMAND(scan, trigger, "[freq <freq>*] [ssid <ssid>*|passive]", | |
977 | NL80211_CMD_TRIGGER_SCAN, 0, CIB_NETDEV, handle_scan, | |
978 | "Trigger a scan on the given frequencies with probing for the given\n" | |
979 | "SSIDs (or wildcard if not given) unless passive scanning is requested."); |
9 | 9 | |
10 | 10 | #include "nl80211.h" |
11 | 11 | #include "iw.h" |
12 | ||
13 | SECTION(station); | |
12 | 14 | |
13 | 15 | enum plink_state { |
14 | 16 | LISTEN, |
64 | 66 | */ |
65 | 67 | |
66 | 68 | if (!tb[NL80211_ATTR_STA_INFO]) { |
67 | fprintf(stderr, "sta stats missing!"); | |
69 | fprintf(stderr, "sta stats missing!\n"); | |
68 | 70 | return NL_SKIP; |
69 | 71 | } |
70 | 72 | if (nla_parse_nested(sinfo, NL80211_STA_INFO_MAX, |
71 | 73 | tb[NL80211_ATTR_STA_INFO], |
72 | 74 | stats_policy)) { |
73 | fprintf(stderr, "failed to parse nested attributes!"); | |
75 | fprintf(stderr, "failed to parse nested attributes!\n"); | |
74 | 76 | return NL_SKIP; |
75 | 77 | } |
76 | 78 | |
79 | 81 | printf("Station %s (on %s)", mac_addr, dev); |
80 | 82 | |
81 | 83 | if (sinfo[NL80211_STA_INFO_INACTIVE_TIME]) |
82 | printf("\n\tinactive time:\t%d ms", | |
84 | printf("\n\tinactive time:\t%u ms", | |
83 | 85 | nla_get_u32(sinfo[NL80211_STA_INFO_INACTIVE_TIME])); |
84 | 86 | if (sinfo[NL80211_STA_INFO_RX_BYTES]) |
85 | printf("\n\trx bytes:\t%d", | |
87 | printf("\n\trx bytes:\t%u", | |
86 | 88 | nla_get_u32(sinfo[NL80211_STA_INFO_RX_BYTES])); |
87 | 89 | if (sinfo[NL80211_STA_INFO_RX_PACKETS]) |
88 | printf("\n\trx packets:\t%d", | |
90 | printf("\n\trx packets:\t%u", | |
89 | 91 | nla_get_u32(sinfo[NL80211_STA_INFO_RX_PACKETS])); |
90 | 92 | if (sinfo[NL80211_STA_INFO_TX_BYTES]) |
91 | printf("\n\ttx bytes:\t%d", | |
93 | printf("\n\ttx bytes:\t%u", | |
92 | 94 | nla_get_u32(sinfo[NL80211_STA_INFO_TX_BYTES])); |
93 | 95 | if (sinfo[NL80211_STA_INFO_TX_PACKETS]) |
94 | printf("\n\ttx packets:\t%d", | |
96 | printf("\n\ttx packets:\t%u", | |
95 | 97 | nla_get_u32(sinfo[NL80211_STA_INFO_TX_PACKETS])); |
96 | 98 | if (sinfo[NL80211_STA_INFO_SIGNAL]) |
97 | 99 | printf("\n\tsignal: \t%d dBm", |
100 | 102 | if (sinfo[NL80211_STA_INFO_TX_BITRATE]) { |
101 | 103 | if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX, |
102 | 104 | sinfo[NL80211_STA_INFO_TX_BITRATE], rate_policy)) { |
103 | fprintf(stderr, "failed to parse nested rate attributes!"); | |
105 | fprintf(stderr, "failed to parse nested rate attributes!\n"); | |
104 | 106 | } else { |
105 | 107 | printf("\n\ttx bitrate:\t"); |
106 | 108 | if (rinfo[NL80211_RATE_INFO_BITRATE]) { |
124 | 126 | printf("\n\tmesh plid:\t%d", |
125 | 127 | nla_get_u16(sinfo[NL80211_STA_INFO_PLID])); |
126 | 128 | if (sinfo[NL80211_STA_INFO_PLINK_STATE]) { |
127 | switch (nla_get_u16(sinfo[NL80211_STA_INFO_PLINK_STATE])) { | |
129 | switch (nla_get_u8(sinfo[NL80211_STA_INFO_PLINK_STATE])) { | |
128 | 130 | case LISTEN: |
129 | 131 | strcpy(state_name, "LISTEN"); |
130 | 132 | break; |
193 | 195 | NL80211_CMD_DEL_STATION, 0, CIB_NETDEV, handle_station_get, |
194 | 196 | "Remove the given station entry (use with caution!)"); |
195 | 197 | |
196 | static int handle_station_set(struct nl80211_state *state, | |
198 | static int handle_station_set_plink(struct nl80211_state *state, | |
197 | 199 | struct nl_cb *cb, |
198 | 200 | struct nl_msg *msg, |
199 | 201 | int argc, char **argv) |
238 | 240 | return -ENOBUFS; |
239 | 241 | } |
240 | 242 | COMMAND(station, set, "<MAC address> plink_action <open|block>", |
241 | NL80211_CMD_SET_STATION, 0, CIB_NETDEV, handle_station_set, | |
243 | NL80211_CMD_SET_STATION, 0, CIB_NETDEV, handle_station_set_plink, | |
242 | 244 | "Set mesh peer link action for this station (peer)."); |
245 | ||
246 | static int handle_station_set_vlan(struct nl80211_state *state, | |
247 | struct nl_cb *cb, | |
248 | struct nl_msg *msg, | |
249 | int argc, char **argv) | |
250 | { | |
251 | unsigned char mac_addr[ETH_ALEN]; | |
252 | unsigned long sta_vlan = 0; | |
253 | char *err = NULL; | |
254 | ||
255 | if (argc < 3) | |
256 | return 1; | |
257 | ||
258 | if (mac_addr_a2n(mac_addr, argv[0])) { | |
259 | fprintf(stderr, "invalid mac address\n"); | |
260 | return 2; | |
261 | } | |
262 | argc--; | |
263 | argv++; | |
264 | ||
265 | if (strcmp("vlan", argv[0]) != 0) | |
266 | return 1; | |
267 | argc--; | |
268 | argv++; | |
269 | ||
270 | sta_vlan = strtoul(argv[0], &err, 0); | |
271 | if (err && *err) { | |
272 | fprintf(stderr, "invalid vlan id\n"); | |
273 | return 2; | |
274 | } | |
275 | argc--; | |
276 | argv++; | |
277 | ||
278 | if (argc) | |
279 | return 1; | |
280 | ||
281 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); | |
282 | NLA_PUT_U32(msg, NL80211_ATTR_STA_VLAN, sta_vlan); | |
283 | ||
284 | return 0; | |
285 | nla_put_failure: | |
286 | return -ENOBUFS; | |
287 | } | |
288 | COMMAND(station, set, "<MAC address> vlan <ifindex>", | |
289 | NL80211_CMD_SET_STATION, 0, CIB_NETDEV, handle_station_set_vlan, | |
290 | "Set an AP VLAN for this station."); | |
291 | ||
243 | 292 | |
244 | 293 | static int handle_station_dump(struct nl80211_state *state, |
245 | 294 | struct nl_cb *cb, |
0 | #include <net/if.h> | |
1 | #include <errno.h> | |
2 | #include <string.h> | |
3 | ||
4 | #include <netlink/genl/genl.h> | |
5 | #include <netlink/genl/family.h> | |
6 | #include <netlink/genl/ctrl.h> | |
7 | #include <netlink/msg.h> | |
8 | #include <netlink/attr.h> | |
9 | ||
10 | #include "nl80211.h" | |
11 | #include "iw.h" | |
12 | ||
13 | SECTION(survey); | |
14 | ||
15 | static int print_survey_handler(struct nl_msg *msg, void *arg) | |
16 | { | |
17 | struct nlattr *tb[NL80211_ATTR_MAX + 1]; | |
18 | struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); | |
19 | struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1]; | |
20 | char dev[20]; | |
21 | ||
22 | static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = { | |
23 | [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 }, | |
24 | [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 }, | |
25 | }; | |
26 | ||
27 | nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), | |
28 | genlmsg_attrlen(gnlh, 0), NULL); | |
29 | ||
30 | if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), dev); | |
31 | printf("Survey data from %s\n", dev); | |
32 | ||
33 | if (!tb[NL80211_ATTR_SURVEY_INFO]) { | |
34 | fprintf(stderr, "survey data missing!\n"); | |
35 | return NL_SKIP; | |
36 | } | |
37 | ||
38 | if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX, | |
39 | tb[NL80211_ATTR_SURVEY_INFO], | |
40 | survey_policy)) { | |
41 | fprintf(stderr, "failed to parse nested attributes!\n"); | |
42 | return NL_SKIP; | |
43 | } | |
44 | ||
45 | if (sinfo[NL80211_SURVEY_INFO_FREQUENCY]) | |
46 | printf("\tfrequency:\t%u MHz\n", | |
47 | nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY])); | |
48 | if (sinfo[NL80211_SURVEY_INFO_NOISE]) | |
49 | printf("\tnoise:\t\t%d dBm\n", | |
50 | (int8_t)nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE])); | |
51 | return NL_SKIP; | |
52 | } | |
53 | ||
54 | static int handle_survey_dump(struct nl80211_state *state, | |
55 | struct nl_cb *cb, | |
56 | struct nl_msg *msg, | |
57 | int argc, char **argv) | |
58 | { | |
59 | nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_survey_handler, NULL); | |
60 | return 0; | |
61 | } | |
62 | COMMAND(survey, dump, NULL, | |
63 | NL80211_CMD_GET_SURVEY, NLM_F_DUMP, CIB_NETDEV, handle_survey_dump, | |
64 | "List all gathered channel survey data"); | |
65 |
0 | #include <ctype.h> | |
1 | #include <netlink/attr.h> | |
2 | #include <errno.h> | |
3 | #include <stdbool.h> | |
0 | 4 | #include "iw.h" |
1 | 5 | #include "nl80211.h" |
2 | 6 | |
3 | int mac_addr_n2a(char *mac_addr, unsigned char *arg) | |
7 | void mac_addr_n2a(char *mac_addr, unsigned char *arg) | |
4 | 8 | { |
5 | 9 | int i, l; |
6 | 10 | |
14 | 18 | l += 3; |
15 | 19 | } |
16 | 20 | } |
17 | return 0; | |
18 | 21 | } |
19 | 22 | |
20 | 23 | int mac_addr_a2n(unsigned char *mac_addr, char *arg) |
65 | 68 | return modebuf; |
66 | 69 | } |
67 | 70 | |
71 | static const char *commands[NL80211_CMD_MAX + 1] = { | |
72 | "unspecified", | |
73 | "get_wiphy", | |
74 | "set_wiphy", | |
75 | "new_wiphy", | |
76 | "del_wiphy", | |
77 | "get_interface", | |
78 | "set_interface", | |
79 | "new_interface", | |
80 | "del_interface", | |
81 | "get_key", | |
82 | "set_key", | |
83 | "new_key", | |
84 | "del_key", | |
85 | "get_beacon", | |
86 | "set_beacon", | |
87 | "new_beacon", | |
88 | "del_beacon", | |
89 | "get_station", | |
90 | "set_station", | |
91 | "new_station", | |
92 | "del_station", | |
93 | "get_mpath", | |
94 | "set_mpath", | |
95 | "new_mpath", | |
96 | "del_mpath", | |
97 | "set_bss", | |
98 | "set_reg", | |
99 | "reg_set_reg", | |
100 | "get_mesh_params", | |
101 | "set_mesh_params", | |
102 | "set_mgmt_extra_ie", | |
103 | "get_reg", | |
104 | "get_scan", | |
105 | "trigger_scan", | |
106 | "new_scan_results", | |
107 | "scan_aborted", | |
108 | "reg_change", | |
109 | "authenticate", | |
110 | "associate", | |
111 | "deauthenticate", | |
112 | "disassociate", | |
113 | "michael_mic_failure", | |
114 | "reg_beacon_hint", | |
115 | "join_ibss", | |
116 | "leave_ibss", | |
117 | "testmode", | |
118 | "connect", | |
119 | "roam", | |
120 | "disconnect", | |
121 | "set_wiphy_netns" | |
122 | }; | |
123 | ||
124 | static char cmdbuf[100]; | |
125 | ||
126 | const char *command_name(enum nl80211_commands cmd) | |
127 | { | |
128 | if (cmd <= NL80211_CMD_MAX) | |
129 | return commands[cmd]; | |
130 | sprintf(cmdbuf, "Unknown command (%d)", cmd); | |
131 | return cmdbuf; | |
132 | } | |
133 | ||
68 | 134 | int ieee80211_channel_to_frequency(int chan) |
69 | 135 | { |
70 | 136 | if (chan < 14) |
88 | 154 | /* FIXME: dot11ChannelStartingFactor (802.11-2007 17.3.8.3.2) */ |
89 | 155 | return freq/5 - 1000; |
90 | 156 | } |
157 | ||
158 | void print_ssid_escaped(const uint8_t len, const uint8_t *data) | |
159 | { | |
160 | int i; | |
161 | ||
162 | for (i = 0; i < len; i++) { | |
163 | if (isprint(data[i])) | |
164 | printf("%c", data[i]); | |
165 | else | |
166 | printf("\\x%.2x", data[i]); | |
167 | } | |
168 | } | |
169 | ||
170 | static int hex2num(char digit) | |
171 | { | |
172 | if (!isxdigit(digit)) | |
173 | return -1; | |
174 | if (isdigit(digit)) | |
175 | return digit - '0'; | |
176 | return tolower(digit) - 'a' + 10; | |
177 | } | |
178 | ||
179 | static int hex2byte(char *hex) | |
180 | { | |
181 | int d1, d2; | |
182 | ||
183 | d1 = hex2num(hex[0]); | |
184 | if (d1 < 0) | |
185 | return -1; | |
186 | d2 = hex2num(hex[1]); | |
187 | if (d2 < 0) | |
188 | return -1; | |
189 | return (d1 << 4) | d2; | |
190 | } | |
191 | ||
192 | static char *hex2bin(char *hex, char *buf) | |
193 | { | |
194 | char *result = buf; | |
195 | int d; | |
196 | ||
197 | while (hex[0]) { | |
198 | d = hex2byte(hex); | |
199 | if (d < 0) | |
200 | return NULL; | |
201 | buf[0] = d; | |
202 | buf++; | |
203 | hex += 2; | |
204 | } | |
205 | ||
206 | return result; | |
207 | } | |
208 | ||
209 | int parse_keys(struct nl_msg *msg, char **argv, int argc) | |
210 | { | |
211 | struct nlattr *keys; | |
212 | int i = 0; | |
213 | bool have_default = false; | |
214 | char keybuf[13]; | |
215 | ||
216 | if (!argc) | |
217 | return 1; | |
218 | ||
219 | NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY); | |
220 | ||
221 | keys = nla_nest_start(msg, NL80211_ATTR_KEYS); | |
222 | if (!keys) | |
223 | return -ENOBUFS; | |
224 | ||
225 | do { | |
226 | char *arg = *argv; | |
227 | int pos = 0, keylen; | |
228 | struct nlattr *key = nla_nest_start(msg, ++i); | |
229 | char *keydata; | |
230 | ||
231 | if (!key) | |
232 | return -ENOBUFS; | |
233 | ||
234 | if (arg[pos] == 'd') { | |
235 | NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT); | |
236 | pos++; | |
237 | if (arg[pos] == ':') | |
238 | pos++; | |
239 | have_default = true; | |
240 | } | |
241 | ||
242 | if (!isdigit(arg[pos])) | |
243 | goto explain; | |
244 | NLA_PUT_U8(msg, NL80211_KEY_IDX, arg[pos++] - '0'); | |
245 | if (arg[pos++] != ':') | |
246 | goto explain; | |
247 | keydata = arg + pos; | |
248 | switch (strlen(keydata)) { | |
249 | case 10: | |
250 | keydata = hex2bin(keydata, keybuf); | |
251 | case 5: | |
252 | NLA_PUT_U32(msg, NL80211_KEY_CIPHER, 0x000FAC01); | |
253 | keylen = 5; | |
254 | break; | |
255 | case 26: | |
256 | keydata = hex2bin(keydata, keybuf); | |
257 | case 13: | |
258 | NLA_PUT_U32(msg, NL80211_KEY_CIPHER, 0x000FAC05); | |
259 | keylen = 13; | |
260 | break; | |
261 | default: | |
262 | goto explain; | |
263 | } | |
264 | ||
265 | if (!keydata) | |
266 | goto explain; | |
267 | ||
268 | NLA_PUT(msg, NL80211_KEY_DATA, keylen, keydata); | |
269 | ||
270 | argv++; | |
271 | argc--; | |
272 | ||
273 | /* one key should be TX key */ | |
274 | if (!have_default && !argc) | |
275 | NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT); | |
276 | ||
277 | nla_nest_end(msg, key); | |
278 | } while (argc); | |
279 | ||
280 | nla_nest_end(msg, keys); | |
281 | ||
282 | return 0; | |
283 | nla_put_failure: | |
284 | return -ENOBUFS; | |
285 | explain: | |
286 | fprintf(stderr, "key must be [d:]index:data where\n" | |
287 | " 'd:' means default (transmit) key\n" | |
288 | " 'index:' is a single digit (0-3)\n" | |
289 | " 'data' must be 5 or 13 ascii chars\n" | |
290 | " or 10 or 26 hex digits\n" | |
291 | "for example: d:2:6162636465 is the same as d:2:abcde\n"); | |
292 | return 2; | |
293 | } | |
294 | ||
295 | static void print_mcs_index(const __u8 *mcs) | |
296 | { | |
297 | unsigned int mcs_bit, prev_bit = -2, prev_cont = 0; | |
298 | ||
299 | for (mcs_bit = 0; mcs_bit <= 76; mcs_bit++) { | |
300 | unsigned int mcs_octet = mcs_bit/8; | |
301 | unsigned int MCS_RATE_BIT = 1 << mcs_bit % 8; | |
302 | bool mcs_rate_idx_set; | |
303 | ||
304 | mcs_rate_idx_set = !!(mcs[mcs_octet] & MCS_RATE_BIT); | |
305 | ||
306 | if (!mcs_rate_idx_set) | |
307 | continue; | |
308 | ||
309 | if (prev_bit != mcs_bit - 1) { | |
310 | if (prev_bit != -2) | |
311 | printf("%d, ", prev_bit); | |
312 | else | |
313 | printf(" "); | |
314 | printf("%d", mcs_bit); | |
315 | prev_cont = 0; | |
316 | } else if (!prev_cont) { | |
317 | printf("-"); | |
318 | prev_cont = 1; | |
319 | } | |
320 | ||
321 | prev_bit = mcs_bit; | |
322 | } | |
323 | ||
324 | if (prev_cont) | |
325 | printf("%d", prev_bit); | |
326 | printf("\n"); | |
327 | } | |
328 | ||
329 | /* | |
330 | * There are only 4 possible values, we just use a case instead of computing it, | |
331 | * but technically this can also be computed through the formula: | |
332 | * | |
333 | * Max AMPDU length = (2 ^ (13 + exponent)) - 1 bytes | |
334 | */ | |
335 | static __u32 compute_ampdu_length(__u8 exponent) | |
336 | { | |
337 | switch (exponent) { | |
338 | case 0: return 8191; /* (2 ^(13 + 0)) -1 */ | |
339 | case 1: return 16383; /* (2 ^(13 + 1)) -1 */ | |
340 | case 2: return 32767; /* (2 ^(13 + 2)) -1 */ | |
341 | case 3: return 65535; /* (2 ^(13 + 3)) -1 */ | |
342 | default: return 0; | |
343 | } | |
344 | } | |
345 | ||
346 | static const char *print_ampdu_space(__u8 space) | |
347 | { | |
348 | switch (space) { | |
349 | case 0: return "No restriction"; | |
350 | case 1: return "1/4 usec"; | |
351 | case 2: return "1/2 usec"; | |
352 | case 3: return "1 usec"; | |
353 | case 4: return "2 usec"; | |
354 | case 5: return "4 usec"; | |
355 | case 6: return "8 usec"; | |
356 | case 7: return "16 usec"; | |
357 | default: | |
358 | return "BUG (spacing more than 3 bits!)"; | |
359 | } | |
360 | } | |
361 | ||
362 | void print_ampdu_length(__u8 exponent) | |
363 | { | |
364 | __u32 max_ampdu_length; | |
365 | ||
366 | max_ampdu_length = compute_ampdu_length(exponent); | |
367 | ||
368 | if (max_ampdu_length) { | |
369 | printf("\t\tMaximum RX AMPDU length %d bytes (exponent: 0x0%02x)\n", | |
370 | max_ampdu_length, exponent); | |
371 | } else { | |
372 | printf("\t\tMaximum RX AMPDU length: unrecognized bytes " | |
373 | "(exponent: %d)\n", exponent); | |
374 | } | |
375 | } | |
376 | ||
377 | void print_ampdu_spacing(__u8 spacing) | |
378 | { | |
379 | printf("\t\tMinimum RX AMPDU time spacing: %s (0x%02x)\n", | |
380 | print_ampdu_space(spacing), spacing); | |
381 | } | |
382 | ||
383 | void print_ht_capability(__u16 cap) | |
384 | { | |
385 | #define PRINT_HT_CAP(_cond, _str) \ | |
386 | do { \ | |
387 | if (_cond) \ | |
388 | printf("\t\t\t" _str "\n"); \ | |
389 | } while (0) | |
390 | ||
391 | printf("\t\tCapabilities: 0x%02x\n", cap); | |
392 | ||
393 | PRINT_HT_CAP((cap & BIT(0)), "RX LDCP"); | |
394 | PRINT_HT_CAP((cap & BIT(1)), "HT20/HT40"); | |
395 | PRINT_HT_CAP(!(cap & BIT(1)), "HT20"); | |
396 | ||
397 | PRINT_HT_CAP(((cap >> 2) & 0x3) == 0, "Static SM Power Save"); | |
398 | PRINT_HT_CAP(((cap >> 2) & 0x3) == 1, "Dynamic SM Power Save"); | |
399 | PRINT_HT_CAP(((cap >> 2) & 0x3) == 3, "SM Power Save disabled"); | |
400 | ||
401 | PRINT_HT_CAP((cap & BIT(4)), "RX Greenfield"); | |
402 | PRINT_HT_CAP((cap & BIT(5)), "RX HT20 SGI"); | |
403 | PRINT_HT_CAP((cap & BIT(6)), "RX HT40 SGI"); | |
404 | PRINT_HT_CAP((cap & BIT(7)), "TX STBC"); | |
405 | ||
406 | PRINT_HT_CAP(((cap >> 8) & 0x3) == 0, "No RX STBC"); | |
407 | PRINT_HT_CAP(((cap >> 8) & 0x3) == 1, "RX STBC 1-stream"); | |
408 | PRINT_HT_CAP(((cap >> 8) & 0x3) == 2, "RX STBC 2-streams"); | |
409 | PRINT_HT_CAP(((cap >> 8) & 0x3) == 3, "RX STBC 3-streams"); | |
410 | ||
411 | PRINT_HT_CAP((cap & BIT(10)), "HT Delayed Block Ack"); | |
412 | ||
413 | PRINT_HT_CAP((cap & BIT(11)), "Max AMSDU length: 3839 bytes"); | |
414 | PRINT_HT_CAP(!(cap & BIT(11)), "Max AMSDU length: 7935 bytes"); | |
415 | ||
416 | /* | |
417 | * For beacons and probe response this would mean the BSS | |
418 | * does or does not allow the usage of DSSS/CCK HT40. | |
419 | * Otherwise it means the STA does or does not use | |
420 | * DSSS/CCK HT40. | |
421 | */ | |
422 | PRINT_HT_CAP((cap & BIT(12)), "DSSS/CCK HT40"); | |
423 | PRINT_HT_CAP(!(cap & BIT(12)), "No DSSS/CCK HT40"); | |
424 | ||
425 | /* BIT(13) is reserved */ | |
426 | ||
427 | PRINT_HT_CAP((cap & BIT(14)), "40 MHz Intolerant"); | |
428 | ||
429 | PRINT_HT_CAP((cap & BIT(15)), "L-SIG TXOP protection"); | |
430 | #undef PRINT_HT_CAP | |
431 | } | |
432 | ||
433 | void print_ht_mcs(const __u8 *mcs) | |
434 | { | |
435 | /* As defined in 7.3.2.57.4 Supported MCS Set field */ | |
436 | unsigned int tx_max_num_spatial_streams, max_rx_supp_data_rate; | |
437 | bool tx_mcs_set_defined, tx_mcs_set_equal, tx_unequal_modulation; | |
438 | ||
439 | max_rx_supp_data_rate = ((mcs[10] >> 8) & ((mcs[11] & 0x3) << 8)); | |
440 | tx_mcs_set_defined = !!(mcs[12] & (1 << 0)); | |
441 | tx_mcs_set_equal = !(mcs[12] & (1 << 1)); | |
442 | tx_max_num_spatial_streams = ((mcs[12] >> 2) & 3) + 1; | |
443 | tx_unequal_modulation = !!(mcs[12] & (1 << 4)); | |
444 | ||
445 | if (max_rx_supp_data_rate) | |
446 | printf("\t\tHT Max RX data rate: %d Mbps\n", max_rx_supp_data_rate); | |
447 | /* XXX: else see 9.6.0e.5.3 how to get this I think */ | |
448 | ||
449 | if (tx_mcs_set_defined) { | |
450 | if (tx_mcs_set_equal) { | |
451 | printf("\t\tHT TX/RX MCS rate indexes supported:"); | |
452 | print_mcs_index(mcs); | |
453 | } else { | |
454 | printf("\t\tHT RX MCS rate indexes supported:"); | |
455 | print_mcs_index(mcs); | |
456 | ||
457 | if (tx_unequal_modulation) | |
458 | printf("\t\tTX unequal modulation supported\n"); | |
459 | else | |
460 | printf("\t\tTX unequal modulation not supported\n"); | |
461 | ||
462 | printf("\t\tHT TX Max spatial streams: %d\n", | |
463 | tx_max_num_spatial_streams); | |
464 | ||
465 | printf("\t\tHT TX MCS rate indexes supported may differ\n"); | |
466 | } | |
467 | } else { | |
468 | printf("\t\tHT RX MCS rate indexes supported:"); | |
469 | print_mcs_index(mcs); | |
470 | printf("\t\tHT TX MCS rate indexes are undefined\n"); | |
471 | } | |
472 | } |
0 | 0 | #!/bin/sh |
1 | 1 | |
2 | VERSION="0.9.14" | |
2 | VERSION="0.9.19" | |
3 | 3 | OUT="$1" |
4 | ||
5 | echo '#include "iw.h"' > "$OUT" | |
4 | 6 | |
5 | 7 | if head=`git rev-parse --verify HEAD 2>/dev/null`; then |
6 | 8 | git update-index --refresh --unmerged > /dev/null |
10 | 12 | # is correct... |
11 | 13 | [ "${descr%%-*}" = "v$VERSION" ] || exit 2 |
12 | 14 | |
13 | echo -n 'const char iw_version[] = "' > "$OUT" | |
14 | 15 | v="${descr#v}" |
15 | 16 | if git diff-index --name-only HEAD | read dummy ; then |
16 | 17 | v="$v"-dirty |
19 | 20 | v="$VERSION" |
20 | 21 | fi |
21 | 22 | |
22 | echo "const char iw_version[] = \"$v\";" > "$OUT" | |
23 | echo "const char iw_version[] = \"$v\";" >> "$OUT" |