]> git.ipfire.org Git - thirdparty/iw.git/blame - iw.c
print extended capabilities
[thirdparty/iw.git] / iw.c
CommitLineData
cad53b3f
JB
1/*
2 * nl80211 userspace tool
3 *
2a1fced2 4 * Copyright 2007, 2008 Johannes Berg <johannes@sipsolutions.net>
cad53b3f
JB
5 */
6
7#include <errno.h>
8#include <stdio.h>
d5ac8ad3 9#include <string.h>
bd396f2a
JB
10#include <net/if.h>
11#include <sys/types.h>
12#include <sys/stat.h>
13#include <fcntl.h>
14#include <unistd.h>
15
cad53b3f
JB
16#include <netlink/genl/genl.h>
17#include <netlink/genl/family.h>
18#include <netlink/genl/ctrl.h>
19#include <netlink/msg.h>
20#include <netlink/attr.h>
cad53b3f 21
f408e01b 22#include "nl80211.h"
cad53b3f
JB
23#include "iw.h"
24
dfd13ee5
PE
25#ifndef CONFIG_LIBNL20
26/* libnl 2.0 compatibility code */
27
28static inline struct nl_handle *nl_socket_alloc(void)
29{
30 return nl_handle_alloc();
31}
32
57077d64 33static inline void nl_socket_free(struct nl_sock *h)
dfd13ee5
PE
34{
35 nl_handle_destroy(h);
36}
37
57077d64 38static inline int __genl_ctrl_alloc_cache(struct nl_sock *h, struct nl_cache **cache)
dfd13ee5
PE
39{
40 struct nl_cache *tmp = genl_ctrl_alloc_cache(h);
41 if (!tmp)
42 return -ENOMEM;
43 *cache = tmp;
44 return 0;
45}
46#define genl_ctrl_alloc_cache __genl_ctrl_alloc_cache
47#endif /* CONFIG_LIBNL20 */
48
656aa246 49static int debug = 0;
cad53b3f
JB
50
51static int nl80211_init(struct nl80211_state *state)
52{
53 int err;
54
57077d64
PE
55 state->nl_sock = nl_socket_alloc();
56 if (!state->nl_sock) {
57 fprintf(stderr, "Failed to allocate netlink socket.\n");
cad53b3f
JB
58 return -ENOMEM;
59 }
60
57077d64 61 if (genl_connect(state->nl_sock)) {
cad53b3f
JB
62 fprintf(stderr, "Failed to connect to generic netlink.\n");
63 err = -ENOLINK;
64 goto out_handle_destroy;
65 }
66
57077d64 67 if (genl_ctrl_alloc_cache(state->nl_sock, &state->nl_cache)) {
cad53b3f
JB
68 fprintf(stderr, "Failed to allocate generic netlink cache.\n");
69 err = -ENOMEM;
70 goto out_handle_destroy;
71 }
72
73 state->nl80211 = genl_ctrl_search_by_name(state->nl_cache, "nl80211");
74 if (!state->nl80211) {
75 fprintf(stderr, "nl80211 not found.\n");
76 err = -ENOENT;
77 goto out_cache_free;
78 }
79
80 return 0;
81
82 out_cache_free:
83 nl_cache_free(state->nl_cache);
84 out_handle_destroy:
57077d64 85 nl_socket_free(state->nl_sock);
cad53b3f
JB
86 return err;
87}
88
89static void nl80211_cleanup(struct nl80211_state *state)
90{
91 genl_family_put(state->nl80211);
92 nl_cache_free(state->nl_cache);
57077d64 93 nl_socket_free(state->nl_sock);
cad53b3f
JB
94}
95
811ec68f
JB
96__COMMAND(NULL, NULL, "", NULL, 0, 0, 0, CIB_NONE, NULL);
97__COMMAND(NULL, NULL, "", NULL, 1, 0, 0, CIB_NONE, NULL);
403b9c83
JB
98
99static int cmd_size;
100
bd396f2a
JB
101static void usage(const char *argv0)
102{
103 struct cmd *cmd;
104
59c49f09
JB
105 fprintf(stderr, "Usage:\t%s [options] command\n", argv0);
106 fprintf(stderr, "Options:\n");
d711f013
JB
107 fprintf(stderr, "\t--debug\t\tenable netlink debugging\n");
108 fprintf(stderr, "\t--version\tshow version\n");
59c49f09 109 fprintf(stderr, "Commands:\n");
2c61ba61
JB
110 fprintf(stderr, "\thelp\n");
111 fprintf(stderr, "\tevent\n");
403b9c83
JB
112 for (cmd = &__start___cmd; cmd < &__stop___cmd;
113 cmd = (struct cmd *)((char *)cmd + cmd_size)) {
ce5af55c 114 if (!cmd->handler || cmd->hidden)
403b9c83 115 continue;
bd396f2a
JB
116 switch (cmd->idby) {
117 case CIB_NONE:
59c49f09 118 fprintf(stderr, "\t");
f83a81d0 119 break;
bd396f2a 120 case CIB_PHY:
f83a81d0
JB
121 fprintf(stderr, "\tphy <phyname> ");
122 break;
bd396f2a 123 case CIB_NETDEV:
f83a81d0 124 fprintf(stderr, "\tdev <devname> ");
bd396f2a
JB
125 break;
126 }
f83a81d0
JB
127 if (cmd->section)
128 fprintf(stderr, "%s ", cmd->section);
129 fprintf(stderr, "%s", cmd->name);
130 if (cmd->args)
131 fprintf(stderr, " %s", cmd->args);
132 fprintf(stderr, "\n");
bd396f2a
JB
133 }
134}
135
d711f013
JB
136static void version(void)
137{
133b069f 138 printf("iw version %s\n", iw_version);
d711f013
JB
139}
140
bd396f2a
JB
141static int phy_lookup(char *name)
142{
143 char buf[200];
144 int fd, pos;
145
146 snprintf(buf, sizeof(buf), "/sys/class/ieee80211/%s/index", name);
147
148 fd = open(buf, O_RDONLY);
989e97c2
JB
149 if (fd < 0)
150 return -1;
bd396f2a
JB
151 pos = read(fd, buf, sizeof(buf) - 1);
152 if (pos < 0)
153 return -1;
154 buf[pos] = '\0';
155 return atoi(buf);
156}
157
70391ccf
JB
158static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
159 void *arg)
160{
161 int *ret = arg;
162 *ret = err->error;
163 return NL_STOP;
164}
165
561c5b7e
JB
166static int finish_handler(struct nl_msg *msg, void *arg)
167{
59c418c0
JB
168 int *ret = arg;
169 *ret = 0;
561c5b7e
JB
170 return NL_SKIP;
171}
172
173static int ack_handler(struct nl_msg *msg, void *arg)
70391ccf
JB
174{
175 int *ret = arg;
176 *ret = 0;
177 return NL_STOP;
178}
179
7c37a24d
JB
180int handle_cmd(struct nl80211_state *state, enum id_input idby,
181 int argc, char **argv)
45c7212c 182{
bb60b4ae 183 struct cmd *cmd, *match = NULL;
7c37a24d 184 struct nl_cb *cb;
bd396f2a
JB
185 struct nl_msg *msg;
186 int devidx = 0;
bb60b4ae 187 int err, o_argc;
bd396f2a 188 const char *command, *section;
bb60b4ae 189 char *tmp, **o_argv;
9927363c 190 enum command_identify_by command_idby = CIB_NONE;
45c7212c 191
9927363c 192 if (argc <= 1 && idby != II_NONE)
5e75fd04 193 return 1;
45c7212c 194
bb60b4ae
JB
195 o_argc = argc;
196 o_argv = argv;
197
bd396f2a 198 switch (idby) {
9927363c
JB
199 case II_PHY_IDX:
200 command_idby = CIB_PHY;
201 devidx = strtoul(*argv + 4, &tmp, 0);
202 if (*tmp != '\0')
203 return 1;
204 argc--;
205 argv++;
206 break;
207 case II_PHY_NAME:
208 command_idby = CIB_PHY;
bd396f2a
JB
209 devidx = phy_lookup(*argv);
210 argc--;
211 argv++;
212 break;
9927363c
JB
213 case II_NETDEV:
214 command_idby = CIB_NETDEV;
bd396f2a 215 devidx = if_nametoindex(*argv);
989e97c2
JB
216 if (devidx == 0)
217 devidx = -1;
bd396f2a
JB
218 argc--;
219 argv++;
220 break;
221 default:
222 break;
223 }
224
989e97c2
JB
225 if (devidx < 0)
226 return -errno;
227
bd396f2a
JB
228 section = command = *argv;
229 argc--;
230 argv++;
231
403b9c83
JB
232 for (cmd = &__start___cmd; cmd < &__stop___cmd;
233 cmd = (struct cmd *)((char *)cmd + cmd_size)) {
234 if (!cmd->handler)
235 continue;
9927363c 236 if (cmd->idby != command_idby)
bd396f2a
JB
237 continue;
238 if (cmd->section) {
239 if (strcmp(cmd->section, section))
240 continue;
241 /* this is a bit icky ... */
242 if (command == section) {
bb60b4ae
JB
243 if (argc <= 0) {
244 if (match)
245 break;
5e75fd04 246 return 1;
bb60b4ae 247 }
bd396f2a
JB
248 command = *argv;
249 argc--;
250 argv++;
251 }
252 } else if (section != command)
253 continue;
254 if (strcmp(cmd->name, command))
255 continue;
256 if (argc && !cmd->args)
257 continue;
bb60b4ae
JB
258
259 match = cmd;
bd396f2a 260 }
45c7212c 261
bb60b4ae
JB
262 cmd = match;
263
264 if (!cmd)
5e75fd04 265 return 1;
45c7212c 266
bb60b4ae
JB
267 if (!cmd->cmd) {
268 argc = o_argc;
269 argv = o_argv;
270 return cmd->handler(state, NULL, NULL, argc, argv);
271 }
272
bd396f2a
JB
273 msg = nlmsg_alloc();
274 if (!msg) {
70391ccf
JB
275 fprintf(stderr, "failed to allocate netlink message\n");
276 return 2;
277 }
278
59c49f09 279 cb = nl_cb_alloc(debug ? NL_CB_DEBUG : NL_CB_DEFAULT);
70391ccf
JB
280 if (!cb) {
281 fprintf(stderr, "failed to allocate netlink callbacks\n");
282 err = 2;
283 goto out_free_msg;
bd396f2a 284 }
45c7212c 285
bd396f2a
JB
286 genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0,
287 cmd->nl_msg_flags, cmd->cmd, 0);
288
9927363c 289 switch (command_idby) {
bd396f2a
JB
290 case CIB_PHY:
291 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, devidx);
292 break;
293 case CIB_NETDEV:
294 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);
295 break;
296 default:
297 break;
298 }
299
7c37a24d 300 err = cmd->handler(state, cb, msg, argc, argv);
70391ccf
JB
301 if (err)
302 goto out;
303
57077d64 304 err = nl_send_auto_complete(state->nl_sock, msg);
70391ccf
JB
305 if (err < 0)
306 goto out;
307
c5c4471a
JB
308 err = 1;
309
70391ccf 310 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
59c418c0 311 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
561c5b7e 312 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
70391ccf 313
c5c4471a 314 while (err > 0)
57077d64 315 nl_recvmsgs(state->nl_sock, cb);
70391ccf
JB
316 out:
317 nl_cb_put(cb);
318 out_free_msg:
319 nlmsg_free(msg);
320 return err;
bd396f2a
JB
321 nla_put_failure:
322 fprintf(stderr, "building message failed\n");
70391ccf 323 return 2;
45c7212c
JB
324}
325
2c61ba61
JB
326static int no_seq_check(struct nl_msg *msg, void *arg)
327{
328 return NL_OK;
329}
330
331static int print_event(struct nl_msg *msg, void *arg)
332{
333 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
334 struct nlattr *tb[NL80211_ATTR_MAX + 1];
99f46802 335 char ifname[100];
edea4d14 336 char macbuf[6*3];
601c6ab2 337 __u8 reg_type;
2c61ba61
JB
338
339 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
340 genlmsg_attrlen(gnlh, 0), NULL);
341
342 switch (gnlh->cmd) {
03109dcb 343 case NL80211_CMD_NEW_WIPHY:
2c61ba61
JB
344 printf("wiphy rename: phy #%d to %s\n",
345 nla_get_u32(tb[NL80211_ATTR_WIPHY]),
346 nla_get_string(tb[NL80211_ATTR_WIPHY_NAME]));
347 break;
99f46802
JB
348 case NL80211_CMD_NEW_SCAN_RESULTS:
349 if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), ifname);
350 printf("scan finished on %s (phy #%d)\n",
351 ifname, nla_get_u32(tb[NL80211_ATTR_WIPHY]));
352 break;
353 case NL80211_CMD_SCAN_ABORTED:
354 if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), ifname);
355 printf("scan aborted on %s (phy #%d)\n",
356 ifname, nla_get_u32(tb[NL80211_ATTR_WIPHY]));
357 break;
601c6ab2
LR
358 case NL80211_CMD_REG_CHANGE:
359
360 printf("regulatory domain change: ");
361
362 reg_type = nla_get_u8(tb[NL80211_ATTR_REG_TYPE]);
363
364 switch (reg_type) {
365 case NL80211_REGDOM_TYPE_COUNTRY:
366 printf("set to %s by %s request",
367 nla_get_string(tb[NL80211_ATTR_REG_ALPHA2]),
368 reg_initiator_to_string(nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR])));
369 if (tb[NL80211_ATTR_WIPHY])
370 printf(" on phy%d", nla_get_u32(tb[NL80211_ATTR_WIPHY]));
371 break;
372 case NL80211_REGDOM_TYPE_WORLD:
373 printf("set to world roaming by %s request",
374 reg_initiator_to_string(nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR])));
375 break;
376 case NL80211_REGDOM_TYPE_CUSTOM_WORLD:
377 printf("custom world roaming rules in place on phy%d by %s request",
378 nla_get_u32(tb[NL80211_ATTR_WIPHY]),
379 reg_initiator_to_string(nla_get_u32(tb[NL80211_ATTR_REG_INITIATOR])));
380 break;
381 case NL80211_REGDOM_TYPE_INTERSECTION:
382 printf("intersection used due to a request made by %s",
383 reg_initiator_to_string(nla_get_u32(tb[NL80211_ATTR_REG_INITIATOR])));
384 if (tb[NL80211_ATTR_WIPHY])
385 printf(" on phy%d", nla_get_u32(tb[NL80211_ATTR_WIPHY]));
386 break;
387 default:
388 printf("unknown source (upgrade this utility)");
389 break;
390 }
391
392 printf("\n");
393 break;
edea4d14
JB
394 case NL80211_CMD_JOIN_IBSS:
395 if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), ifname);
396 mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
397 printf("IBSS %s joined on %s (phy #%d)\n",
398 macbuf, ifname, nla_get_u32(tb[NL80211_ATTR_WIPHY]));
399 break;
03109dcb
JB
400 default:
401 printf("unknown event: %d\n", gnlh->cmd);
402 break;
2c61ba61
JB
403 }
404
405 return NL_SKIP;
406}
407
72041aa0
JB
408struct wait_event {
409 int n_cmds;
410 const __u32 *cmds;
411 __u32 cmd;
412};
413
414static int wait_event(struct nl_msg *msg, void *arg)
415{
416 struct wait_event *wait = arg;
417 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
418 int i;
419
420 for (i = 0; i < wait->n_cmds; i++) {
421 if (gnlh->cmd == wait->cmds[i]) {
422 wait->cmd = gnlh->cmd;
423 }
424 }
425
426 return NL_SKIP;
427}
428
429__u32 listen_events(struct nl80211_state *state,
430 const int n_waits, const __u32 *waits)
2c61ba61
JB
431{
432 int mcid, ret;
433 struct nl_cb *cb = nl_cb_alloc(debug ? NL_CB_DEBUG : NL_CB_DEFAULT);
72041aa0 434 struct wait_event wait_ev;
2c61ba61
JB
435
436 if (!cb) {
437 fprintf(stderr, "failed to allocate netlink callbacks\n");
438 return -ENOMEM;
439 }
440
601c6ab2 441 /* Configuration multicast group */
57077d64 442 mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "config");
2c61ba61
JB
443 if (mcid < 0)
444 return mcid;
445
57077d64 446 ret = nl_socket_add_membership(state->nl_sock, mcid);
2c61ba61
JB
447 if (ret)
448 return ret;
99f46802 449
601c6ab2 450 /* Scan multicast group */
99f46802 451 mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "scan");
5406d9e4
JB
452 if (mcid >= 0) {
453 ret = nl_socket_add_membership(state->nl_sock, mcid);
454 if (ret)
455 return ret;
456 }
99f46802 457
601c6ab2
LR
458 /* Regulatory multicast group */
459 mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "regulatory");
460 if (mcid >= 0) {
461 ret = nl_socket_add_membership(state->nl_sock, mcid);
462 if (ret)
463 return ret;
464 }
465
edea4d14
JB
466 /* MLME multicast group */
467 mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "mlme");
468 if (mcid >= 0) {
469 ret = nl_socket_add_membership(state->nl_sock, mcid);
470 if (ret)
471 return ret;
472 }
473
2c61ba61
JB
474 /* no sequence checking for multicast messages */
475 nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
2c61ba61 476
72041aa0
JB
477 if (n_waits && waits) {
478 wait_ev.cmds = waits;
479 wait_ev.n_cmds = n_waits;
480 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, wait_event, &wait_ev);
481 } else {
482 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_event, NULL);
483 }
484
485 wait_ev.cmd = 0;
486
487 while (!wait_ev.cmd)
57077d64 488 nl_recvmsgs(state->nl_sock, cb);
2c61ba61
JB
489
490 nl_cb_put(cb);
491
72041aa0 492 return wait_ev.cmd;
2c61ba61
JB
493}
494
cad53b3f
JB
495int main(int argc, char **argv)
496{
497 struct nl80211_state nlstate;
bd396f2a
JB
498 int err;
499 const char *argv0;
cad53b3f 500
f408e01b 501 /* calculate command size including padding */
811ec68f
JB
502 cmd_size = abs((long)&__cmd_NULL_NULL_1_CIB_NONE_0
503 - (long)&__cmd_NULL_NULL_0_CIB_NONE_0);
45c7212c
JB
504 /* strip off self */
505 argc--;
1cdd9016
MK
506 argv0 = *argv++;
507
59c49f09
JB
508 if (argc > 0 && strcmp(*argv, "--debug") == 0) {
509 debug = 1;
510 argc--;
511 argv++;
512 }
513
d711f013
JB
514 if (argc > 0 && strcmp(*argv, "--version") == 0) {
515 version();
516 return 0;
517 }
518
bd396f2a 519 if (argc == 0 || strcmp(*argv, "help") == 0) {
1cdd9016 520 usage(argv0);
4a972f80 521 return 0;
1cdd9016 522 }
45c7212c 523
2bdb6bd1
JB
524 err = nl80211_init(&nlstate);
525 if (err)
526 return 1;
527
2c61ba61 528 if (strcmp(*argv, "event") == 0) {
72041aa0
JB
529 if (argc != 1)
530 err = 1;
531 else
532 err = listen_events(&nlstate, 0, NULL);
811ec68f 533 } else if (strcmp(*argv, "dev") == 0 && argc > 1) {
14a0380d
LR
534 argc--;
535 argv++;
9927363c 536 err = handle_cmd(&nlstate, II_NETDEV, argc, argv);
811ec68f 537 } else if (strncmp(*argv, "phy", 3) == 0 && argc > 1) {
9927363c
JB
538 if (strlen(*argv) == 3) {
539 argc--;
540 argv++;
541 err = handle_cmd(&nlstate, II_PHY_NAME, argc, argv);
542 } else if (*(*argv + 3) == '#')
543 err = handle_cmd(&nlstate, II_PHY_IDX, argc, argv);
544 else
545 err = 1;
bd396f2a 546 } else
9927363c 547 err = handle_cmd(&nlstate, II_NONE, argc, argv);
45c7212c 548
5e75fd04 549 if (err == 1)
bd396f2a 550 usage(argv0);
5e75fd04 551 if (err < 0)
b49be3e1 552 fprintf(stderr, "command failed: %s (%d)\n", strerror(-err), err);
cad53b3f
JB
553
554 nl80211_cleanup(&nlstate);
555
45c7212c 556 return err;
cad53b3f 557}