]> git.ipfire.org Git - thirdparty/iw.git/blame - iw.c
iw: fix some scan code indentation
[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>
27c49ed6 15#include <stdbool.h>
86da57ad 16#include <linux/netlink.h>
c551449a 17
cad53b3f
JB
18#include <netlink/genl/genl.h>
19#include <netlink/genl/family.h>
c551449a 20#include <netlink/genl/ctrl.h>
cad53b3f
JB
21#include <netlink/msg.h>
22#include <netlink/attr.h>
cad53b3f 23
f408e01b 24#include "nl80211.h"
cad53b3f
JB
25#include "iw.h"
26
ded667b0
YY
27/* libnl 1.x compatibility code */
28#if !defined(CONFIG_LIBNL20) && !defined(CONFIG_LIBNL30)
dfd13ee5
PE
29static inline struct nl_handle *nl_socket_alloc(void)
30{
31 return nl_handle_alloc();
32}
33
57077d64 34static inline void nl_socket_free(struct nl_sock *h)
dfd13ee5
PE
35{
36 nl_handle_destroy(h);
37}
b9be8936
JB
38
39static inline int nl_socket_set_buffer_size(struct nl_sock *sk,
40 int rxbuf, int txbuf)
41{
42 return nl_set_buffer_size(sk, rxbuf, txbuf);
43}
ded667b0 44#endif /* CONFIG_LIBNL20 && CONFIG_LIBNL30 */
dfd13ee5 45
957a0f07 46int iw_debug = 0;
cad53b3f
JB
47
48static int nl80211_init(struct nl80211_state *state)
49{
50 int err;
51
57077d64
PE
52 state->nl_sock = nl_socket_alloc();
53 if (!state->nl_sock) {
54 fprintf(stderr, "Failed to allocate netlink socket.\n");
cad53b3f
JB
55 return -ENOMEM;
56 }
57
57077d64 58 if (genl_connect(state->nl_sock)) {
cad53b3f
JB
59 fprintf(stderr, "Failed to connect to generic netlink.\n");
60 err = -ENOLINK;
61 goto out_handle_destroy;
62 }
63
7687d596
TG
64 nl_socket_set_buffer_size(state->nl_sock, 8192, 8192);
65
3a807325
JB
66 /* try to set NETLINK_EXT_ACK to 1, ignoring errors */
67 err = 1;
68 setsockopt(nl_socket_get_fd(state->nl_sock), SOL_NETLINK,
69 NETLINK_EXT_ACK, &err, sizeof(err));
70
f09cee6d
JB
71 state->nl80211_id = genl_ctrl_resolve(state->nl_sock, "nl80211");
72 if (state->nl80211_id < 0) {
cad53b3f
JB
73 fprintf(stderr, "nl80211 not found.\n");
74 err = -ENOENT;
f09cee6d 75 goto out_handle_destroy;
cad53b3f
JB
76 }
77
78 return 0;
79
cad53b3f 80 out_handle_destroy:
57077d64 81 nl_socket_free(state->nl_sock);
cad53b3f
JB
82 return err;
83}
84
85static void nl80211_cleanup(struct nl80211_state *state)
86{
57077d64 87 nl_socket_free(state->nl_sock);
cad53b3f
JB
88}
89
403b9c83
JB
90static int cmd_size;
91
4698bfc2
JB
92extern struct cmd __start___cmd;
93extern struct cmd __stop___cmd;
94
95#define for_each_cmd(_cmd) \
96 for (_cmd = &__start___cmd; _cmd < &__stop___cmd; \
97 _cmd = (const struct cmd *)((char *)_cmd + cmd_size))
98
99
100static void __usage_cmd(const struct cmd *cmd, char *indent, bool full)
3bb116da 101{
01ae06f9
JB
102 const char *start, *lend, *end;
103
bd663893 104 printf("%s", indent);
4f0cae73 105
3bb116da
JB
106 switch (cmd->idby) {
107 case CIB_NONE:
3bb116da
JB
108 break;
109 case CIB_PHY:
bd663893 110 printf("phy <phyname> ");
3bb116da
JB
111 break;
112 case CIB_NETDEV:
bd663893 113 printf("dev <devname> ");
3bb116da 114 break;
290a3dd4
JB
115 case CIB_WDEV:
116 printf("wdev <idx> ");
117 break;
3bb116da 118 }
4698bfc2
JB
119 if (cmd->parent && cmd->parent->name)
120 printf("%s ", cmd->parent->name);
bd663893 121 printf("%s", cmd->name);
eb795501
JB
122
123 if (cmd->args) {
124 /* print line by line */
125 start = cmd->args;
126 end = strchr(start, '\0');
127 printf(" ");
128 do {
129 lend = strchr(start, '\n');
130 if (!lend)
131 lend = end;
132 if (start != cmd->args) {
133 printf("\t");
134 switch (cmd->idby) {
135 case CIB_NONE:
136 break;
137 case CIB_PHY:
138 printf("phy <phyname> ");
139 break;
140 case CIB_NETDEV:
141 printf("dev <devname> ");
142 break;
143 case CIB_WDEV:
144 printf("wdev <idx> ");
145 break;
146 }
147 if (cmd->parent && cmd->parent->name)
148 printf("%s ", cmd->parent->name);
149 printf("%s ", cmd->name);
150 }
151 printf("%.*s\n", (int)(lend - start), start);
152 start = lend + 1;
153 } while (end != lend);
154 } else
155 printf("\n");
01ae06f9
JB
156
157 if (!full || !cmd->help)
158 return;
159
160 /* hack */
161 if (strlen(indent))
162 indent = "\t\t";
163 else
bd663893 164 printf("\n");
01ae06f9
JB
165
166 /* print line by line */
167 start = cmd->help;
168 end = strchr(start, '\0');
169 do {
170 lend = strchr(start, '\n');
171 if (!lend)
172 lend = end;
bd663893
HS
173 printf("%s", indent);
174 printf("%.*s\n", (int)(lend - start), start);
01ae06f9
JB
175 start = lend + 1;
176 } while (end != lend);
177
bd663893 178 printf("\n");
3bb116da
JB
179}
180
4f0cae73
JB
181static void usage_options(void)
182{
bd663893
HS
183 printf("Options:\n");
184 printf("\t--debug\t\tenable netlink debugging\n");
4f0cae73
JB
185}
186
01ae06f9
JB
187static const char *argv0;
188
f3ac8bf1 189static void usage(int argc, char **argv)
bd396f2a 190{
4698bfc2 191 const struct cmd *section, *cmd;
f3ac8bf1
JB
192 bool full = argc >= 0;
193 const char *sect_filt = NULL;
194 const char *cmd_filt = NULL;
195
196 if (argc > 0)
197 sect_filt = argv[0];
198
199 if (argc > 1)
200 cmd_filt = argv[1];
bd396f2a 201
bd663893 202 printf("Usage:\t%s [options] command\n", argv0);
4f0cae73 203 usage_options();
bd663893
HS
204 printf("\t--version\tshow version (%s)\n", iw_version);
205 printf("Commands:\n");
4698bfc2
JB
206 for_each_cmd(section) {
207 if (section->parent)
403b9c83 208 continue;
4698bfc2 209
f3ac8bf1
JB
210 if (sect_filt && strcmp(section->name, sect_filt))
211 continue;
212
4698bfc2
JB
213 if (section->handler && !section->hidden)
214 __usage_cmd(section, "\t", full);
215
216 for_each_cmd(cmd) {
217 if (section != cmd->parent)
218 continue;
219 if (!cmd->handler || cmd->hidden)
220 continue;
f3ac8bf1
JB
221 if (cmd_filt && strcmp(cmd->name, cmd_filt))
222 continue;
4698bfc2
JB
223 __usage_cmd(cmd, "\t", full);
224 }
bd396f2a 225 }
75f4204c
JB
226 printf("\nCommands that use the netdev ('dev') can also be given the\n"
227 "'wdev' instead to identify the device.\n");
bd663893 228 printf("\nYou can omit the 'phy' or 'dev' if "
f4ec76d0 229 "the identification is unique,\n"
8aefee9a 230 "e.g. \"iw wlan0 info\" or \"iw phy0 info\". "
fbdb8d05
JB
231 "(Don't when scripting.)\n\n"
232 "Do NOT screenscrape this tool, we don't "
233 "consider its output stable.\n\n");
bd396f2a
JB
234}
235
01ae06f9 236static int print_help(struct nl80211_state *state,
01ae06f9 237 struct nl_msg *msg,
05514f95
JB
238 int argc, char **argv,
239 enum id_input id)
01ae06f9
JB
240{
241 exit(3);
242}
f3ac8bf1
JB
243TOPLEVEL(help, "[command]", 0, 0, CIB_NONE, print_help,
244 "Print usage for all or a specific command, e.g.\n"
245 "\"help wowlan\" or \"help wowlan enable\".");
01ae06f9 246
4698bfc2 247static void usage_cmd(const struct cmd *cmd)
4f0cae73 248{
bd663893 249 printf("Usage:\t%s [options] ", argv0);
01ae06f9 250 __usage_cmd(cmd, "", true);
4f0cae73
JB
251 usage_options();
252}
253
d711f013
JB
254static void version(void)
255{
133b069f 256 printf("iw version %s\n", iw_version);
d711f013
JB
257}
258
bd396f2a
JB
259static int phy_lookup(char *name)
260{
261 char buf[200];
262 int fd, pos;
263
264 snprintf(buf, sizeof(buf), "/sys/class/ieee80211/%s/index", name);
265
266 fd = open(buf, O_RDONLY);
989e97c2
JB
267 if (fd < 0)
268 return -1;
bd396f2a 269 pos = read(fd, buf, sizeof(buf) - 1);
8f253ee2
ES
270 if (pos < 0) {
271 close(fd);
bd396f2a 272 return -1;
8f253ee2 273 }
bd396f2a 274 buf[pos] = '\0';
8f253ee2 275 close(fd);
bd396f2a
JB
276 return atoi(buf);
277}
278
70391ccf
JB
279static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
280 void *arg)
281{
3a807325
JB
282 struct nlmsghdr *nlh = (struct nlmsghdr *)err - 1;
283 int len = nlh->nlmsg_len;
284 struct nlattr *attrs;
285 struct nlattr *tb[NLMSGERR_ATTR_MAX + 1];
70391ccf 286 int *ret = arg;
3a807325
JB
287 int ack_len = sizeof(*nlh) + sizeof(int) + sizeof(*nlh);
288
70391ccf 289 *ret = err->error;
3a807325
JB
290
291 if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS))
292 return NL_STOP;
293
294 if (!(nlh->nlmsg_flags & NLM_F_CAPPED))
295 ack_len += err->msg.nlmsg_len - sizeof(*nlh);
296
297 if (len <= ack_len)
298 return NL_STOP;
299
300 attrs = (void *)((unsigned char *)nlh + ack_len);
301 len -= ack_len;
302
303 nla_parse(tb, NLMSGERR_ATTR_MAX, attrs, len, NULL);
304 if (tb[NLMSGERR_ATTR_MSG]) {
305 len = strnlen((char *)nla_data(tb[NLMSGERR_ATTR_MSG]),
306 nla_len(tb[NLMSGERR_ATTR_MSG]));
307 fprintf(stderr, "kernel reports: %*s\n", len,
308 (char *)nla_data(tb[NLMSGERR_ATTR_MSG]));
309 }
310
70391ccf
JB
311 return NL_STOP;
312}
313
561c5b7e
JB
314static int finish_handler(struct nl_msg *msg, void *arg)
315{
59c418c0
JB
316 int *ret = arg;
317 *ret = 0;
561c5b7e
JB
318 return NL_SKIP;
319}
320
321static int ack_handler(struct nl_msg *msg, void *arg)
70391ccf
JB
322{
323 int *ret = arg;
324 *ret = 0;
325 return NL_STOP;
326}
327
34b23014
JB
328static int (*registered_handler)(struct nl_msg *, void *);
329static void *registered_handler_data;
330
331void register_handler(int (*handler)(struct nl_msg *, void *), void *data)
332{
333 registered_handler = handler;
334 registered_handler_data = data;
335}
336
337int valid_handler(struct nl_msg *msg, void *arg)
338{
339 if (registered_handler)
340 return registered_handler(msg, registered_handler_data);
341
342 return NL_OK;
343}
344
4f0cae73 345static int __handle_cmd(struct nl80211_state *state, enum id_input idby,
4698bfc2 346 int argc, char **argv, const struct cmd **cmdout)
45c7212c 347{
4698bfc2 348 const struct cmd *cmd, *match = NULL, *sectcmd;
7c37a24d 349 struct nl_cb *cb;
5cb60f91 350 struct nl_cb *s_cb;
bd396f2a 351 struct nl_msg *msg;
290a3dd4 352 signed long long devidx = 0;
bb60b4ae 353 int err, o_argc;
bd396f2a 354 const char *command, *section;
bb60b4ae 355 char *tmp, **o_argv;
9927363c 356 enum command_identify_by command_idby = CIB_NONE;
45c7212c 357
9927363c 358 if (argc <= 1 && idby != II_NONE)
5e75fd04 359 return 1;
45c7212c 360
bb60b4ae
JB
361 o_argc = argc;
362 o_argv = argv;
363
bd396f2a 364 switch (idby) {
9927363c
JB
365 case II_PHY_IDX:
366 command_idby = CIB_PHY;
367 devidx = strtoul(*argv + 4, &tmp, 0);
368 if (*tmp != '\0')
369 return 1;
370 argc--;
371 argv++;
372 break;
373 case II_PHY_NAME:
374 command_idby = CIB_PHY;
bd396f2a
JB
375 devidx = phy_lookup(*argv);
376 argc--;
377 argv++;
378 break;
9927363c
JB
379 case II_NETDEV:
380 command_idby = CIB_NETDEV;
bd396f2a 381 devidx = if_nametoindex(*argv);
989e97c2
JB
382 if (devidx == 0)
383 devidx = -1;
bd396f2a
JB
384 argc--;
385 argv++;
386 break;
290a3dd4
JB
387 case II_WDEV:
388 command_idby = CIB_WDEV;
389 devidx = strtoll(*argv, &tmp, 0);
390 if (*tmp != '\0')
391 return 1;
392 argc--;
393 argv++;
bd396f2a
JB
394 default:
395 break;
396 }
397
989e97c2
JB
398 if (devidx < 0)
399 return -errno;
400
4698bfc2 401 section = *argv;
bd396f2a
JB
402 argc--;
403 argv++;
404
4698bfc2
JB
405 for_each_cmd(sectcmd) {
406 if (sectcmd->parent)
403b9c83 407 continue;
4698bfc2
JB
408 /* ok ... bit of a hack for the dupe 'info' section */
409 if (match && sectcmd->idby != command_idby)
bd396f2a 410 continue;
4698bfc2
JB
411 if (strcmp(sectcmd->name, section) == 0)
412 match = sectcmd;
bd396f2a 413 }
45c7212c 414
4698bfc2
JB
415 sectcmd = match;
416 match = NULL;
417 if (!sectcmd)
5e75fd04 418 return 1;
45c7212c 419
4698bfc2
JB
420 if (argc > 0) {
421 command = *argv;
422
423 for_each_cmd(cmd) {
424 if (!cmd->handler)
425 continue;
426 if (cmd->parent != sectcmd)
427 continue;
75f4204c
JB
428 /*
429 * ignore mismatch id by, but allow WDEV
430 * in place of NETDEV
431 */
432 if (cmd->idby != command_idby &&
433 !(cmd->idby == CIB_NETDEV &&
434 command_idby == CIB_WDEV))
4698bfc2
JB
435 continue;
436 if (strcmp(cmd->name, command))
437 continue;
438 if (argc > 1 && !cmd->args)
439 continue;
440 match = cmd;
441 break;
442 }
443
444 if (match) {
445 argc--;
446 argv++;
447 }
448 }
449
450 if (match)
451 cmd = match;
452 else {
453 /* Use the section itself, if possible. */
454 cmd = sectcmd;
455 if (argc && !cmd->args)
456 return 1;
75f4204c
JB
457 if (cmd->idby != command_idby &&
458 !(cmd->idby == CIB_NETDEV && command_idby == CIB_WDEV))
4698bfc2
JB
459 return 1;
460 if (!cmd->handler)
461 return 1;
462 }
463
1633ddf7
JB
464 if (cmd->selector) {
465 cmd = cmd->selector(argc, argv);
466 if (!cmd)
467 return 1;
468 }
469
4f0cae73
JB
470 if (cmdout)
471 *cmdout = cmd;
472
bb60b4ae
JB
473 if (!cmd->cmd) {
474 argc = o_argc;
475 argv = o_argv;
34b23014 476 return cmd->handler(state, NULL, argc, argv, idby);
bb60b4ae
JB
477 }
478
bd396f2a
JB
479 msg = nlmsg_alloc();
480 if (!msg) {
70391ccf
JB
481 fprintf(stderr, "failed to allocate netlink message\n");
482 return 2;
483 }
484
957a0f07 485 cb = nl_cb_alloc(iw_debug ? NL_CB_DEBUG : NL_CB_DEFAULT);
5cb60f91
SR
486 s_cb = nl_cb_alloc(iw_debug ? NL_CB_DEBUG : NL_CB_DEFAULT);
487 if (!cb || !s_cb) {
70391ccf
JB
488 fprintf(stderr, "failed to allocate netlink callbacks\n");
489 err = 2;
7faa1ba1 490 goto out;
bd396f2a 491 }
45c7212c 492
f09cee6d 493 genlmsg_put(msg, 0, 0, state->nl80211_id, 0,
bd396f2a
JB
494 cmd->nl_msg_flags, cmd->cmd, 0);
495
9927363c 496 switch (command_idby) {
bd396f2a
JB
497 case CIB_PHY:
498 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, devidx);
499 break;
500 case CIB_NETDEV:
501 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);
502 break;
290a3dd4
JB
503 case CIB_WDEV:
504 NLA_PUT_U64(msg, NL80211_ATTR_WDEV, devidx);
505 break;
bd396f2a
JB
506 default:
507 break;
508 }
509
34b23014 510 err = cmd->handler(state, msg, argc, argv, idby);
70391ccf
JB
511 if (err)
512 goto out;
513
5cb60f91
SR
514 nl_socket_set_cb(state->nl_sock, s_cb);
515
57077d64 516 err = nl_send_auto_complete(state->nl_sock, msg);
70391ccf
JB
517 if (err < 0)
518 goto out;
519
c5c4471a
JB
520 err = 1;
521
70391ccf 522 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
59c418c0 523 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
561c5b7e 524 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
34b23014 525 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, valid_handler, NULL);
70391ccf 526
c5c4471a 527 while (err > 0)
57077d64 528 nl_recvmsgs(state->nl_sock, cb);
70391ccf
JB
529 out:
530 nl_cb_put(cb);
7faa1ba1 531 nl_cb_put(s_cb);
70391ccf
JB
532 nlmsg_free(msg);
533 return err;
bd396f2a
JB
534 nla_put_failure:
535 fprintf(stderr, "building message failed\n");
70391ccf 536 return 2;
45c7212c
JB
537}
538
4f0cae73
JB
539int handle_cmd(struct nl80211_state *state, enum id_input idby,
540 int argc, char **argv)
541{
542 return __handle_cmd(state, idby, argc, argv, NULL);
543}
544
cad53b3f
JB
545int main(int argc, char **argv)
546{
547 struct nl80211_state nlstate;
bd396f2a 548 int err;
4698bfc2 549 const struct cmd *cmd = NULL;
cad53b3f 550
f408e01b 551 /* calculate command size including padding */
8ccc4795 552 cmd_size = labs((long)&__section_set - (long)&__section_get);
45c7212c
JB
553 /* strip off self */
554 argc--;
1cdd9016
MK
555 argv0 = *argv++;
556
59c49f09 557 if (argc > 0 && strcmp(*argv, "--debug") == 0) {
957a0f07 558 iw_debug = 1;
59c49f09
JB
559 argc--;
560 argv++;
561 }
562
d711f013
JB
563 if (argc > 0 && strcmp(*argv, "--version") == 0) {
564 version();
565 return 0;
566 }
567
01ae06f9 568 /* need to treat "help" command specially so it works w/o nl80211 */
bd396f2a 569 if (argc == 0 || strcmp(*argv, "help") == 0) {
f3ac8bf1 570 usage(argc - 1, argv + 1);
4a972f80 571 return 0;
1cdd9016 572 }
45c7212c 573
2bdb6bd1
JB
574 err = nl80211_init(&nlstate);
575 if (err)
576 return 1;
577
957a0f07 578 if (strcmp(*argv, "dev") == 0 && argc > 1) {
14a0380d
LR
579 argc--;
580 argv++;
4f0cae73 581 err = __handle_cmd(&nlstate, II_NETDEV, argc, argv, &cmd);
811ec68f 582 } else if (strncmp(*argv, "phy", 3) == 0 && argc > 1) {
9927363c
JB
583 if (strlen(*argv) == 3) {
584 argc--;
585 argv++;
4f0cae73 586 err = __handle_cmd(&nlstate, II_PHY_NAME, argc, argv, &cmd);
9927363c 587 } else if (*(*argv + 3) == '#')
4f0cae73 588 err = __handle_cmd(&nlstate, II_PHY_IDX, argc, argv, &cmd);
9927363c 589 else
f4ec76d0 590 goto detect;
290a3dd4
JB
591 } else if (strcmp(*argv, "wdev") == 0 && argc > 1) {
592 argc--;
593 argv++;
594 err = __handle_cmd(&nlstate, II_WDEV, argc, argv, &cmd);
f4ec76d0
JB
595 } else {
596 int idx;
597 enum id_input idby = II_NONE;
598 detect:
599 if ((idx = if_nametoindex(argv[0])) != 0)
600 idby = II_NETDEV;
66f8ca45 601 else if ((idx = phy_lookup(argv[0])) >= 0)
f4ec76d0
JB
602 idby = II_PHY_NAME;
603 err = __handle_cmd(&nlstate, idby, argc, argv, &cmd);
604 }
45c7212c 605
b2c4bf45 606 if (err == HANDLER_RET_USAGE) {
4f0cae73 607 if (cmd)
01ae06f9 608 usage_cmd(cmd);
4f0cae73 609 else
f3ac8bf1 610 usage(0, NULL);
94af668b
JB
611 } else if (err == HANDLER_RET_DONE) {
612 err = 0;
4f0cae73 613 } else if (err < 0)
b49be3e1 614 fprintf(stderr, "command failed: %s (%d)\n", strerror(-err), err);
cad53b3f
JB
615
616 nl80211_cleanup(&nlstate);
617
45c7212c 618 return err;
cad53b3f 619}