]> git.ipfire.org Git - thirdparty/iw.git/blob - iw.c
make event printing more regular
[thirdparty/iw.git] / iw.c
1 /*
2 * nl80211 userspace tool
3 *
4 * Copyright 2007, 2008 Johannes Berg <johannes@sipsolutions.net>
5 */
6
7 #include <errno.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <net/if.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <fcntl.h>
14 #include <unistd.h>
15
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>
21
22 #include "nl80211.h"
23 #include "iw.h"
24
25 #ifndef CONFIG_LIBNL20
26 /* libnl 2.0 compatibility code */
27
28 static inline struct nl_handle *nl_socket_alloc(void)
29 {
30 return nl_handle_alloc();
31 }
32
33 static inline void nl_socket_free(struct nl_sock *h)
34 {
35 nl_handle_destroy(h);
36 }
37
38 static inline int __genl_ctrl_alloc_cache(struct nl_sock *h, struct nl_cache **cache)
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
49 static int debug = 0;
50
51 static int nl80211_init(struct nl80211_state *state)
52 {
53 int err;
54
55 state->nl_sock = nl_socket_alloc();
56 if (!state->nl_sock) {
57 fprintf(stderr, "Failed to allocate netlink socket.\n");
58 return -ENOMEM;
59 }
60
61 if (genl_connect(state->nl_sock)) {
62 fprintf(stderr, "Failed to connect to generic netlink.\n");
63 err = -ENOLINK;
64 goto out_handle_destroy;
65 }
66
67 if (genl_ctrl_alloc_cache(state->nl_sock, &state->nl_cache)) {
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:
85 nl_socket_free(state->nl_sock);
86 return err;
87 }
88
89 static void nl80211_cleanup(struct nl80211_state *state)
90 {
91 genl_family_put(state->nl80211);
92 nl_cache_free(state->nl_cache);
93 nl_socket_free(state->nl_sock);
94 }
95
96 __COMMAND(NULL, NULL, "", NULL, 0, 0, 0, CIB_NONE, NULL);
97 __COMMAND(NULL, NULL, "", NULL, 1, 0, 0, CIB_NONE, NULL);
98
99 static int cmd_size;
100
101 static void usage(const char *argv0)
102 {
103 struct cmd *cmd;
104
105 fprintf(stderr, "Usage:\t%s [options] command\n", argv0);
106 fprintf(stderr, "Options:\n");
107 fprintf(stderr, "\t--debug\t\tenable netlink debugging\n");
108 fprintf(stderr, "\t--version\tshow version\n");
109 fprintf(stderr, "Commands:\n");
110 fprintf(stderr, "\thelp\n");
111 fprintf(stderr, "\tevent\n");
112 for (cmd = &__start___cmd; cmd < &__stop___cmd;
113 cmd = (struct cmd *)((char *)cmd + cmd_size)) {
114 if (!cmd->handler || cmd->hidden)
115 continue;
116 switch (cmd->idby) {
117 case CIB_NONE:
118 fprintf(stderr, "\t");
119 break;
120 case CIB_PHY:
121 fprintf(stderr, "\tphy <phyname> ");
122 break;
123 case CIB_NETDEV:
124 fprintf(stderr, "\tdev <devname> ");
125 break;
126 }
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");
133 }
134 }
135
136 static void version(void)
137 {
138 printf("iw version %s\n", iw_version);
139 }
140
141 static 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);
149 if (fd < 0)
150 return -1;
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
158 static 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
166 static int finish_handler(struct nl_msg *msg, void *arg)
167 {
168 int *ret = arg;
169 *ret = 0;
170 return NL_SKIP;
171 }
172
173 static int ack_handler(struct nl_msg *msg, void *arg)
174 {
175 int *ret = arg;
176 *ret = 0;
177 return NL_STOP;
178 }
179
180 int handle_cmd(struct nl80211_state *state, enum id_input idby,
181 int argc, char **argv)
182 {
183 struct cmd *cmd, *match = NULL;
184 struct nl_cb *cb;
185 struct nl_msg *msg;
186 int devidx = 0;
187 int err, o_argc;
188 const char *command, *section;
189 char *tmp, **o_argv;
190 enum command_identify_by command_idby = CIB_NONE;
191
192 if (argc <= 1 && idby != II_NONE)
193 return 1;
194
195 o_argc = argc;
196 o_argv = argv;
197
198 switch (idby) {
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;
209 devidx = phy_lookup(*argv);
210 argc--;
211 argv++;
212 break;
213 case II_NETDEV:
214 command_idby = CIB_NETDEV;
215 devidx = if_nametoindex(*argv);
216 if (devidx == 0)
217 devidx = -1;
218 argc--;
219 argv++;
220 break;
221 default:
222 break;
223 }
224
225 if (devidx < 0)
226 return -errno;
227
228 section = command = *argv;
229 argc--;
230 argv++;
231
232 for (cmd = &__start___cmd; cmd < &__stop___cmd;
233 cmd = (struct cmd *)((char *)cmd + cmd_size)) {
234 if (!cmd->handler)
235 continue;
236 if (cmd->idby != command_idby)
237 continue;
238 if (cmd->section) {
239 if (strcmp(cmd->section, section))
240 continue;
241 /* this is a bit icky ... */
242 if (command == section) {
243 if (argc <= 0) {
244 if (match)
245 break;
246 return 1;
247 }
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;
258
259 match = cmd;
260 }
261
262 cmd = match;
263
264 if (!cmd)
265 return 1;
266
267 if (!cmd->cmd) {
268 argc = o_argc;
269 argv = o_argv;
270 return cmd->handler(state, NULL, NULL, argc, argv);
271 }
272
273 msg = nlmsg_alloc();
274 if (!msg) {
275 fprintf(stderr, "failed to allocate netlink message\n");
276 return 2;
277 }
278
279 cb = nl_cb_alloc(debug ? NL_CB_DEBUG : NL_CB_DEFAULT);
280 if (!cb) {
281 fprintf(stderr, "failed to allocate netlink callbacks\n");
282 err = 2;
283 goto out_free_msg;
284 }
285
286 genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0,
287 cmd->nl_msg_flags, cmd->cmd, 0);
288
289 switch (command_idby) {
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
300 err = cmd->handler(state, cb, msg, argc, argv);
301 if (err)
302 goto out;
303
304 err = nl_send_auto_complete(state->nl_sock, msg);
305 if (err < 0)
306 goto out;
307
308 err = 1;
309
310 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
311 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
312 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
313
314 while (err > 0)
315 nl_recvmsgs(state->nl_sock, cb);
316 out:
317 nl_cb_put(cb);
318 out_free_msg:
319 nlmsg_free(msg);
320 return err;
321 nla_put_failure:
322 fprintf(stderr, "building message failed\n");
323 return 2;
324 }
325
326 static int no_seq_check(struct nl_msg *msg, void *arg)
327 {
328 return NL_OK;
329 }
330
331 static 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];
335 char ifname[100];
336 char macbuf[6*3];
337 __u8 reg_type;
338
339 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
340 genlmsg_attrlen(gnlh, 0), NULL);
341
342 if (tb[NL80211_ATTR_IFINDEX] && tb[NL80211_ATTR_WIPHY]) {
343 if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), ifname);
344 printf("%s (phy #%d): ", ifname, nla_get_u32(tb[NL80211_ATTR_WIPHY]));
345 } else if (tb[NL80211_ATTR_IFINDEX]) {
346 if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), ifname);
347 printf("%s: ", ifname);
348 } else if (tb[NL80211_ATTR_WIPHY]) {
349 printf("phy #%d: ", nla_get_u32(tb[NL80211_ATTR_WIPHY]));
350 }
351
352 switch (gnlh->cmd) {
353 case NL80211_CMD_NEW_WIPHY:
354 printf("renamed to %s\n", nla_get_string(tb[NL80211_ATTR_WIPHY_NAME]));
355 break;
356 case NL80211_CMD_NEW_SCAN_RESULTS:
357 printf("scan finished\n");
358 break;
359 case NL80211_CMD_SCAN_ABORTED:
360 printf("scan aborted\n");
361 break;
362 case NL80211_CMD_REG_CHANGE:
363 printf("regulatory domain change: ");
364
365 reg_type = nla_get_u8(tb[NL80211_ATTR_REG_TYPE]);
366
367 switch (reg_type) {
368 case NL80211_REGDOM_TYPE_COUNTRY:
369 printf("set to %s by %s request",
370 nla_get_string(tb[NL80211_ATTR_REG_ALPHA2]),
371 reg_initiator_to_string(nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR])));
372 if (tb[NL80211_ATTR_WIPHY])
373 printf(" on phy%d", nla_get_u32(tb[NL80211_ATTR_WIPHY]));
374 break;
375 case NL80211_REGDOM_TYPE_WORLD:
376 printf("set to world roaming by %s request",
377 reg_initiator_to_string(nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR])));
378 break;
379 case NL80211_REGDOM_TYPE_CUSTOM_WORLD:
380 printf("custom world roaming rules in place on phy%d by %s request",
381 nla_get_u32(tb[NL80211_ATTR_WIPHY]),
382 reg_initiator_to_string(nla_get_u32(tb[NL80211_ATTR_REG_INITIATOR])));
383 break;
384 case NL80211_REGDOM_TYPE_INTERSECTION:
385 printf("intersection used due to a request made by %s",
386 reg_initiator_to_string(nla_get_u32(tb[NL80211_ATTR_REG_INITIATOR])));
387 if (tb[NL80211_ATTR_WIPHY])
388 printf(" on phy%d", nla_get_u32(tb[NL80211_ATTR_WIPHY]));
389 break;
390 default:
391 printf("unknown source (upgrade this utility)");
392 break;
393 }
394
395 printf("\n");
396 break;
397 case NL80211_CMD_JOIN_IBSS:
398 mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
399 printf("IBSS %s joined\n", macbuf);
400 break;
401 case NL80211_CMD_AUTHENTICATE:
402 printf("auth\n");
403 break;
404 case NL80211_CMD_ASSOCIATE:
405 printf("assoc\n");
406 break;
407 case NL80211_CMD_DEAUTHENTICATE:
408 printf("deauth\n");
409 break;
410 case NL80211_CMD_DISASSOCIATE:
411 printf("disassoc\n");
412 break;
413 default:
414 printf("unknown event %d\n", gnlh->cmd);
415 break;
416 }
417
418 return NL_SKIP;
419 }
420
421 struct wait_event {
422 int n_cmds;
423 const __u32 *cmds;
424 __u32 cmd;
425 };
426
427 static int wait_event(struct nl_msg *msg, void *arg)
428 {
429 struct wait_event *wait = arg;
430 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
431 int i;
432
433 for (i = 0; i < wait->n_cmds; i++) {
434 if (gnlh->cmd == wait->cmds[i]) {
435 wait->cmd = gnlh->cmd;
436 }
437 }
438
439 return NL_SKIP;
440 }
441
442 __u32 listen_events(struct nl80211_state *state,
443 const int n_waits, const __u32 *waits)
444 {
445 int mcid, ret;
446 struct nl_cb *cb = nl_cb_alloc(debug ? NL_CB_DEBUG : NL_CB_DEFAULT);
447 struct wait_event wait_ev;
448
449 if (!cb) {
450 fprintf(stderr, "failed to allocate netlink callbacks\n");
451 return -ENOMEM;
452 }
453
454 /* Configuration multicast group */
455 mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "config");
456 if (mcid < 0)
457 return mcid;
458
459 ret = nl_socket_add_membership(state->nl_sock, mcid);
460 if (ret)
461 return ret;
462
463 /* Scan multicast group */
464 mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "scan");
465 if (mcid >= 0) {
466 ret = nl_socket_add_membership(state->nl_sock, mcid);
467 if (ret)
468 return ret;
469 }
470
471 /* Regulatory multicast group */
472 mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "regulatory");
473 if (mcid >= 0) {
474 ret = nl_socket_add_membership(state->nl_sock, mcid);
475 if (ret)
476 return ret;
477 }
478
479 /* MLME multicast group */
480 mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "mlme");
481 if (mcid >= 0) {
482 ret = nl_socket_add_membership(state->nl_sock, mcid);
483 if (ret)
484 return ret;
485 }
486
487 /* no sequence checking for multicast messages */
488 nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
489
490 if (n_waits && waits) {
491 wait_ev.cmds = waits;
492 wait_ev.n_cmds = n_waits;
493 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, wait_event, &wait_ev);
494 } else {
495 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_event, NULL);
496 }
497
498 wait_ev.cmd = 0;
499
500 while (!wait_ev.cmd)
501 nl_recvmsgs(state->nl_sock, cb);
502
503 nl_cb_put(cb);
504
505 return wait_ev.cmd;
506 }
507
508 int main(int argc, char **argv)
509 {
510 struct nl80211_state nlstate;
511 int err;
512 const char *argv0;
513
514 /* calculate command size including padding */
515 cmd_size = abs((long)&__cmd_NULL_NULL_1_CIB_NONE_0
516 - (long)&__cmd_NULL_NULL_0_CIB_NONE_0);
517 /* strip off self */
518 argc--;
519 argv0 = *argv++;
520
521 if (argc > 0 && strcmp(*argv, "--debug") == 0) {
522 debug = 1;
523 argc--;
524 argv++;
525 }
526
527 if (argc > 0 && strcmp(*argv, "--version") == 0) {
528 version();
529 return 0;
530 }
531
532 if (argc == 0 || strcmp(*argv, "help") == 0) {
533 usage(argv0);
534 return 0;
535 }
536
537 err = nl80211_init(&nlstate);
538 if (err)
539 return 1;
540
541 if (strcmp(*argv, "event") == 0) {
542 if (argc != 1)
543 err = 1;
544 else
545 err = listen_events(&nlstate, 0, NULL);
546 } else if (strcmp(*argv, "dev") == 0 && argc > 1) {
547 argc--;
548 argv++;
549 err = handle_cmd(&nlstate, II_NETDEV, argc, argv);
550 } else if (strncmp(*argv, "phy", 3) == 0 && argc > 1) {
551 if (strlen(*argv) == 3) {
552 argc--;
553 argv++;
554 err = handle_cmd(&nlstate, II_PHY_NAME, argc, argv);
555 } else if (*(*argv + 3) == '#')
556 err = handle_cmd(&nlstate, II_PHY_IDX, argc, argv);
557 else
558 err = 1;
559 } else
560 err = handle_cmd(&nlstate, II_NONE, argc, argv);
561
562 if (err == 1)
563 usage(argv0);
564 if (err < 0)
565 fprintf(stderr, "command failed: %s (%d)\n", strerror(-err), err);
566
567 nl80211_cleanup(&nlstate);
568
569 return err;
570 }